Ted's RPG Rant

A place to rant about RPG games, particularly the Temple of Elemental Evil. Co8 members get a free cookie for stopping by. Thats ONE cookie each, no seconds.

Friday, April 28, 2006

Flags Tutorial Part 2

Ok, time for object flags. Rather than do an update, here is a new post (cause we already have great long lists in part 1) ;-).

These are flags (or 'identifiers') that are attached to specific objects (funnily enough), not just to prototypes (which might occur several times on a map. For instance, you might spawn or .mob in several goblins or skels or whatever in a dungeon, or a couple helms in an armoury). Last time you saw a manner in which I faked a way around it: I had 2 .mobs on a map of identical protos and (therefore) with identical scripts, and distinguished between them by setting different OCF flags in their .mobs. Today we will look at the real deal. These are internal flags so they can be read more than they can be set ;-) Also, they can happily crash a game if u stuff up by setting an item flag for an NPC or whatever, just like a mob (probably like a prototype too but never tried). And indeed I don't know if some of them won't crash the game anyway, if they are not supported (Arcanum anyone?) In this racket, you gotta get used to trial-and-error people, its the only way.

Now, first a word from C-Blue on this subject, then a list of ALL the flags. I like lists. 8^D For those who want some downloadable versions, check this thread HERE.

Ok, over to ol' Red-Eye:

All the fields can be read, but not all of them can be set. The “ _f_” fields are floating point and the “ _i_” fields are integer. The fields with 64 in them are 64 bit, the fields that end in “as” are arrays, and the fields that end in “idx” are indexes for arrays. Don’t mess with those. The get_int function only reads 32 bit integers. That is pretty much all I know about these fields. Trial and error has shown me what I can set and what I can’t. I can’t remember off hand what all is what though. That’s why I have the spreadsheet now, so I can record this stuff.


We'll lean on him later for this list: you're gonna have to get used to these people, we are gonna use them a LOT for KotB, where global flags and variables will be left for GLOBAL events, not just to check if your project NPC has had his breakfast or not. Why set a global flag for an object when you can just read it straight from the object's internal flags? Madness, I tells ya. For now, we'll look at some flags that can be used as internal variables. But first, the list:

obj_f_begin=0
obj_f_current_aid=1
obj_f_location=2
obj_f_offset_x=3
obj_f_offset_y=4
obj_f_shadow=5
obj_f_overlay_fore=6
obj_f_overlay_back=7
obj_f_underlay=8
obj_f_blit_flags=9
obj_f_blit_color=10
obj_f_blit_alpha=11
obj_f_scale=12
obj_f_light_flags=13
obj_f_light_aid=14
obj_f_light_color=15
obj_f_overlay_light_flags=16
obj_f_overlay_light_aid=17
obj_f_overlay_light_color=18
obj_f_flags=19
obj_f_spell_flags=20
obj_f_blocking_mask=21
obj_f_name=22
obj_f_description=23
obj_f_aid=24
obj_f_destroyed_aid=25
obj_f_size=26
obj_f_hp_pts=27
obj_f_hp_adj=28
obj_f_hp_damage=29
obj_f_material=30
obj_f_scripts_idx=31
obj_f_sound_effect=32
obj_f_category=33
obj_f_rotation=34
obj_f_speed_walk=35
obj_f_speed_run=36
obj_f_base_mesh=37
obj_f_base_anim=38
obj_f_radius=39
obj_f_3d_render_height=40
obj_f_conditions=41
obj_f_condition_arg0=42
obj_f_permanent_mods=43
obj_f_initiative=44
obj_f_dispatcher=45
obj_f_subinitiative=46
obj_f_secretdoor_flags=47
obj_f_secretdoor_effectname=48
obj_f_secretdoor_dc=49
obj_f_pad_i_7=50
obj_f_pad_i_8=51
obj_f_pad_i_9=52
obj_f_pad_i_0=53
obj_f_offset_z=54
obj_f_rotation_pitch=55
obj_f_pad_f_3=56
obj_f_pad_f_4=57
obj_f_pad_f_5=58
obj_f_pad_f_6=59
obj_f_pad_f_7=60
obj_f_pad_f_8=61
obj_f_pad_f_9=62
obj_f_pad_f_0=63
obj_f_pad_i64_0=64
obj_f_pad_i64_1=65
obj_f_pad_i64_2=66
obj_f_pad_i64_3=67
obj_f_pad_i64_4=68
obj_f_last_hit_by=69
obj_f_pad_obj_1=70
obj_f_pad_obj_2=71
obj_f_pad_obj_3=72
obj_f_pad_obj_4=73
obj_f_permanent_mod_data=74
obj_f_attack_types_idx=75
obj_f_attack_bonus_idx=76
obj_f_strategy_state=77
obj_f_pad_ias_4=78
obj_f_pad_i64as_0=79
obj_f_pad_i64as_1=80
obj_f_pad_i64as_2=81
obj_f_pad_i64as_3=82
obj_f_pad_i64as_4=83
obj_f_pad_objas_0=84
obj_f_pad_objas_1=85
obj_f_pad_objas_2=86
obj_f_end=87

obj_f_portal_begin=88
obj_f_portal_flags=89
obj_f_portal_lock_dc=90
obj_f_portal_key_id=91
obj_f_portal_notify_npc=92
obj_f_portal_pad_i_1=93
obj_f_portal_pad_i_2=94
obj_f_portal_pad_i_3=95
obj_f_portal_pad_i_4=96
obj_f_portal_pad_i_5=97
obj_f_portal_pad_obj_1=98
obj_f_portal_pad_ias_1=99
obj_f_portal_pad_i64as_1=100
obj_f_portal_end=101

obj_f_container_begin=102
obj_f_container_flags=103
obj_f_container_lock_dc=104
obj_f_container_key_id=105
obj_f_container_inventory_num=106
obj_f_container_inventory_list_idx=107
obj_f_container_inventory_source=108
obj_f_container_notify_npc=109
obj_f_container_pad_i_1=110
obj_f_container_pad_i_2=111
obj_f_container_pad_i_3=112
obj_f_container_pad_i_4=113
obj_f_container_pad_i_5=114
obj_f_container_pad_obj_1=115
obj_f_container_pad_obj_2=116
obj_f_container_pad_ias_1=117
obj_f_container_pad_i64as_1=118
obj_f_container_pad_objas_1=119
obj_f_container_end=120

obj_f_scenery_begin=121
obj_f_scenery_flags=122
obj_f_scenery_pad_obj_0=123
obj_f_scenery_respawn_delay=124
obj_f_scenery_pad_i_0=125
obj_f_scenery_pad_i_1=126
obj_f_scenery_teleport_to=127
obj_f_scenery_pad_i_4=128
obj_f_scenery_pad_i_5=129
obj_f_scenery_pad_obj_1=130
obj_f_scenery_pad_ias_1=131
obj_f_scenery_pad_i64as_1=132
obj_f_scenery_end=133

obj_f_projectile_begin=134
obj_f_projectile_flags_combat=135
obj_f_projectile_flags_combat_damage=136
obj_f_projectile_parent_weapon=137
obj_f_projectile_parent_ammo=138
obj_f_projectile_part_sys_id=139
obj_f_projectile_acceleration_x=140
obj_f_projectile_acceleration_y=141
obj_f_projectile_acceleration_z=142
obj_f_projectile_pad_i_4=143
obj_f_projectile_pad_obj_1=144
obj_f_projectile_pad_obj_2=145
obj_f_projectile_pad_obj_3=146
obj_f_projectile_pad_ias_1=147
obj_f_projectile_pad_i64as_1=148
obj_f_projectile_pad_objas_1=149
obj_f_projectile_end=150

obj_f_item_begin=151
obj_f_item_flags=152
obj_f_item_parent=153
obj_f_item_weight=154
obj_f_item_worth=155
obj_f_item_inv_aid=156
obj_f_item_inv_location=157
obj_f_item_ground_mesh=158
obj_f_item_ground_anim=159
obj_f_item_description_unknown=160
obj_f_item_description_effects=161
obj_f_item_spell_idx=162
obj_f_item_spell_idx_flags=163
obj_f_item_spell_charges_idx=164
obj_f_item_ai_action=165
obj_f_item_wear_flags=166
obj_f_item_material_slot=167
obj_f_item_quantity=168
obj_f_item_pad_i_1=169
obj_f_item_pad_i_2=170
obj_f_item_pad_i_3=171
obj_f_item_pad_i_4=172
obj_f_item_pad_i_5=173
obj_f_item_pad_i_6=174
obj_f_item_pad_obj_1=175
obj_f_item_pad_obj_2=176
obj_f_item_pad_obj_3=177
obj_f_item_pad_obj_4=178
obj_f_item_pad_obj_5=179
obj_f_item_pad_wielder_condition_array=180
obj_f_item_pad_wielder_argument_array=181
obj_f_item_pad_i64as_1=182
obj_f_item_pad_i64as_2=183
obj_f_item_pad_objas_1=184
obj_f_item_pad_objas_2=185
obj_f_item_end=186

obj_f_weapon_begin=187
obj_f_weapon_flags=188
obj_f_weapon_range=189
obj_f_weapon_ammo_type=190
obj_f_weapon_ammo_consumption=191
obj_f_weapon_missile_aid=192
obj_f_weapon_crit_hit_chart=193
obj_f_weapon_attacktype=194
obj_f_weapon_damage_dice=195
obj_f_weapon_animtype=196
obj_f_weapon_type=197
obj_f_weapon_crit_range=198
obj_f_weapon_pad_i_1=199
obj_f_weapon_pad_i_2=200
obj_f_weapon_pad_obj_1=201
obj_f_weapon_pad_obj_2=202
obj_f_weapon_pad_obj_3=203
obj_f_weapon_pad_obj_4=204
obj_f_weapon_pad_obj_5=205
obj_f_weapon_pad_ias_1=206
obj_f_weapon_pad_i64as_1=207
obj_f_weapon_end=208

obj_f_ammo_begin=209
obj_f_ammo_flags=210
obj_f_ammo_quantity=211
obj_f_ammo_type=212
obj_f_ammo_pad_i_1=213
obj_f_ammo_pad_i_2=214
obj_f_ammo_pad_obj_1=215
obj_f_ammo_pad_ias_1=216
obj_f_ammo_pad_i64as_1=217
obj_f_ammo_end=218

obj_f_armor_begin=219
obj_f_armor_flags=220
obj_f_armor_ac_adj=221
obj_f_armor_max_dex_bonus=222
obj_f_armor_arcane_spell_failure=223
obj_f_armor_armor_check_penalty=224
obj_f_armor_pad_i_1=225
obj_f_armor_pad_ias_1=226
obj_f_armor_pad_i64as_1=227
obj_f_armor_end=228

obj_f_money_begin=229
obj_f_money_flags=230
obj_f_money_quantity=231
obj_f_money_type=232
obj_f_money_pad_i_1=233
obj_f_money_pad_i_2=234
obj_f_money_pad_i_3=235
obj_f_money_pad_i_4=236
obj_f_money_pad_i_5=237
obj_f_money_pad_ias_1=238
obj_f_money_pad_i64as_1=239
obj_f_money_end=240

obj_f_food_begin=241
obj_f_food_flags=242
obj_f_food_pad_i_1=243
obj_f_food_pad_i_2=244
obj_f_food_pad_ias_1=245
obj_f_food_pad_i64as_1=246
obj_f_food_end=247

obj_f_scroll_begin=248
obj_f_scroll_flags=249
obj_f_scroll_pad_i_1=250
obj_f_scroll_pad_i_2=251
obj_f_scroll_pad_ias_1=252
obj_f_scroll_pad_i64as_1=253
obj_f_scroll_end=254

obj_f_key_begin=255
obj_f_key_key_id=256
obj_f_key_pad_i_1=257
obj_f_key_pad_i_2=258
obj_f_key_pad_ias_1=259
obj_f_key_pad_i64as_1=260
obj_f_key_end=261

obj_f_written_begin=262
obj_f_written_flags=263
obj_f_written_subtype=264
obj_f_written_text_start_line=265
obj_f_written_text_end_line=266
obj_f_written_pad_i_1=267
obj_f_written_pad_i_2=268
obj_f_written_pad_ias_1=269
obj_f_written_pad_i64as_1=270
obj_f_written_end=271

obj_f_bag_begin=272
obj_f_bag_flags=273
obj_f_bag_size=274
obj_f_bag_end=275

obj_f_generic_begin=276
obj_f_generic_flags=277
obj_f_generic_usage_bonus=278
obj_f_generic_usage_count_remaining=279
obj_f_generic_pad_ias_1=280
obj_f_generic_pad_i64as_1=281
obj_f_generic_end=282

obj_f_critter_begin=283
obj_f_critter_flags=284
obj_f_critter_flags2=285
obj_f_critter_abilities_idx=286
obj_f_critter_level_idx=287
obj_f_critter_race=288
obj_f_critter_gender=289
obj_f_critter_age=290
obj_f_critter_height=291
obj_f_critter_weight=292
obj_f_critter_experience=293
obj_f_critter_pad_i_1=294
obj_f_critter_alignment=295
obj_f_critter_deity=296
obj_f_critter_domain_1=297
obj_f_critter_domain_2=298
obj_f_critter_alignment_choice=299
obj_f_critter_school_specialization=300
obj_f_critter_spells_known_idx=301
obj_f_critter_spells_memorized_idx=302
obj_f_critter_spells_cast_idx=303
obj_f_critter_feat_idx=304
obj_f_critter_feat_count_idx=305
obj_f_critter_fleeing_from=306
obj_f_critter_portrait=307
obj_f_critter_money_idx=308
obj_f_critter_inventory_num=309
obj_f_critter_inventory_list_idx=310
obj_f_critter_inventory_source=311
obj_f_critter_description_unknown=312
obj_f_critter_follower_idx=313
obj_f_critter_teleport_dest=314
obj_f_critter_teleport_map=315
obj_f_critter_death_time=316
obj_f_critter_skill_idx=317
obj_f_critter_reach=318
obj_f_critter_subdual_damage=319
obj_f_critter_pad_i_4=320
obj_f_critter_pad_i_5=321
obj_f_critter_sequence=322
obj_f_critter_hair_style=323
obj_f_critter_strategy=324
obj_f_critter_pad_i_3=325
obj_f_critter_monster_category=326
obj_f_critter_pad_i64_2=327
obj_f_critter_pad_i64_3=328
obj_f_critter_pad_i64_4=329
obj_f_critter_pad_i64_5=330
obj_f_critter_damage_idx=331
obj_f_critter_attacks_idx=332
obj_f_critter_seen_maplist=333
obj_f_critter_pad_i64as_2=334
obj_f_critter_pad_i64as_3=335
obj_f_critter_pad_i64as_4=336
obj_f_critter_pad_i64as_5=337
obj_f_critter_end=338

obj_f_pc_begin=339
obj_f_pc_flags=340
obj_f_pc_pad_ias_0=341
obj_f_pc_pad_i64as_0=342
obj_f_pc_player_name=343
obj_f_pc_global_flags=344
obj_f_pc_global_variables=345
obj_f_pc_voice_idx=346
obj_f_pc_roll_count=347
obj_f_pc_pad_i_2=348
obj_f_pc_weaponslots_idx=349
obj_f_pc_pad_ias_2=350
obj_f_pc_pad_i64as_1=351
obj_f_pc_end=352

obj_f_npc_begin=353
obj_f_npc_flags=354
obj_f_npc_leader=355
obj_f_npc_ai_data=356
obj_f_npc_combat_focus=357
obj_f_npc_who_hit_me_last=358
obj_f_npc_waypoints_idx=359
obj_f_npc_waypoint_current=360
obj_f_npc_standpoint_day_INTERNAL_DO_NOT_USE=361
obj_f_npc_standpoint_night_INTERNAL_DO_NOT_USE=362
obj_f_npc_faction=363
obj_f_npc_retail_price_multiplier=364
obj_f_npc_substitute_inventory=365
obj_f_npc_reaction_base=366
obj_f_npc_challenge_rating=367
obj_f_npc_reaction_pc_idx=368
obj_f_npc_reaction_level_idx=369
obj_f_npc_reaction_time_idx=370
obj_f_npc_generator_data=371
obj_f_npc_ai_list_idx=372
obj_f_npc_save_reflexes_bonus=373
obj_f_npc_save_fortitude_bonus=374
obj_f_npc_save_willpower_bonus=375
obj_f_npc_ac_bonus=376
obj_f_npc_add_mesh=377
obj_f_npc_waypoint_anim=378
obj_f_npc_pad_i_3=379
obj_f_npc_pad_i_4=380
obj_f_npc_pad_i_5=381
obj_f_npc_ai_flags64=382
obj_f_npc_pad_i64_2=383
obj_f_npc_pad_i64_3=384
obj_f_npc_pad_i64_4=385
obj_f_npc_pad_i64_5=386
obj_f_npc_hitdice_idx=387
obj_f_npc_ai_list_type_idx=388
obj_f_npc_pad_ias_3=389
obj_f_npc_pad_ias_4=390
obj_f_npc_pad_ias_5=391
obj_f_npc_standpoints=392
obj_f_npc_pad_i64as_2=393
obj_f_npc_pad_i64as_3=394
obj_f_npc_pad_i64as_4=395
obj_f_npc_pad_i64as_5=396
obj_f_npc_end=397

obj_f_trap_begin=398
obj_f_trap_flags=399
obj_f_trap_difficulty=400
obj_f_trap_pad_i_2=401
obj_f_trap_pad_ias_1=402
obj_f_trap_pad_i64as_1=403
obj_f_trap_end=404

obj_f_total_normal=405
obj_f_transient_begin=406
obj_f_render_color=407
obj_f_render_colors=408
obj_f_render_palette=409
obj_f_render_scale=410
obj_f_render_alpha=411
obj_f_render_x=412
obj_f_render_y=413
obj_f_render_width=414
obj_f_render_height=415
obj_f_palette=416
obj_f_color=417
obj_f_colors=418
obj_f_render_flags=419
obj_f_temp_id=420
obj_f_light_handle=421
obj_f_overlay_light_handles=422
obj_f_internal_flags=423
obj_f_find_node=424
obj_f_animation_handle=425
obj_f_grapple_state=426
obj_f_transient_end=427
obj_f_type=428
obj_f_prototype_handle=429

Try and have those memorised by Tuesday ;-)

Ok, enough bamboozling you, lets pick a specific one and play with it.

We are gonna use obj_f_npc_pad_i_5=381 as a variable that will be changed according to the ongoing state of what is happening to the character. We are using that particular integer because Blue used it for the shop-keeper-reinventorising and I know it works ;-) Go and have a look at Burne's .py file, he uses things in a more integrated way than I bother with (I am keeping it simple).

My guinea-pig for today is Endarire's NPC Ronald. You may remember (but probably won't) that he already has a story-state variable dependant on what the party have done to him (like dump him to recruit Lareth, or other pleasant actions). If necessary, refamiliarise yourself from this tutorial HERE (hint: its not necessary for this tutorial).

Sooo... what do we want to do? Well:

Read the integer.

Set the integer.

Simple! For what purpose?

Well, its a story-state variable. The first time it will appear is when Ronald hits level 17 and gains the clerical power to take care of something that he has had on his mind throughout the entire game. So firstly, we want it to trigger an event when Ron becomes lvl 17 and then advance the variable accordingly. But where to put it? First_heartbeat is an option, but Ron's is already a fiasco. Soooo, lets put it for starters in san_new_map. At the moment, Ron's looks like this:

def san_new_map( attachee, triggerer ):
________if (attachee.map == 5004):
________________attachee.float_line(650,triggerer)
________________game.new_sid = 0
________return RUN_DEFAULT

What this does is have Ron make a quirky remark when he enters the Moathouse, then sets it to zero so it never happens again (Endarire not only recorded dialogue for all the stuff the NPCs can say in the game, like "my pack is full" and "hey look Emridy Meadows", bur also a fair bit for stuff they don't normally say, and left me to script workarounds. Here is one).

Instead of setting the bugger to zero, lets see if you can set it to some other number (of course theoretically we all know you can, but has anyone ever tried?) I am setting it to 283, my ioun stone .py file, in the happy knowledge it will never be asked to use a new_map thing (in fact, doesn't even have it in its prototype). Liv used to do this a lot, stick scripts in other scripts that wouldn't get called by their original owner: for instance, the OCF_MUTE thing for the trolls we looked at last time is actually in the script for that woman in Hommlet, ummm the one married to Filliken's brother (Percy?) who sets you on the whole love-quest roundabout.

NPC: Your just as sweet as sugar.
PC: Just doing my job, ma'am.

Something like that - and quality dialogue for once! Ahhh, didn't that run out quickly... anyways, first time I saw that thing in her file, I thought, "crikey, THATS who's got the password? She must be suggested or something... i wonder how we would know?" But of course it was nothing to do with her, just using her script. The "Peter, I've been murdered by gnolls!" interlude is likewise hidden in Kent's stuff.

But I digress. The point is, diverting a character to this or that script, while having inherent dangers (remember when I tried to run all the san_dying things off one script and Otis etc yelled out in Spugnoir's voice when they died?) is damn handy. Will be doing this for KotB, having different scripts for the guards to switch between depending on how they feel about the party.

Anyways, the altered script from py00277Ron.py looks like this:

def san_new_map( attachee, triggerer ): # after moathouse, sets to 283
________if (attachee.map == 5004):
________________attachee.float_line(650,triggerer)
________________game.new_sid = 283
________return RUN_DEFAULT

Painless. Now what about the accompanying file, py00283ioun.py? That now looks like this:

def san_new_map( attachee, triggerer ): # Ron after moathouse
________game.particles( "sp-Magic Stone", triggerer )
________st = attachee.obj_get_int( obj_f_npc_pad_i_5 )
________if (st == 0 and (attachee.stat_level_get(stat_level_cleric) == 8)):
________________attachee.obj_set_int( obj_f_npc_pad_i_5, 1 )
________________game.party[0].begin_dialog( attachee, 2000 )
________else:
________________game.particles( "sp-summon monster I", game.party[0] )
________return RUN_DEFAULT

The first and last game.particles things are just there to let me know it is firing (I had a shocker getting it to work, because I had a stupid typo in the script, but thought I had made some other sort of error - thought maybe i needed to do a second dlg at 00283 (I didn't) - but finally got it going). Otherwise, its the other stuff that is of interest.

Now, this is just to initiate the first "I have turned lvl 17" dialogue. Note I am using lvl 8 for the moment because I couldn't be bothered entering 'levelup' enough times just yet to get him to lvl 17 (I know its just typing it in, then 'up' + 'return' several dozen times, but I'm a lazy, lazy man Roger...) will do that when I am satisfied the script works. When that happens, there will be additional stuff here and in the san_dialog thing to advance the story through the various parts of the endgame, but thats for later. This is a flags tutorial, not a Ronald tutorial ;-)

So, reading and setting the flags? Here they are again:

st = attachee.obj_get_int( obj_f_npc_pad_i_5 ) (where 'st' is the name of the variable of course)

attachee.obj_set_int( obj_f_npc_pad_i_5, 1 )

Note that in the second one, we are setting the value at 1 (for the moment). Thats whay the 1 is for. We could set it at something else, and will later. A bit different to how we set global variables or OCF_FLAGS etc.

Well, there you go, now your objects can have personal flags that will never clash with anyone else's - and for the moment you know as much about them as I do ;-) Later I will update this with stuff about how to use the personal flags to see if another NPC has done something or other (not sure how I will do that, but we'll see ;-) and how to read the internal health of your NPC:

obj_f_npc_who_hit_me_last=358

Mmm, roleplaying... me RIKEY!!!

O and while we're at it...

obj_f_npc_substitute_inventory=365

Change number in event of Masterwork quest? Hmmm, must test this, and there are several other contenders...

Thanks again to C-Blue, and folks like Agetian and Darmagon who helped track all these down.

Monday, April 24, 2006

Flag Tutorial (updated)

UPDATED 24/4/6

Note: Some changes have been made to how the OCF flags are handled! Re-read the end parts!

Winnings: $539

Woohoooo!!! The long awaited flags tutorial appears!

Well some at least... I will describe some of the basic ways of using flags, ones that come from inside the game and thus we know work. In some cases they are things I have discovered myself - be sure I will crow long and loud about those! In most cases they are things found by others such as Liv, Agetian and Dulcaion. Also, at some point we will look at individual variables (as opposed to the global kind) based on some stuff done by Agetian and Cerulean the Blue. Most importantly, this tutorial will be done in parts and will be upgraded at various points as I think of new stuff.

What are flags? Well, I am not talking the global.flags and global.vars, I am speaking about the various object flags, critter flags, npc flags etc that can be put into the prototype or mobbed into specific critters using ToEEWB. If you have used ToEEWB and opened a mob, or made a new one, you will doubtless have noticed long lists of flags. Lets look at them now:

Object Flags (OF_*)

OF_DESTROYED
OF_OFF
OF_FLAT
OF_TEXT
OF_SEE_THROUGH
OF_SHOOT_THROUGH
OF_TRANSLUCENT
OF_SHRUNK
OF_DONTDRAW
OF_INVISIBLE
OF_NO_BLOCK
OF_CLICK_THROUGH
OF_INVENTORY
OF_DYNAMIC
OF_PROVIDES_COVER
OF_RANDOM_SIZE
OF_NOHEIGHT
OF_WADING
OF_LOOTED
OF_STONED
OF_DONTLIGHT
OF_TEXT_FLOATER
OF_INVULNERABLE
OF_EXTINCT
OF_DISALLOW_WADING
OF_HEIGHT_SET
OF_ANIMATED_DEAD
OF_TELEPORTED
OF_RADIUS_SET

Item Flags (OIF_*)

OIF_IDENTIFIED
OIF_WONT_SELL
OIF_IS_MAGICAL
OIF_NO_PICKPOCKET
OIF_NO_DISPLAY
OIF_NO_DROP
OIF_NEEDS_SPELL
OIF_CAN_USE_BOX
OIF_NEEDS_TARGET
OIF_LIGHT_SMALL
OIF_LIGHT_MEDIUM
OIF_LIGHT_LARGE
OIF_LIGHT_XLARGE
OIF_PERSISTENT
OIF_MT_TRIGGERED
OIF_STOLEN
OIF_USE_IS_THROW
OIF_NO_DECAY
OIF_UBER
OIF_NO_NPC_PICKUP
OIF_NO_RANGED_USE
OIF_VALID_AI_ACTION
OIF_DRAW_WHEN_PARENTED
OIF_EXPIRES_AFTER_USE
OIF_NO_LOOT
OIF_USES_WAND_ANIM
OIF_NO_TRANSFER
OIF_FAMILIAR

Critter Flags (OCF_*)

OCF_IS_CONCEALED
OCF_MOVING_SILENTLY
OCF_EXPERIENCE_AWARDED
OCF_FLEEING
OCF_STUNNED
OCF_PARALYZED
OCF_BLINDED
OCF_HAS_ARCANE_ABILITY
OCF_SLEEPING
OCF_MUTE
OCF_SURRENDERED
OCF_MONSTER
OCF_SPELL_FLEE
OCF_ENCOUNTER
OCF_COMBAT_MODE_ACTIVE
OCF_LIGHT_SMALL
OCF_LIGHT_MEDIUM
OCF_LIGHT_LARGE
OCF_LIGHT_XLARGE
OCF_UNREVIVIFIABLE
OCF_UNRESSURRECTABLE
OCF_NO_FLEE
OCF_NON_LETHAL_COMBAT
OCF_MECHANICAL

Critter Flags 2 (OCF2_*)

OCF2_ITEM_STOLEN
OCF2_AUTO_ANIMATES
OCF2_USING_BOOMERANG
OCF2_FATIGUE_DRAINING
OCF2_SLOW_PARTY
OCF2_NO_DECAY
OCF2_NO_PICKPOCKET
OCF2_NO_BLOOD_SPLOTCHES
OCF2_NIGH_INVULNERABLE
OCF2_ELEMENTAL
OCF2_DARK_SIGHT
OCF2_NO_SLIP
OCF2_NO_DISINTEGRATE
OCF2_TARGET_LOCK
OCF2_ACTION*_PAUSED

NPC Flags (ONF_*)

ONF_EX_FOLLOWER
ONF_WAYPOINTS_DAY
ONF_WAYPOINTS_NIGHT
ONF_AI_WAIT_HERE
ONF_AI_SPREAD_OUT
ONF_JILTED -
ONF_LOGBOOK_IGNORES
ONF_KOS
ONF_USE_ALERTPOINTS
ONF_FORCED_FOLLOWER
ONF_KOS_OVERRIDE
ONF_WANDERS
ONF_WANDERS_IN_DARK
ONF_FENCE
ONF_FAMILIAR
ONF_CHECK_LEADER
ONF_CAST_HIGHEST
ONF_GENERATOR
ONF_GENERATED
ONF_GENERATOR_RATE1
ONF_GENERATOR_RATE2
ONF_GENERATOR_RATE3
ONF_DEMAINTAIN_SPELLS
ONF_BACKING_OFF
ONF_NO_ATTACK
ONF_BOSS_MONSTER
ONF_EXTRAPLANAR

This list is, of course, nicked from the forum HERE. Now, it is not the purpose of this blog to explain the meaning of these - thats what the thread is for - but rather to explain how to access them in-game. I will do this by demonstrating one of each type using an example from the game I know works. Lets start with a look at the most obvious:

OF_OFF

This is the most frequently used flag in scripts. Simply put, it turns the critter on or off: when off, the critter can still fire its scripts (eg heartbeat scripts) but will not be drawn or turn up on the radar for find_npc_near or anything like that.

To access the flag in a script, use the following commands:

________________attachee.object_flag_set(OF_OFF)

________________attachee.object_flag_unset(OF_OFF)

Simple, init? And so it goes for the various other Object Flags (OF_...). Or so I assume, no time to test them all! But note that a .mob set OF_OFF canNOT be unset by this flag! (Thanks Cerulean the Blue). I will keep an eye out for what can be over-ridden in the .mobs by scripts and what can't - I don't know if this is the only one or if that is a blanket thing. Annoying if it is - but I don't think so, because, (as you will see below) KOS_OVERRIDE in a script will speak over a .mobbed KOS flag (which is not the same as unsetting it... hmmm... wonder if the override exists precisely because you can't unset a .mobbed flag? More testing needed!)

Moving right along for the critter flags:

OCF_MUTE

This was sorta discovered by Liv and Dulcaion, I don't think it turns up in scripts in the original ToEE but is found a lot nowdays. It allows monsters to speak under very specific circumstances who would normally be mute (if they were not mute, they would make random comments if you snuck up and clicked on them, like NPCs without specific dlg files do. Having dire rats say, "good morning sir" when u click on them is less than necessary). So where the OCF_MUTE flag may be set by the prototype or the mob, it can be overriden and switched off in specific circumstances by the script, then reactivated when you are done talking to it. (The thread dealing with all this is HERE and is well worth reading for the issue at hand. It is also well worth reading for several other nostalgic reasons but a tutorial is no place to go into it. Note that I disagree with Dulcaion's assertion that unsetting a flag breaks the script - that sounds like the classic symptom of a minor cockup, I've had many. More testing needed).

So what do the scripts look like? Here they are, hot from the .py files:

def san_first_heartbeat( attachee, triggerer ):
________if (attachee.map != 5080 or game.global_flags[813] == 1):
________________attachee.critter_flag_set( OCF_MUTE )
________game.new_sid = 0
________return RUN_DEFAULT

Now... note that previoulsy I said it was flagS where the previous (object) and following (npc) flags are in the singular. I have now REVERSED that opinion, based on more extensive reading of Dulcaion's tests, and also some of my own experience. Thus that little script above has been altered from the one in-game, which is, again based on my experience, broken. Took me a while for it to sink in. (Thats a really perverse use of game.new_sid too, in context). That flag is meant to mute trolls found elsewhere than dungeon level 4 (where u can try to beat a password for the trap out of them. They don't actually know it - damn Liv was a champ! A red herring no less!) However, long-term readers of the forum will remember a funny pic I posted where I clicked on a troll and he said, "me no see you" because my guy was invisible. Now, my troll was on dungeon lvl THREE, in Thrommel's room (a random encounter caused by sleeping). It has always niggled at the back of my mind, why wasn't he mute when he wasn't on lvl 4? Leaving aside the issue of whether muting affects floating text (Liv pretty conclusively showed it does, Dulcaion disagreed) I think that shows the code I originally posted (saying attachee.critter_flagS_set( OCF_MUTE )) was probably broken. Also there is the common sense element that it should not be in a different form than the other flags (which require a singular flag thing) and finally, in Dulcaion's final post on this issue he made exactly this point. So barring conclusive testing otherwise, thats gonna be my official position.

Damn I hate it when I post something wrong in my tutorials! Hate it... please understand, I try to stick to things I have personally done or used, but periodically use scripts I have come across by Liv but not personally seen in action (like here), or in the game that I know werk. Let me at least assure you I NEVER just make stuff up and post it on the basis that it SHOULD work: amyone who has modded knows u hit problems with things that 'should' work all the time, thats why we need tutorials. Anyways, my apologies for the error.

So... npc flags :-)

ONF_KOS

Here's a common flag, and well worth being able to manipulate since changing critters to KOS (or not) depending on the player's actions makes for a nicely interactive game. Setting the flag in the prototype or mob is straightforward enough, but what about changes in game? One way is to use the san_will_kos thing in the protoype. That can look something like this:

def san_will_kos( attachee, triggerer ):
________if (game.global_flags[840] == 1 and attachee.map == 5065):
________________return SKIP_DEFAULT
________return RUN_DEFAULT

Simple enough, and speaks volumes about the difference between skipping and running the default scripts.

What about changing it on the fly from scripts? I had to discover this one myself, and what a pita it was!!! But it was damn useful since of course it will work for all NPC flags. Here is a snapshot of the upcoming Moathouse respawn:

________________bear1 = game.obj_create( 14052, location_from_axis (429L, 437L) )
________________bear1.rotation = 2
________________bear1.npc_flag_set( ONF_KOS )
________________bear2 = game.obj_create( 14053, location_from_axis (427L, 447L) )
________________bear2.rotation = 3
________________bear2.npc_flag_set( ONF_KOS )

I spawned some bears wandering around outside the walls of the moathouse, but since they were usually animal familiars, they had no KOS flags set. Can't have summoned animals attacking the party ;-)

Now... this brings us to the KOS_OVERRIDE script. I added one of these to KotB as I have a guy who runs amok under certain conditions, but unless u have met those conditions you should never get near him. So, I flagged him KOS with a thought to maybe altering it later. Well, later is fast approaching ;-) so I left him .mobbed as KOS and added the following script:

def san_first_heartbeat( attachee, triggerer ):
________if game.quests[4].state == qs_unknown:
________________attachee.npc_flag_set( ONF_KOS_OVERRIDE )
________return RUN_DEFAULT

Damn backwards ;-) should leave him normal then make him KOS when the time is right, but meh I say. It'll do for now - one reason I often do things backwards or in weird ways is to learn how to do new stuff. This worked for that end, so stop complaining!

Speaking of first_heartbeat files, here's a reminder of something I also put in the Well Whaddya Know? thread: The first time you enter a map, all the first_heartbeat files will fire everywhere. However, if you have been there before, they only fire as you enter their sector. So if you are adding to a first_heartbeat file, as well as using a save from off the map (I made that mistake with the file above, then wondered why it didn't work ;-)) you may have to enter the sector to get it to work, EVEN THOUGH if you have mobbed something new in it will work straight away whatever sector its in. That can be confusing if u r using little tells like having game.particles fire to let you know certain internal effects are working: when some work and others don't, you of course assume you have screwed up somewhere. Try walking into the sector first.

Ok, thats our basic NPC flags dealt with (OCF2 still to do). What about item flags? Mr Blue mentioned the other day that item flags look like this, as you might expect:

obj.item_flag_set( OIF_FLAG )

Again, its just common sense :-)

Soooooooo... what about reading flags? Here's something complicated by Dulcaion that will probably tell you more about reading flags than you want to know!

- First I collected a list of all the critters in the vicinity of my party (that includes the party members), calling it a

>>> a = game.obj_list_vicinity(game.party[0].location, OLC_CRITTERS)

- I then examined a and found out that the Murderous thief was item 5 (a[5]) with simply

>>> a

- I then examined OCF_MUTE to find out its binary value (it's 8192)

>>> OCF_MUTE

For reference, 8192 in binary is
0000 0000 0000 0010 0000 0000 0000

- Then I checked his critter flags

>>> a[5].critter_flags_get()

This returns 134488064, which is (in binary):
1000 0000 0100 0010 0000 0000 0000

So you can see that the mute flag IS set (the 0010 column lines up with a 1 between the two numbers in binary)

- Then I unset the mute flag with

>>> a[5].critter_flags_unset(OCF_MUTE) (Ted says: don't believe that flagS!!)

- I checked the results

>>> a[5].critter_flags_get()

this time, it was 134479872, or
1000 0000 0100 0000 0000 0000 0000

so you can see that the mute flag WAS cleared by the command.


I know its a pain me posting things and adding, "Btw I haven't tested it but its wrong" but again this was by Dulcaion and he basically added an errata saying as much himself. Anyways, I think that is well worth reading all that, because the flags themselves are of course stored as binary within the .mobs. This is why you can't click, say, the 'items' thing in ToEEWB on a .mob for an NPC: at the appropriate part of the .mob, clicking that will add

0000 0000 0000 0000 0000 0000 0000

to the .mob and kaboom, the damn thing doesn't work because NPC .mobs aren't meant to have item flags and the game can't read what it sees. It also explains no matter how many flags you set or unset, the .mob file doesn't change size, only adding a new TYPE of flag (or indeed all the flags of that type for the same size-price) will change the size. We don't all have to be Agetians, but every little bit of understanding helps. :-)

So, lets go back and see about the flag-reading thing. Here's another example from the upcoming moathouse spawn: and let me assure you this works, because I tested my a$$ off on it, complete with many private discussions with Mr Blue, and many different formats. Turned out I was doing the right thing all along - it was the fact my first_heartbeat files weren't firing on subsequent trips til I entered the sector that was making me think nothing was working. I sent C-Blue a screaming ranting (but also exulting) email about the evils of first_heartbeat files when I finally got to the end of it, and he hasn't spoken to me since ;-)

def san_first_heartbeat( attachee, triggerer ):
________y = (attachee.critter_flags_get() & OCF_MUTE)
________bandit1 = find_npc_near(attachee,14070)
________bugbear2 = find_npc_near(attachee,14172)
________gnolls1 = find_npc_near(attachee,14079)
________gnolls2 = find_npc_near(attachee,14066)
________if (attachee.map == 5005 and game.areas[4] == 1):
________________if game.global_vars[52] >= 2:
________________________game.obj_create( ??? )
________________________game.obj_create( ??? )
________________________game.obj_create( ??? )
________________________game.obj_create( ??? )
________________________game.global_vars[52] = 0
________________if y == 0:
________________________game.particles( "sp-summon monster I", game.party[1] )
________________________if (bugbear2 == OBJ_HANDLE_NULL):
________________________________game.obj_create( ??? )
________________________________game.obj_create( ??? )
________________________________game.obj_create( ??? )
________________________________game.obj_create( ??? )
________________________________game.obj_create( ??? )
________________________attachee.destroy()
________________else:
________________________game.particles( "sp-summon monster I", game.party[0] )
________________________if ((gnolls1 == OBJ_HANDLE_NULL) and (gnolls2 == OBJ_HANDLE_NULL) and game.global_flags[288] != 1):
________________________________game.obj_create( ??? )
________________________________game.obj_create( ??? )
________________________________game.obj_create( ??? )
________________________________game.obj_create( ??? )
________________________attachee.destroy()
________else:
________________return SKIP_DEFAULT
________return RUN_DEFAULT

Note the game.particles are merely there for testing purposes, I have left out what is spawned so there will be some surprises, and there is lots more to this (all the spawning stuff for the upstairs and outside). They were simple enough, make a .mob, stick it somewhere where it could tell if the players have been through or not (eg the outside one is in the middle of the bandits) then do a quick nearby NPC check to seee if the players went that way and wasted all the monsters. If so, spawn - if not, don't spawn. 'Game.area[4] == 1' is to check if the players have found the temple yet, thats the trigger for this new lot of content - if they have, then they have been gone long enough for the bodies to rot (dead monsters still show up on find_npc_near checks!) and they are a healthy level to come back and try this (ok, they may have just gone to Nulb, got the location from Otis, then raced back here, but if they do it that quick the bodies may not have rotted, so nothing will spawn - EVER - and they have ruined their added content. Ne'er mind - at that level they would not have survived these encounters anyways ;-))

So much for the upper levels (keep in mind there are not new critters in every room, just a few new encounters here and there to show what the new owner of the place is up to - namely, adding undead as she can). BUT for the lower levels, there are a number of encounters the players may never have done - if they use the secret stairs to go via the Zombies and Ghouls (skipping the much tougher Lugbash / Gnolls / Bugbears encounters) they could easily have gone straight through to Lareth, killed his men (one web and a couple charms and then sit back and enjoy :-)), dealt with him, gone out the back door, then come back later. Can't just add a bunch of new monsters to the gnolls' or bugbears' rooms under such circumstances, they will set on the gnolls and bugbears! (The gnolls have been respawned as skeletal gnolls, as you might expect - something rather more nasty has moved into the bugbears' old apartments). So, I need multiple .mobs running find_npc_near in different places (or, a counter added to their san_dying files, but if said bugbears and gnolls in the protos.tab turn up somewhere else, eg in random encounters or in new content added by people saying "hey those protos look ideal", this could be triggered wrongly.)

Multiple prototypes? Nah, too much effort ;-)

Multiple .mobs of one prototype? But then they will all be using the same first_heartbeat script. That means a lot of global flags, dunnit?

In the past, yes! But today, nah... u should know now how much I hate using global flags if I can help it. And as it turns out, I can help it here :-)

What I did was add OCF_MUTE to one of the mobs but not the other, and differentiated between them that way :-) Thats what the first variable 'y' does, it checks to see whether the attachee (that specific .mob) has the flag set, by logically ANDing it with the flags as read. If it does, its the .mob sitting in the middle of the gnolls (OF_OFF of course. game.global_flags[288], btw, is set by u bribing the gnolls: it would mean they would not show up as there, but of course they shouldn't have been lying around as corpses waiting to be reanimated as skeletal gnolls either, so in that case they don't show).

If it returns a zero on the AND, meaning the flag was not set, I know I am dealing with the bugbears' .mob, and it can test if they are around (I had a bugbear1 test as well but he would pick up one of the ones hiding in the little rooms behind the doors. People could easily forget them or not bother with them - I know I have done both in the past - so I am not going to care if they are there or not, as long as the rest have been dealt with, thats ok. If people want to pull the hiding bugbears into combat at their rear while dealing with the new monsters, thats their business).

Either way, they only fire once then are destroyed. The first to fire also deals with the issue of the main inhabitant (who is set up in Lareth's old rooms of course, not much of a spoiler that!), thats the first little spawny thing. game.global_vars[52] was put in the san_dying thing of Lareth's leiutenant and seargant, two unique critters who should not be showing up elsewhere, and as long as they are both dead this will fire (then it is reset to 0, only fires once). If you suggested one of them, then u r in trouble - but you shouldn't have suggestion at that level anyways!

Quick recap: to find if a critter flag is set, use:

attachee.critter_flags_get() & OCF_FLAG

Note that yes it IS flagS when getting but not when setting!!! That is tested and undisputed!

Next time, personal obj flags, they'll be thanks again to C-Blue! To go straight there, click HERE.

Thursday, April 13, 2006

Sleepless in Sydney

Winnings: $733

Another night with barely 3 hours sleep. Stupid shiftwork.

Rather than lay around grumbling, I got up and worked on the moathouse respawn. Having done the hard yards (hacking up some long 'game.obj_create' lists, putting stuff in the protos.tab, working out spawning locations) I actually hacked the damn scripts into the game and tested. Took me about an hour to get the simplest thing to work (I left out a comma... [sigh]) but when I did, it all worked nicely. I have now got a respawn for the outer moathouse, and since this is nothing special, I don't mind giving out a spoiler - the bodies of the bandits have been animated by the moathouse's new owner, and there are some angry animals outside that have wandered in from the swamp. Just something simple: main thing was to only get it to fire if the bandits acyually were dead (the party may have initially gone around by the back door), otherwise apart from the RP fiasco aspect, the undead would have had at the bandits upon spawning. Funny, but hardly appropriate.

Liv's Skeletal Priest makes a reappearance (the concept, not the specific monster!) and if people don't like that, I don't care. His ability to Desecrate the battle field is the difference between a moderate level party having a fun encounter, and them simply pulling out a holy symbol at the first wiff of undead and incinerating them before they even clambered out of the ground.

That being said, this will be a bare-bones hack, folks are more than free to improve upon it once it is released (I want to get back to KotB and am not interesting in making a complicated cunning stunt, anyone else who wants to, hey go for it). So anyone who feeels the need to turn him into a Ranger-ghost, well, if u put the hard yards in, meh I say.

Saturday, April 08, 2006

Shadows of the NIght

Winnings: $571

Attentive readers will notice I had another loss: for the second time I had clawed back what I lost, only to lose it again immediately. Frankly I'm sick of it. The system is officially on hiatus for retooling, and my hard-earned is instead going to pay off the credit card, which I dare say is far more sensible anyway.

I am back on nightshifts for a couple days. U know, being back into ToEE for 4.1.0 has really given me a taste for the ol' girl... hmmm lemme rephrase that. I feel quite inspired to add new stuff, where previously I was basically over it and just going through the motions for contractual obligation (wanting rather to focus solely on KotB). Not only am I doing the Moathouse respawn, but thanks to a healthier understanding of some of the flags, I am really hanging to do the Thrommel changes too that I put on hold a while back, and once we know where things stand, I wanna knock over Endarire's npc once and for all :) And as u all doubtless know, I have a taste for getting the repeating crossbows functioning in some form - fine weapons they are! Damn fine! Interesting the various feats that are mentioned in the game, I wonder what others work on some level. Improved shield bash is there (though how we could associate it with a shield-weapon is beyond me), and so is weapon proficiency for gauntlets (would be nice to get that happening for the boxing gloves). Well, it will all have to wait for Brad, because even if I was inlined to try to hack new feats in (and I don't for one moment claim I could, even the easy ones) to hack the .dll when Brad is giving it such an overhaul would be ridiculous. If I am not mistaken, Brad is not just hacking bits and pieces here and there, he is completely decompiling and recompiling it to add various new stuff (Moebius didn't go that far - he hacked in new stuff over existing but non-active stuff if I am not mistaken, so the file stayed the same size etc) so anything I or anyone else did would of course clash with Brad's efforts.

Speaking of flags - seems like centuries I have been promising a flags tutorial. Well thanks to some diligent work by Cerulean, I am more informed, and since I HAVE to do a few flags to get the respawn to work properly, I will have no excuse for not tutorialising as I go.

Where does that leave KotB? Well, tonight here at work I hacked up a chunk of the Invensource with some randomly determined outfits: a random Farmer Garb set, Villager Garb set, Wizard Robe set, Mystic set and Noble Set (the last 2 being rather small). These can be attached to various ancilliary characters, such as Guild merchants showing up during the course of things, or folks like the stablehands etc. This way, when they spawn in each new game, they will have different clothes. Of course this assumes a script spawning - a lot of characters in the game will be script-spawned rather than modded so that there can be a random element introduced into their locations: for instance, i will spawn all the spiders in the spider forest (other than big mamma) from a spawner at the entrance: thus they can be put in very different positions. This will increase the replayability of the game - people won't know exactly what monsters will turn up where. Also, adding a spawner means if u clean out the Spider forest (for instance), it will be a peice of cake to have the game respawn the place later.

Not only will this mean NPCs will dress different and be in slightly different places from game to game, subtly helping in the feeling that something 'different' is going on, but having these sets all ready to go mean that using the 'load inventory' button in ToEEWB will allow people making mobs to have readymade clothes/boots/funny hat/money all ready to go, make things easier for people getting started and faster for me when I add stuff.

Thats the theory, anyway ;-)

Here's some Invensource entries, for no good reason. I also did a few shop inventories, the sorta deadly dull stuff that is ideal for nightshifts. Note these are atm completely untested.

{39}{Inner Gate Guard Chain Shield Sword HandAxe: 100,6453 100,6463 100,6473 100,6020 100,6021 100,6018 100,4802 100,4806 silver,2-12}
{40}{Inner Gate Guard Chain Longbow Sword: 100,6453 100,6463 100,6020 100,6021 100,4087 100,4043 100,5004 silver,2-12 gold,2-5}
{41}{Inner Gate Guard Scale Polearm: 100,6463 100,6020 100,6021 100,4043 100,4412 100,6805 copper,5-12}
{42}{Barkeep: 100,6180 100,6023 100,6076 100,4118 silver,40 gold,27 gems,60}
{43}{Peasant Farmer Garb: (6123,6142,6143,6144,6145,6146) 100,6011 (6025,6028,6034,6037,6235,6236,6237,6238,6283,6038) 25,6180 copper,5-12 silver,4-10}
{44}{Peasant Villager Garb: (6147,6148,6149,6150) (6025,6028,6034,6037,6235,6236,6237,6238,6283,6038) 100,6023 25,6185 copper,3-32 silver,40-80}
{45}{Peasant Monk Garb: (6203,6204,6205,6206,6207,6208) (6025,6028,6034,6037,6235,6236,6237,6238,6283,6038) 100,6045 copper,27-51 silver,3-33 gold,1-6}
{46}{Generic Desk with cash: silver,12-37 gold,4-19 platinum,1-11}
{47}{unused thus far}
{48}{Wizard Robed Figure: 100,6202 100,6283 (6109,6112,6081,6130,6329,6331,6332,6333) 10,6183 10,6184 10,6181 10,6192 10,6197 copper,1-20 silver,1-13 gold,21-36 platinum,1-11}
{49}{Guildmaster: 100,6021 100,6093 100,6182 100,6084 100,6090 100,4079 100,6202 gold,2-12}
{50}{Noble Garbed Figure: 100,6202 (6151,6016,6218,6159) 10,6082 10,6183 10,6184 10,6181 10,6192 10,6197 copper,14-38 silver,3-17 gold,9-15}
{51}{Mystic Garbed Figure: 100,6456 (6211,6212,6213) 10,6183 10,6184 10,6181 10,6192 10,6197 silver,3-27 gold,3-11}

Thursday, April 06, 2006

Bump!

Just bumping this little fella, lest it get deleted for lack of activity. Been busy lately, not to mention exhausted. My sleeping patterns are a nightmare.

Very excited about this crossbow thing. Tomorrow's a day off so hopefully I can get some sleep and wake up feeling up to doing some rigorous testing and workarounding. Stupid non-sleeping.

Saturday, April 01, 2006

Lazarus lives!

For anyone who missed my spamming on the forum, U5:Lazarus version 1.2, the final build, has just been released and has 2 mirrors up already. Its 520Mb, and I am hitting 50% as I type. No time to play it though, I am off to a damn overnight shift tonight :(

O - get it here:

http://www.planetdungeonsiege.com/ultima5/main.asp

Now, as for KotB, went on a photo rampage with my pa's very sweet digital camera, added some nice little bits to the game and been collecting screenies lately: will update the gallery soon. Otherwise, I have started work on a little element for ToEE that I think will add greatly to the gaming experience and answer a much-voiced request: and it will only be a few dozen lines of code. The informed will know what I am referring to. The intelligent will also know, because the answer is right in front of them. It won't be ready for the IRC chat tomorrow, but it shouldn't take long.

Re my ongoing promise to look at flags: here's a tip for you! To add something to the game that can function as an NPC (such as the noticeboard in KotB where u learn about new quests and recruit new members, or the book in the Welcome Wench where u do it in ToEE, or a talking statue, or some such thing that u want to be able to interact with but not get into fights) flag it as:

ONF_NO_ATTACK ONF_ALOOF

Can't see ONF_ALOOF in TOEEWB, have to have a word with Agetian 9^)