ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/loader.C
Revision: 1.65
Committed: Wed Mar 14 04:12:27 2007 UTC (17 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.64: +1 -1 lines
Log Message:
- rewrote more face handling code
- automatically send smooth faces, as the client will need them anyways
  and it makes little sense to wait for the client to axk for it. of course,
  gcfclient suffers from weird ordering problems again.
- UP_OBJ_FACE was often abused in situations where other things changed,
  updated lots of spaces, probably more to be done.
- update_smooth became so small that inlining it actually clarified
  the code. similar for update_space, which is not inlined for other reasons.
- faces were not initialised properly
- add versioncheck for face data
- rewrite invisibility handling a bit: god finger etc. now makes you blink,
  blinking routine has changed to be less annoying and more useful while
  still indicating invisibleness.

File Contents

# Content
1 /*
2 * CrossFire, A Multiplayer game for X-windows
3 *
4 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
5 * Copyright (C) 2002 Mark Wedel & Crossfire Development Team
6 * Copyright (C) 1992 Frank Tore Johansen
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 *
22 * The authors can be reached via e-mail at <crossfire@schmorp.de>
23 */
24
25 /* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects.
26 sub/add_weight will transcend the environment updating the carrying
27 variable. */
28
29 #include <global.h>
30 #include <loader.h>
31 #include <sproto.h>
32
33 /////////////////////////////////////////////////////////////////////////////
34
35 /* This table is only necessary to convert objects that existed before the
36 * spell object conversion to the new object. It was not practical
37 * to go through every mapping looking for every potion, rod, wand, etc
38 * that had a sp set and update to the new value. So this maps the
39 * old spell numbers to the name of the new archs.
40 * If you are adding a new spell, you should not modify this - you
41 * new spell won't have been used, and thus won't have any legacy object.
42 * NULL entries in this table are valid - to denote objects that should
43 * not be updated for whatever reason.
44 */
45 const char *spell_mapping[] = {
46 "spell_magic_bullet", /* 0 */
47 "spell_small_fireball", /* 1 */
48 "spell_medium_fireball", /* 2 */
49 "spell_large_fireball", /* 3 */
50 "spell_burning_hands", /* 4 */
51 "spell_sm_lightning", /* 5 */
52 "spell_large_lightning", /* 6 */
53 "spell_magic_missile", /* 7 */
54 "spell_create_bomb", /* 8 */
55 "spell_summon_golem", /* 9 */
56 "spell_summon_fire_elemental", /* 10 */
57 "spell_summon_earth_elemental", /* 11 */
58 "spell_summon_water_elemental", /* 12 */
59 "spell_summon_air_elemental", /* 13 */
60 "spell_dimension_door", /* 14 */
61 "spell_create_earth_wall", /* 15 */
62 "spell_paralyze", /* 16 */
63 "spell_icestorm", /* 17 */
64 "spell_magic_mapping", /* 18 */
65 "spell_turn_undead", /* 19 */
66 "spell_fear", /* 20 */
67 "spell_poison_cloud", /* 21 */
68 "spell_wonder", /* 22 */
69 "spell_destruction", /* 23 */
70 "spell_perceive_self", /* 24 */
71 "spell_word_of_recall", /* 25 */
72 "spell_invisible", /* 26 */
73 "spell_invisible_to_undead", /* 27 */
74 "spell_probe", /* 28 */
75 "spell_lg_magic_bullet", /* 29 */
76 "spell_improved_invisibility", /* 30 */
77 "spell_holy_word", /* 31 */
78 "spell_minor_healing", /* 32 */
79 "spell_medium_healing", /* 33 */
80 "spell_major_healing", /* 34 */
81 "spell_heal", /* 35 */
82 "spell_create_food", /* 36 */
83 "spell_earth_to_dust", /* 37 */
84 "spell_armour", /* 38 */
85 "spell_strength", /* 39 */
86 "spell_dexterity", /* 40 */
87 "spell_constitution", /* 41 */
88 "spell_charisma", /* 42 */
89 "spell_create_fire_wall", /* 43 */
90 "spell_create_frost_wall", /* 44 */
91 "spell_protection_from_cold", /* 45 */
92 "spell_protection_from_electricity", /* 46 */
93 "spell_protection_from_fire", /* 47 */
94 "spell_protection_from_poison", /* 48 */
95 "spell_protection_from_slow", /* 49 */
96 "spell_protection_from_paralysis", /* 50 */
97 "spell_protection_from_draining", /* 51 */
98 "spell_protection_from_magic", /* 52 */
99 "spell_protection_from_attack", /* 53 */
100 "spell_levitate", /* 54 */
101 "spell_small_speedball", /* 55 */
102 "spell_large_speedball", /* 56 */
103 "spell_hellfire", /* 57 */
104 "spell_dragonbreath", /* 58 */
105 "spell_large_icestorm", /* 59 */
106 "spell_charging", /* 60 */
107 "spell_polymorph", /* 61 */
108 "spell_cancellation", /* 62 */
109 "spell_confusion", /* 63 */
110 "spell_mass_confusion", /* 64 */
111 "spell_summon_pet_monster", /* 65 */
112 "spell_slow", /* 66 */
113 "spell_regenerate_spellpoints", /* 67 */
114 "spell_cure_poison", /* 68 */
115 "spell_protection_from_confusion", /* 69 */
116 "spell_protection_from_cancellation", /* 70 */
117 "spell_protection_from_depletion", /* 71 */
118 "spell_alchemy", /* 72 */
119 "spell_remove_curse", /* 73 */
120 "spell_remove_damnation", /* 74 */
121 "spell_identify", /* 75 */
122 "spell_detect_magic", /* 76 */
123 "spell_detect_monster", /* 77 */
124 "spell_detect_evil", /* 78 */
125 "spell_detect_curse", /* 79 */
126 "spell_heroism", /* 80 */
127 "spell_aggravation", /* 81 */
128 "spell_firebolt", /* 82 */
129 "spell_frostbolt", /* 83 */
130 "spell_shockwave", /* 84 */
131 "spell_color_spray", /* 85 */
132 "spell_haste", /* 86 */
133 "spell_face_of_death", /* 87 */
134 "spell_ball_lightning", /* 88 */
135 "spell_meteor_swarm", /* 89 */
136 "spell_comet", /* 90 */
137 "spell_mystic_fist", /* 91 */
138 "spell_raise_dead", /* 92 */
139 "spell_resurrection", /* 93 */
140 "spell_reincarnation", /* 94 */
141 "spell_immunity_to_cold", /* 95 */
142 "spell_immunity_to_electricity", /* 96 */
143 "spell_immunity_to_fire", /* 97 */
144 "spell_immunity_to_poison", /* 98 */
145 "spell_immunity_to_slow", /* 99 */
146 "spell_immunity_to_paralysis", /* 100 */
147 "spell_immunity_to_draining", /* 101 */
148 "spell_immunity_to_magic", /* 102 */
149 "spell_immunity_to_attack", /* 103 */
150 "spell_invulnerability", /* 104 */
151 "spell_defense", /* 105 */
152 "spell_rune_of_fire", /* 106 */
153 "spell_rune_of_frost", /* 107 */
154 "spell_rune_of_shocking", /* 108 */
155 "spell_rune_of_blasting", /* 109 */
156 "spell_rune_of_death", /* 110 */
157 "spell_marking_rune", /* 111 */
158 "spell_build_director", /* 112 */
159 "spell_create_pool_of_chaos", /* 113 */
160 "spell_build_bullet_wall", /* 114 */
161 "spell_build_lightning_wall", /* 115 */
162 "spell_build_fireball_wall", /* 116 */
163 "spell_magic_rune", /* 117 */
164 "spell_rune_of_magic_drain", /* 118 */
165 "spell_antimagic_rune", /* 119 */
166 "spell_rune_of_transference", /* 120 */
167 "spell_transference", /* 121 */
168 "spell_magic_drain", /* 122 */
169 "spell_counterspell", /* 123 */
170 "spell_disarm", /* 124 */
171 "spell_cure_confusion", /* 125 */
172 "spell_restoration", /* 126 */
173 "was summon evil monster", /* 127 *//* Not implenented as nothing used it */
174 "spell_counterwall", /* 128 */
175 "spell_cause_light_wounds", /* 129 */
176 "spell_cause_medium_wounds", /* 130 */
177 "spell_cause_heavy_wounds", /* 131 */
178 "spell_charm_monsters", /* 132 */
179 "spell_banishment", /* 133 */
180 "spell_create_missile", /* 134 */
181 "spell_show_invisible", /* 135 */
182 "spell_xray", /* 136 */
183 "spell_pacify", /* 137 */
184 "spell_summon_fog", /* 138 */
185 "spell_steambolt", /* 139 */
186 "spell_command_undead", /* 140 */
187 "spell_holy_orb", /* 141 */
188 "spell_summon_avatar", /* 142 */
189 "spell_holy_possession", /* 143 */
190 "spell_bless", /* 144 */
191 "spell_curse", /* 145 */
192 "spell_regeneration", /* 146 */
193 "spell_consecrate", /* 147 */
194 "spell_summon_cult_monsters", /* 148 */
195 "spell_cause_critical_wounds", /* 149 */
196 "spell_holy_wrath", /* 150 */
197 "spell_retributive_strike", /* 151 */
198 "spell_finger_of_death", /* 152 */
199 "spell_insect_plague", /* 153 */
200 "spell_call_holy_servant", /* 154 */
201 "spell_wall_of_thorns", /* 155 */
202 "spell_staff_to_snake", /* 156 */
203 "spell_light", /* 157 */
204 "spell_darkness", /* 158 */
205 "spell_nightfall", /* 159 */
206 "spell_daylight", /* 160 */
207 "spell_sunspear", /* 161 */
208 "spell_faery_fire", /* 162 */
209 "spell_cure_blindness", /* 163 */
210 "spell_dark_vision", /* 164 */
211 "spell_bullet_swarm", /* 165 */
212 "spell_bullet_storm", /* 166 */
213 "spell_cause_many_wounds", /* 167 */
214 "spell_small_snowstorm", /* 168 */
215 "spell_medium_snowstorm", /* 169 */
216 "spell_large_snowstorm", /* 170 */
217 "spell_cure_disease", /* 171 */
218 "spell_cause_red_death", /* 172 */
219 "spell_cause_flu", /* 173 */
220 "spell_cause_black_death", /* 174 */
221 "spell_cause_leprosy", /* 175 */
222 "spell_cause_smallpox", /* 176 */
223 "spell_cause_white_death", /* 177 */
224 "spell_cause_anthrax", /* 178 */
225 "spell_cause_typhoid", /* 179 */
226 "spell_mana_blast", /* 180 */
227 "spell_small_manaball", /* 181 */
228 "spell_medium_manaball", /* 182 */
229 "spell_large_manaball", /* 183 */
230 "spell_manabolt", /* 184 */
231 "spell_dancing_sword", /* 185 */
232 "spell_animate_weapon", /* 186 */
233 "spell_cause_cold", /* 187 */
234 "spell_divine_shock", /* 188 */
235 "spell_windstorm", /* 189 */
236 "spell_sanctuary", /* 190 */
237 "spell_peace", /* 191 */
238 "spell_spiderweb", /* 192 */
239 "spell_conflict", /* 193 */
240 "spell_rage", /* 194 */
241 "spell_forked_lightning", /* 195 */
242 "spell_poison_fog", /* 196 */
243 "spell_flaming_aura", /* 197 */
244 "spell_vitriol", /* 198 */
245 "spell_vitriol_splash", /* 199 */
246 "spell_iron_skin", /* 200 */
247 "spell_wrathful_eye", /* 201 */
248 "spell_town_portal", /* 202 */
249 "spell_missile_swarm", /* 203 */
250 "spell_cause_rabies", /* 204 */
251 "spell_glyph", /* 205 */
252 NULL
253 };
254
255 extern int arch_init;
256
257 /* This function checks the object after it has been loaded (when we
258 * get the 'end' in the input stream). This function can be used to
259 * deal with legacy objects where fields may have changed. It can also be used
260 * to check for objects to make sure there are no common errors.
261 */
262 static void
263 check_loaded_object (object *op)
264 {
265 /* We do some specialised handling to handle legacy cases of name_pl.
266 * If the object doesn't have a name_pl, we just use the object name -
267 * this isn't perfect (things won't be properly pluralised), but works to
268 * that degree (5 heart is still quite understandable). But the case we
269 * also have to catch is if this object is not using the normal name for
270 * the object. In that case, we also want to use the loaded name.
271 * Otherwise, what happens is that the the plural name will lose
272 * information (appear as just 'hearts' and not 'goblins heart')
273 */
274 if (op->arch && op->name != op->arch->clone.name && op->name_pl == op->arch->clone.name_pl)
275 op->name_pl = 0;
276
277 if (!op->name_pl)
278 op->name_pl = op->name;
279
280 /* objects now have a materialname. try to patch it in */
281 if (!(op->is_weapon () && op->level > 0))
282 {
283 if (op->map != NULL)
284 set_materialname (op, op->map->difficulty, NULL);
285 else
286 set_materialname (op, 5, NULL);
287 }
288
289 /* only do these when program is first run - a bit
290 * excessive to do this at every run - most of this is
291 * really just to catch any errors - program will still run, but
292 * not in the ideal fashion.
293 */
294 if ((op->type == WEAPON || op->type == BOW) && arch_init)
295 {
296 if (!op->skill)
297 LOG (llevError, "Weapon %s lacks a skill.\n", op->debug_desc ());
298 else if ((!strcmp (op->skill, "one handed weapons") && op->body_info[1] != -1) ||
299 (!strcmp (op->skill, "two handed weapons") && op->body_info[1] != -2))
300 LOG (llevError, "weapon %s arm usage does not match skill: %d, %s\n", op->debug_desc (), op->body_info[1], &op->skill);
301 }
302
303 /* We changed last_heal to gen_sp_armour, which is what it
304 * really does for many objects. Need to catch any in maps
305 * that may have an old value.
306 */
307 if (op->type == WEAPON
308 || op->type == ARMOUR || op->type == HELMET
309 || op->type == SHIELD || op->type == RING
310 || op->type == BOOTS || op->type == GLOVES
311 || op->type == AMULET || op->type == GIRDLE
312 || op->type == BRACERS || op->type == CLOAK)
313 {
314 if (op->last_heal)
315 {
316 LOG (llevDebug, "Object %s still has last_heal set, not gen_sp_armour\n", op->debug_desc ());
317 op->gen_sp_armour = op->last_heal;
318 op->last_heal = 0;
319 }
320
321 int ip = calc_item_power (op, 0);
322
323 /* Legacy objects from before item power was in the game */
324 if (!op->item_power && ip)
325 {
326 if (ip > 3)
327 LOG (llevDebug, "Object %s had no item power, using %d\n", op->debug_desc (), ip);
328
329 op->item_power = ip;
330 }
331
332 /* Check for possibly bogus values. Has to meet both these criteria -
333 * something that has item_power 1 is probably just fine if our calculated
334 * value is 1 or 2 - these values are small enough that hard to be precise.
335 * similarly, it item_power is 0, the first check will always pass,
336 * but not the second one.
337 */
338 if (ip > 2 * op->item_power && ip > (op->item_power + 3))
339 LOG (llevDebug, "Object %s seems to have too low item power? %d > %d\n", op->debug_desc (), ip, op->item_power);
340 }
341
342 /* Old spellcasting object - need to load in the appropiate object */
343 if ((op->type == ROD || op->type == WAND || op->type == SCROLL || op->type == HORN || op->type == FIREWALL ||
344 /* POTIONS and ALTARS don't always cast spells, but if they do, update them */
345 ((op->type == POTION || op->type == ALTAR) && op->stats.sp)) && !op->inv && !arch_init)
346 {
347 /* Fireall is bizarre in that spell type was stored in dam. Rest are 'normal'
348 * in that spell was stored in sp.
349 */
350 object *tmp = get_archetype (spell_mapping[op->type == FIREWALL ? op->stats.dam : op->stats.sp]);
351 insert_ob_in_ob (tmp, op);
352 op->randomitems = NULL; /* So another spell isn't created for this object */
353 }
354
355 /* spellbooks & runes use slaying. But not to arch name, but to spell name */
356 if ((op->type == SPELLBOOK || op->type == RUNE) && op->slaying && !op->inv && !arch_init)
357 {
358 object *tmp = get_archetype_by_object_name (op->slaying);
359 insert_ob_in_ob (tmp, op);
360 op->randomitems = NULL; /* So another spell isn't created for this object */
361 /* without this, value is all screwed up */
362 op->value = op->arch->clone.value * op->inv->value;
363 }
364
365 if (QUERY_FLAG (op, FLAG_MONSTER))
366 {
367 if (op->stats.hp > op->stats.maxhp)
368 {
369 LOG (llevDebug, "Monster %s has hp set higher than maxhp (%d>%d)\n", op->debug_desc (), op->stats.hp, op->stats.maxhp);
370 op->stats.maxhp = op->stats.hp;
371 }
372
373 /* The archs just need to be updated for this */
374 if (op->move_type == 0)
375 op->move_type = MOVE_WALK;
376 }
377
378 if ((QUERY_FLAG (op, FLAG_GENERATOR) && QUERY_FLAG (op, FLAG_CONTENT_ON_GEN)) || op->type == CREATOR || op->type == CONVERTER)
379 {
380 /* Object will duplicate it's content as part of the
381 * generation process. To do this, we must flag inventory
382 * so it remains unevaluated concerning the randomitems and
383 * the living (a demonlord shouldn't cast from inside generator!)
384 */
385 flag_inv (op, FLAG_IS_A_TEMPLATE);
386 }
387
388 /* Handle player movers. We use move_type for player movers
389 * because they operate on their own time (move_on
390 * would potentially cause them to be triggered when someone steps
391 * on them). If move_type is set, presume person knows what they
392 * are doing, otherwise, set move_type based on maxhp value.
393 */
394 if (op->type == PLAYERMOVER)
395 {
396 if (!op->move_type)
397 {
398 if (op->stats.maxhp)
399 {
400 op->move_type = MOVE_ALL;
401 op->stats.maxhp = 0;
402 }
403 else
404 op->move_type = MOVE_WALK;
405 }
406 }
407
408 }
409
410 static void
411 set_move (MoveType &mt, const char *str)
412 {
413 static const struct flagstr {
414 char *name;
415 MoveType flags;
416 } move_flags[] = {
417 { "walk" , MOVE_WALK },
418 { "flying" , MOVE_FLY_LOW | MOVE_FLY_HIGH },
419 { "fly_low" , MOVE_FLY_LOW },
420 { "fly_high", MOVE_FLY_HIGH },
421 { "swim" , MOVE_SWIM },
422 { "boat" , MOVE_BOAT },
423 { "all" , MOVE_ALL },
424 };
425
426 if (!str)
427 {
428 mt = 0;
429 return;
430 }
431
432 if (isdigit (*str))
433 {
434 mt = atoi (str);
435 return;
436 }
437
438 mt = 0;
439
440 for (str = strtok ((char *) str, " "); str; str = strtok (0, " "))
441 {
442 bool negate = 0;
443
444 if (*str == '-')
445 {
446 negate = 1;
447 str++;
448 }
449
450 for (const flagstr *f = move_flags; f < move_flags + sizeof (move_flags) / sizeof (move_flags [0]); ++f)
451 {
452 if (!strcmp (f->name, str))
453 {
454 if (negate)
455 mt &= ~f->flags;
456 else
457 mt |= f->flags;
458
459 goto next;
460 }
461 }
462
463 LOG (llevDebug, "common/loader.C: set_move - unknown move string '%s'\n", str);
464
465 next: ;
466 }
467 }
468
469 #define GET_FLAG(op,flag) \
470 if (f.get_sint32 ()) \
471 SET_FLAG (op, flag); \
472 else \
473 CLEAR_FLAG (op, flag) \
474
475 bool
476 object::parse_kv (object_thawer &f)
477 {
478 assert (f.kw == KW_object || f.kw == KW_arch);
479
480 if (f.kw == KW_object)
481 f.get (name); // preset name from object name
482
483 f.next ();
484
485 object *op_inv = inv;
486
487 for (;;)
488 {
489 switch (f.kw)
490 {
491 case KW_uuid:
492 if (const char *s = f.get_str ())
493 {
494 unsigned int version;
495 unsigned long long seq;
496
497 if (2 == sscanf (s, "<%d.%llx>", &version, &seq) && version == 1)
498 {
499 uuid.seq = seq;
500 break;
501 }
502 }
503
504 uuid = gen_uuid ();
505 break;
506
507 case KW_oid:
508 f.get (this, f.get_sint32 ());
509 break;
510
511 case KW_name: f.get (name); break;
512 case KW_name_pl: f.get (name_pl); break;
513 case KW_title: f.get (title); break;
514 case KW_custom_name: f.get (custom_name); break;
515
516 case KW_attach: f.get_ornull (attach); break;
517 case KW_skill: f.get_ornull (skill); break;
518 case KW_race: f.get_ornull (race); break;
519 case KW_slaying: f.get_ornull (slaying); break;
520
521 case KW_arch:
522 {
523 object *tmp = object::read (f);
524 tmp->deactivate ();
525
526 {
527 // was: insert_ob_in_ob (tmp, op);
528 // but manually adding it can improve map loading times a lot
529 // also, appending instead of prepending keeps the
530 // save ordering the same between repeated load/saves.
531 CLEAR_FLAG (tmp, FLAG_OBJ_ORIGINAL);
532 CLEAR_FLAG (tmp, FLAG_REMOVED);
533
534 if (!op_inv)
535 {
536 inv = tmp;
537 tmp->above = 0;
538 }
539 else
540 {
541 while (op_inv->below)
542 op_inv = op_inv->below;
543
544 op_inv->below = tmp;
545 tmp->above = op_inv;
546 }
547
548 tmp->below = 0;
549 tmp->env = this;
550 op_inv = tmp;
551 }
552 }
553 continue;
554
555 case KW_other_arch:
556 other_arch = archetype::find (f.get_str ());
557 break;
558
559 case KW_animation:
560 {
561 CLEAR_FLAG (this, FLAG_ANIMATE);
562 animation_id = 0;
563
564 const char *str = f.get_str ();
565 if (str && (animation_id = find_animation (str)))
566 SET_FLAG (this, FLAG_ANIMATE);
567 }
568 break;
569
570 case KW_last_heal: f.get (last_heal); break;
571 case KW_last_sp: f.get (last_sp); break;
572 case KW_last_grace: f.get (last_grace); break;
573 case KW_last_eat: f.get (last_eat); break;
574 case KW_speed_left: f.get (speed_left); break;
575
576 case KW_speed:
577 f.get (speed);
578
579 //TODO: maybe do in check_object
580 // removed check for style maps
581 if (speed < 0)
582 speed_left = speed_left - rndm ();
583
584 break;
585
586 case KW_slow_move:
587 move_slow |= MOVE_WALK;
588 f.get (move_slow_penalty);
589 break;
590
591 case KW_face:
592 face = face_find (f.get_str ());
593 break;
594
595 case KW_x: f.get (x); break;
596 case KW_y: f.get (y); break;
597
598 case KW_Str: // uppercase alias
599 case KW_str: f.get (stats.Str); break;
600 case KW_Dex: // uppercase alias
601 case KW_dex: f.get (stats.Dex); break;
602 case KW_Con: // uppercase alias
603 case KW_con: f.get (stats.Con); break;
604 case KW_Wis: // uppercase alias
605 case KW_wis: f.get (stats.Wis); break;
606 case KW_Cha: // uppercase alias
607 case KW_cha: f.get (stats.Cha); break;
608 case KW_Int: // uppercase alias
609 case KW_int: f.get (stats.Int); break;
610 case KW_Pow: // uppercase alias
611 case KW_pow: f.get (stats.Pow); break;
612
613 case KW_hp: f.get (stats.hp); break;
614 case KW_maxhp: f.get (stats.maxhp); break;
615 case KW_sp: f.get (stats.sp); break;
616 case KW_maxsp: f.get (stats.maxsp); break;
617 case KW_grace: f.get (stats.grace); break;
618 case KW_maxgrace: f.get (stats.maxgrace); break;
619
620 case KW_exp: f.get (stats.exp); break;
621 case KW_perm_exp: f.get (perm_exp); break;
622 case KW_food: f.get (stats.food); break;
623 case KW_dam: f.get (stats.dam); break;
624 case KW_wc: f.get (stats.wc); break;
625 case KW_ac: f.get (stats.ac); break;
626 case KW_nrof: f.get (nrof); break;
627 case KW_level: f.get (level); break;
628 case KW_direction: f.get (direction); break;
629 case KW_type: f.get (type); break;
630 case KW_subtype: f.get (subtype); break;
631 case KW_value: f.get (value); break;
632 case KW_weight: f.get (weight); break;
633 case KW_carrying: f.get (carrying); break;
634 case KW_attacktype: f.get (attacktype); break;
635 case KW_path_attuned: f.get (path_attuned); break;
636 case KW_path_repelled: f.get (path_repelled); break;
637 case KW_path_denied: f.get (path_denied); break;
638 case KW_invisible: f.get (invisible); break;
639 case KW_magic: f.get (magic); break;
640 case KW_state: f.get (state); break;
641 case KW_move_slow_penalty: f.get (move_slow_penalty); break;
642 case KW_material: f.get (materials); break; //TODO: nuke
643 case KW_materialname: f.get (materialname); break;
644
645 /* These are the new values */
646 case KW_move_block: set_move (move_block, f.get_str ()); break;
647 case KW_move_allow: set_move (move_allow, f.get_str ()); break;
648 case KW_move_type: set_move (move_type, f.get_str ()); break;
649 case KW_move_on: set_move (move_on, f.get_str ()); break;
650 case KW_move_off: set_move (move_off, f.get_str ()); break;
651 case KW_move_slow: set_move (move_slow, f.get_str ()); break;
652
653 /* These are all legacy - any new objects should use the move_ .. values */
654 case KW_no_pass:
655 {
656 if (f.get_sint32 ())
657 move_block = MOVE_ALL;
658 else
659 move_block = 0;
660 }
661
662 break;
663
664 /* These are all legacy - any new objects should use the move_ .. values */
665 case KW_walk_on:
666 {
667 if (f.get_sint32 ())
668 move_on |= MOVE_WALK;
669 else
670 move_on &= ~MOVE_WALK;
671 }
672
673 break;
674
675 /* These are all legacy - any new objects should use the move_ .. values */
676 case KW_walk_off:
677 {
678 if (f.get_sint32 ())
679 move_off |= MOVE_WALK;
680 else
681 move_off &= ~MOVE_WALK;
682 }
683 break;
684
685 /* These are all legacy - any new objects should use the move_ .. values */
686 case KW_fly_on:
687 {
688 if (f.get_sint32 ())
689 move_on |= MOVE_FLY_LOW;
690 else
691 move_on &= ~MOVE_FLY_LOW;
692 }
693 break;
694
695 /* These are all legacy - any new objects should use the move_ .. values */
696 case KW_fly_off:
697 {
698 if (f.get_sint32 ())
699 move_off |= MOVE_FLY_LOW;
700 else
701 move_off &= ~MOVE_FLY_LOW;
702 }
703 break;
704
705 //TODO: remove these after converting archetypes
706 case KW_can_use_wand:
707 GET_FLAG (this, FLAG_USE_RANGE);
708 break;
709
710 /* These are all legacy - any new objects should use the move_ .. values */
711 case KW_flying:
712 {
713 if (f.get_sint32 ())
714 move_type |= MOVE_FLY_LOW;
715 else
716 move_type &= ~MOVE_FLY_LOW;
717 }
718 break;
719
720
721 case KW_identified:
722 GET_FLAG (this, FLAG_IDENTIFIED);
723 //TODO: move to check_object or so
724 if (QUERY_FLAG (this, FLAG_IDENTIFIED))
725 CLEAR_FLAG (this, FLAG_KNOWN_MAGICAL);
726
727 break;
728
729 case KW_wiz:
730 GET_FLAG (this, FLAG_WIZ);
731 //TODO: move to check_object
732 if (QUERY_FLAG (this, FLAG_WIZ))
733 {
734 SET_FLAG (this, FLAG_WAS_WIZ);
735 SET_FLAG (this, FLAG_WIZPASS);
736 SET_FLAG (this, FLAG_WIZCAST);
737 }
738 else
739 {
740 CLEAR_FLAG (this, FLAG_WIZPASS);
741 CLEAR_FLAG (this, FLAG_WIZCAST);
742 }
743 break;
744
745 case KW_friendly:
746 if (f.get_sint32 ())
747 if (type != PLAYER)
748 add_friendly_object (this);
749
750 break;
751
752 case KW_monster: GET_FLAG (this, FLAG_MONSTER); break;
753 case KW_neutral: GET_FLAG (this, FLAG_NEUTRAL); break;
754 case KW_no_attack: GET_FLAG (this, FLAG_NO_ATTACK); break;
755 case KW_no_damage: GET_FLAG (this, FLAG_NO_DAMAGE); break;
756 case KW_obj_original: GET_FLAG (this, FLAG_OBJ_ORIGINAL); break;
757 case KW_generator: GET_FLAG (this, FLAG_GENERATOR); break;
758 case KW_use_content_on_gen: GET_FLAG (this, FLAG_CONTENT_ON_GEN); break;
759 case KW_is_thrown: GET_FLAG (this, FLAG_IS_THROWN); break;
760 case KW_auto_apply: GET_FLAG (this, FLAG_AUTO_APPLY); break;
761 case KW_see_invisible: GET_FLAG (this, FLAG_SEE_INVISIBLE); break;
762 case KW_can_roll: GET_FLAG (this, FLAG_CAN_ROLL); break;
763 case KW_overlay_floor: GET_FLAG (this, FLAG_OVERLAY_FLOOR); break;
764 case KW_is_turnable: GET_FLAG (this, FLAG_IS_TURNABLE); break;
765 case KW_is_used_up: GET_FLAG (this, FLAG_IS_USED_UP); break;
766 case KW_alive: GET_FLAG (this, FLAG_ALIVE); break;
767 case KW_applied: GET_FLAG (this, FLAG_APPLIED); break;
768 case KW_unpaid: GET_FLAG (this, FLAG_UNPAID); break;
769 case KW_is_animated: GET_FLAG (this, FLAG_ANIMATE); break;
770 case KW_no_pick: GET_FLAG (this, FLAG_NO_PICK); break;
771 case KW_reflecting: GET_FLAG (this, FLAG_REFLECTING); break;
772 case KW_changing: GET_FLAG (this, FLAG_CHANGING); break;
773 case KW_splitting: GET_FLAG (this, FLAG_SPLITTING); break;
774 case KW_hitback: GET_FLAG (this, FLAG_HITBACK); break;
775 case KW_startequip: GET_FLAG (this, FLAG_STARTEQUIP); break;
776 case KW_blocksview: GET_FLAG (this, FLAG_BLOCKSVIEW); break;
777 case KW_undead: GET_FLAG (this, FLAG_UNDEAD); break;
778 case KW_scared: GET_FLAG (this, FLAG_SCARED); break;
779 case KW_unaggressive: GET_FLAG (this, FLAG_UNAGGRESSIVE); break;
780 case KW_reflect_missile: GET_FLAG (this, FLAG_REFL_MISSILE); break;
781 case KW_reflect_spell: GET_FLAG (this, FLAG_REFL_SPELL); break;
782 case KW_no_magic: GET_FLAG (this, FLAG_NO_MAGIC); break;
783 case KW_no_drop: GET_FLAG (this, FLAG_NO_DROP); break;
784 case KW_random_movement: GET_FLAG (this, FLAG_RANDOM_MOVE); break;
785 case KW_was_wiz: GET_FLAG (this, FLAG_WAS_WIZ); break;
786 case KW_no_fix_player: GET_FLAG (this, FLAG_NO_FIX_PLAYER); break;
787 case KW_is_lightable: GET_FLAG (this, FLAG_IS_LIGHTABLE); break;
788 case KW_tear_down: GET_FLAG (this, FLAG_TEAR_DOWN); break;
789 case KW_can_use_shield: GET_FLAG (this, FLAG_USE_SHIELD); break;
790 case KW_can_cast_spell: GET_FLAG (this, FLAG_CAST_SPELL); break;
791 case KW_can_use_scroll: GET_FLAG (this, FLAG_USE_SCROLL); break;
792 case KW_can_use_range: GET_FLAG (this, FLAG_USE_RANGE); break;
793 case KW_can_use_bow: GET_FLAG (this, FLAG_USE_BOW); break;
794 case KW_can_use_armour: GET_FLAG (this, FLAG_USE_ARMOUR); break;
795 case KW_can_use_weapon: GET_FLAG (this, FLAG_USE_WEAPON); break;
796 case KW_can_use_ring: GET_FLAG (this, FLAG_USE_RING); break;
797 case KW_has_ready_bow: GET_FLAG (this, FLAG_READY_BOW); break;
798 case KW_has_ready_range: GET_FLAG (this, FLAG_READY_RANGE); break;
799 case KW_xrays: GET_FLAG (this, FLAG_XRAYS); break;
800 case KW_is_floor: GET_FLAG (this, FLAG_IS_FLOOR); break;
801 case KW_lifesave: GET_FLAG (this, FLAG_LIFESAVE); break;
802 case KW_no_strength: GET_FLAG (this, FLAG_NO_STRENGTH); break;
803 case KW_sleep: GET_FLAG (this, FLAG_SLEEP); break;
804 case KW_stand_still: GET_FLAG (this, FLAG_STAND_STILL); break;
805 case KW_random_move: GET_FLAG (this, FLAG_RANDOM_MOVE); break;
806 case KW_only_attack: GET_FLAG (this, FLAG_ONLY_ATTACK); break;
807 case KW_activate_on_push: GET_FLAG (this, FLAG_ACTIVATE_ON_PUSH); break;
808 case KW_activate_on_release: GET_FLAG (this, FLAG_ACTIVATE_ON_RELEASE); break;
809 case KW_confused: GET_FLAG (this, FLAG_CONFUSED); break;
810 case KW_stealth: GET_FLAG (this, FLAG_STEALTH); break;
811 case KW_cursed: GET_FLAG (this, FLAG_CURSED); break;
812 case KW_damned: GET_FLAG (this, FLAG_DAMNED); break;
813 case KW_see_anywhere: GET_FLAG (this, FLAG_SEE_ANYWHERE); break;
814 case KW_known_magical: GET_FLAG (this, FLAG_KNOWN_MAGICAL); break;
815 case KW_known_cursed: GET_FLAG (this, FLAG_KNOWN_CURSED); break;
816 case KW_can_use_skill: GET_FLAG (this, FLAG_CAN_USE_SKILL); break;
817 case KW_been_applied: GET_FLAG (this, FLAG_BEEN_APPLIED); break;
818 case KW_has_ready_scroll: GET_FLAG (this, FLAG_READY_SCROLL); break;
819 case KW_can_use_rod: GET_FLAG (this, FLAG_USE_ROD); break;
820 case KW_can_use_horn: GET_FLAG (this, FLAG_USE_HORN); break;
821 case KW_unique: GET_FLAG (this, FLAG_UNIQUE); break;
822 case KW_make_invisible: GET_FLAG (this, FLAG_MAKE_INVIS); break;
823 case KW_inv_locked: GET_FLAG (this, FLAG_INV_LOCKED); break;
824 case KW_is_wooded: GET_FLAG (this, FLAG_IS_WOODED); break;
825 case KW_is_hilly: GET_FLAG (this, FLAG_IS_HILLY); break;
826 case KW_is_water: GET_FLAG (this, FLAG_IS_WATER); break;
827 case KW_has_ready_skill: GET_FLAG (this, FLAG_READY_SKILL); break;
828 case KW_has_ready_weapon: GET_FLAG (this, FLAG_READY_WEAPON); break;
829 case KW_no_skill_ident: GET_FLAG (this, FLAG_NO_SKILL_IDENT); break;
830 case KW_is_blind: GET_FLAG (this, FLAG_BLIND); break;
831 case KW_can_see_in_dark: GET_FLAG (this, FLAG_SEE_IN_DARK); break;
832 case KW_is_cauldron: GET_FLAG (this, FLAG_IS_CAULDRON); break;
833 case KW_no_steal: GET_FLAG (this, FLAG_NO_STEAL); break;
834 case KW_one_hit: GET_FLAG (this, FLAG_ONE_HIT); break;
835 case KW_berserk: GET_FLAG (this, FLAG_BERSERK); break;
836 case KW_is_buildable: GET_FLAG (this, FLAG_IS_BUILDABLE); break;
837 case KW_destroy_on_death: GET_FLAG (this, FLAG_DESTROY_ON_DEATH); break;
838
839 case KW_armour: f.get (resist[ATNR_PHYSICAL]); break;
840 case KW_resist_physical: f.get (resist[ATNR_PHYSICAL]); break;
841 case KW_resist_magic: f.get (resist[ATNR_MAGIC]); break;
842 case KW_resist_fire: f.get (resist[ATNR_FIRE]); break;
843 case KW_resist_electricity: f.get (resist[ATNR_ELECTRICITY]); break;
844 case KW_resist_cold: f.get (resist[ATNR_COLD]); break;
845 case KW_resist_confusion: f.get (resist[ATNR_CONFUSION]); break;
846 case KW_resist_acid: f.get (resist[ATNR_ACID]); break;
847 case KW_resist_drain: f.get (resist[ATNR_DRAIN]); break;
848 case KW_resist_weaponmagic: f.get (resist[ATNR_WEAPONMAGIC]); break;
849 case KW_resist_ghosthit: f.get (resist[ATNR_GHOSTHIT]); break;
850 case KW_resist_poison: f.get (resist[ATNR_POISON]); break;
851 case KW_resist_slow: f.get (resist[ATNR_SLOW]); break;
852 case KW_resist_paralyze: f.get (resist[ATNR_PARALYZE]); break;
853 case KW_resist_turn_undead: f.get (resist[ATNR_TURN_UNDEAD]); break;
854 case KW_resist_fear: f.get (resist[ATNR_FEAR]); break;
855 case KW_resist_cancellation: f.get (resist[ATNR_CANCELLATION]); break;
856 case KW_resist_deplete: f.get (resist[ATNR_DEPLETE]); break;
857 case KW_resist_death: f.get (resist[ATNR_DEATH]); break;
858 case KW_resist_chaos: f.get (resist[ATNR_CHAOS]); break;
859 case KW_resist_counterspell: f.get (resist[ATNR_COUNTERSPELL]); break;
860 case KW_resist_godpower: f.get (resist[ATNR_GODPOWER]); break;
861 case KW_resist_holyword: f.get (resist[ATNR_HOLYWORD]); break;
862 case KW_resist_blind: f.get (resist[ATNR_BLIND]); break;
863 case KW_resist_internal: f.get (resist[ATNR_INTERNAL]); break;
864 case KW_resist_life_stealing: f.get (resist[ATNR_LIFE_STEALING]); break;
865 case KW_resist_disease: f.get (resist[ATNR_DISEASE]); break;
866
867 case KW_luck: f.get (stats.luck); break;
868 case KW_run_away: f.get (run_away); break;
869 case KW_pick_up: f.get (pick_up); break;
870 case KW_item_power: f.get (item_power); break;
871 case KW_gen_sp_armour: f.get (gen_sp_armour); break;
872 case KW_anim_speed: f.get (anim_speed); break;
873 case KW_container: f.get (weight_limit); break;
874 case KW_will_apply: f.get (will_apply); break;
875 case KW_attack_movement: f.get (attack_movement); break;
876 case KW_move_state: f.get (move_status); break;
877 case KW_expmul: f.get (expmul); break;
878 case KW_glow_radius: f.get (glow_radius); break;
879 case KW_weapontype: f.get (weapontype); break;
880 case KW_tooltype: f.get (tooltype); break;
881 case KW_casting_time: f.get (casting_time); break;
882 case KW_elevation: f.get (elevation); break;
883 case KW_smoothlevel: f.get (smoothlevel); smoothlevel = clamp (smoothlevel, 0, 255); break;
884 case KW_client_type: f.get (client_type); break;
885 case KW_duration: f.get (duration); break;
886 case KW_range: f.get (range); break;
887 case KW_range_modifier: f.get (range_modifier); break;
888 case KW_dam_modifier: f.get (dam_modifier); break;
889 case KW_duration_modifier: f.get (duration_modifier); break;
890
891 //TODO: mechanism to ensure that KW_xxx is consecutive needed from include/preprocess
892 //TODO: parse from other include files
893 case KW_body_range: f.get (body_info[0]); break;
894 case KW_body_arm: f.get (body_info[1]); break;
895 case KW_body_torso: f.get (body_info[2]); break;
896 case KW_body_head: f.get (body_info[3]); break;
897 case KW_body_neck: f.get (body_info[4]); break;
898 case KW_body_skill: f.get (body_info[5]); break;
899 case KW_body_finger: f.get (body_info[6]); break;
900 case KW_body_shoulder: f.get (body_info[7]); break;
901 case KW_body_foot: f.get (body_info[8]); break;
902 case KW_body_hand: f.get (body_info[9]); break;
903 case KW_body_wrist: f.get (body_info[10]); break;
904 case KW_body_waist: f.get (body_info[11]); break;
905 case KW_can_apply:
906 break;
907
908 case KW_connected:
909 add_button_link (this, map, f.get_sint32 ());
910 break;
911
912 case KW_randomitems:
913 randomitems = find_treasurelist (f.get_str ());
914 //if (!randomitems)
915 // LOG (llevError, "%s uses unknown randomitems '%s'.\n", debug_desc (), f.get_str ());
916 break;
917
918 case KW_msg:
919 f.get_ml (KW_endmsg, msg);
920 //TODO: allow longer messages
921 if (strlen (msg) >= HUGE_BUF)
922 {
923 LOG (llevDebug, "\tError message length >= %d: %d\n>%.80s<\n", HUGE_BUF, strlen (msg), &msg);
924 msg = "ERROR, please report: string too long, winged.\n";
925 }
926 break;
927
928 case KW_lore:
929 f.get_ml (KW_endlore, lore);
930 //TODO: allow longer messages
931 /* Just print a warning so we can be reasonably safe
932 * about not overflowing the buffer.
933 */
934 if (strlen (lore) > (HUGE_BUF / 2))
935 LOG (llevDebug, "\tWarning lore length > %d (max allowed=%d): %d\n>%.80s<\n",
936 HUGE_BUF / 2, HUGE_BUF, strlen (lore), &lore);
937 break;
938
939 case KW_editable:
940 case KW_editor_folder:
941 break;
942
943 case KW_end:
944 check_loaded_object (this);
945
946 if (!arch_init)
947 instantiate ();
948
949 f.next ();
950 return true;
951
952 case KW_ERROR:
953 set_ob_key_value (this, f.kw_str, f.value, true);
954 //fprintf (stderr, "addkv(%s,%s)\n", f.kw_str, f.value);//D
955 break;
956
957 default:
958 if (!f.parse_error ("object", name))
959 return false;
960 break;
961 }
962
963 f.next ();
964 }
965 }
966
967 object *
968 object::read (object_thawer &f, maptile *map)
969 {
970 assert (f.kw == KW_arch);
971
972 archetype *arch = archetype::find (f.get_str ());
973
974 if (!arch)
975 {
976 LOG (llevError, "object refering to nonexistant archetype '%s'.\n", f.get_str ());
977 arch = archetype::find ("earthwall");
978 }
979
980 assert (arch); //D maybe use exception handling of sorts?
981
982 object *op = object::create ();
983
984 op->map = map;
985 op->arch = arch;
986 arch->clone.copy_to (op);
987 // copy_to activates, this should be fixed properly
988 op->deactivate ();
989
990 if (!op->parse_kv (f))
991 {
992 delete op;
993 return 0;
994 }
995
996 return op;
997 }
998
999 /* This takes a buffer, scans it for variables, and sets those variables
1000 * as appropriate in op.
1001 *
1002 * This function appears to be used in only 2 places - in crossedit to
1003 * override values and in c_wiz to mutate values.
1004 */
1005 int
1006 set_variable (object *op, char *buf)
1007 {
1008 object_thawer f (buf, (AV *)0);
1009
1010 f.kw = KW_arch; // special hack so that parse_kv skips
1011 return op->parse_kv (f);
1012 }
1013
1014 /* This returns a string of the integer movement type */
1015 #if 0
1016 // unused function
1017 static char *
1018 get_string_move_type (MoveType mt)
1019 {
1020 static char retbuf[MAX_BUF], retbuf_all[MAX_BUF];
1021 int i, all_count = 0, count;
1022
1023 strcpy (retbuf, "");
1024 strcpy (retbuf_all, " all");
1025
1026 /* Quick check, and probably fairly common */
1027 if (mt == MOVE_ALL)
1028 return retbuf_all + 1;
1029 if (mt == 0)
1030 {
1031 strcpy (retbuf, "0");
1032 return retbuf;
1033 }
1034
1035 /* We basically slide the bits down. Why look at MOVE_ALL?
1036 * because we may want to return a string like 'all -swim',
1037 * and if we just looked at mt, we couldn't get that.
1038 */
1039 for (i = MOVE_ALL, count = 0; i != 0; i >>= 1, count++)
1040 {
1041 if (mt & (1 << count))
1042 {
1043 strcat (retbuf, " ");
1044 strcat (retbuf, move_name[count]);
1045 }
1046 else
1047 {
1048 strcat (retbuf_all, " -");
1049 strcat (retbuf_all, move_name[count]);
1050 all_count++;
1051 }
1052 }
1053 /* Basically, if there is a single negation, return it, eg
1054 * 'all -swim'. But more than that, just return the
1055 * enumerated values. It doesn't make sense to return
1056 * 'all -walk -fly_low' - it is shorter to return 'fly_high swim'
1057 */
1058 if (all_count <= 1)
1059 return retbuf_all + 1;
1060 else
1061 return retbuf + 1;
1062 }
1063 #endif
1064
1065 // compare *op against *tmp and output differences
1066 static void
1067 write_diff (object_freezer &f, object *op, object *tmp)
1068 {
1069 static const keyword resist_save[NROFATTACKS] = {
1070 # define def(uc, lc, name, plus, change) KW_resist_ ## lc,
1071 # include "attackinc.h"
1072 # undef def
1073 };
1074
1075 /* This is a list of keywords that correspond to the FLAG_.. values.
1076 * This is a simple 1:1 mapping - if FLAG_FRIENDLY is 15, then
1077 * the 15'th element of this array should match that name.
1078 * If an entry is NULL, that is a flag not to loaded/saved.
1079 */
1080 static const keyword flag_names [NUM_FLAGS] = {
1081 KW_alive,
1082 KW_wiz,
1083 KW_NULL,
1084 KW_NULL,
1085 KW_was_wiz,
1086 KW_applied,
1087 KW_unpaid,
1088 KW_can_use_shield,
1089 KW_no_pick,
1090 KW_NULL, // walk_on
1091 KW_NULL, // no_pass
1092 /* 10 */
1093 KW_is_animated,
1094 KW_NULL, // slow_move
1095 KW_NULL, // flying
1096 KW_monster,
1097 KW_friendly,
1098 KW_generator,
1099 KW_is_thrown,
1100 KW_auto_apply,
1101 KW_NULL, // was KW_treasure
1102 KW_player_sold,
1103 /* 20 */
1104 KW_see_invisible,
1105 KW_can_roll,
1106 KW_overlay_floor,
1107 KW_is_turnable,
1108 KW_NULL, // walk_off
1109 KW_NULL, // fly_on
1110 KW_NULL, // fly_off
1111 KW_is_used_up,
1112 KW_identified,
1113 KW_reflecting,
1114 /* 30 */
1115 KW_changing,
1116 KW_splitting,
1117 KW_hitback,
1118 KW_startequip,
1119 KW_blocksview,
1120 KW_undead,
1121 KW_scared,
1122 KW_unaggressive,
1123 KW_reflect_missile,
1124 KW_reflect_spell,
1125 /* 40 */
1126 KW_no_magic,
1127 KW_no_fix_player,
1128 KW_is_lightable,
1129 KW_tear_down,
1130 KW_run_away,
1131 KW_NULL, // pass_thru
1132 KW_NULL, // an_pass_thru
1133 KW_pick_up,
1134 KW_unique,
1135 KW_no_drop,
1136 /* 50 */
1137 KW_NULL, // wizcast
1138 KW_can_cast_spell,
1139 KW_can_use_scroll,
1140 KW_can_use_range,
1141 KW_can_use_bow,
1142 KW_can_use_armour,
1143 KW_can_use_weapon,
1144 KW_can_use_ring,
1145 KW_has_ready_range,
1146 KW_has_ready_bow,
1147 /* 60 */
1148 KW_xrays,
1149 KW_NULL,
1150 KW_is_floor,
1151 KW_lifesave,
1152 KW_no_strength,
1153 KW_sleep,
1154 KW_stand_still,
1155 KW_random_move,
1156 KW_only_attack,
1157 KW_confused,
1158 /* 70 */
1159 KW_stealth,
1160 KW_NULL,
1161 KW_NULL,
1162 KW_cursed,
1163 KW_damned,
1164 KW_see_anywhere,
1165 KW_known_magical,
1166 KW_known_cursed,
1167 KW_can_use_skill,
1168 KW_been_applied,
1169 /* 80 */
1170 KW_has_ready_scroll,
1171 KW_can_use_rod,
1172 KW_NULL,
1173 KW_can_use_horn,
1174 KW_make_invisible,
1175 KW_inv_locked,
1176 KW_is_wooded,
1177 KW_is_hilly,
1178 KW_has_ready_skill,
1179 KW_has_ready_weapon,
1180 /* 90 */
1181 KW_no_skill_ident,
1182 KW_is_blind,
1183 KW_can_see_in_dark,
1184 KW_is_cauldron,
1185 KW_NULL,
1186 KW_no_steal,
1187 KW_one_hit,
1188 KW_NULL,
1189 KW_berserk,
1190 KW_neutral,
1191 /* 100 */
1192 KW_no_attack,
1193 KW_no_damage,
1194 KW_obj_original,
1195 KW_NULL,
1196 KW_activate_on_push,
1197 KW_activate_on_release,
1198 KW_is_water,
1199 KW_use_content_on_gen,
1200 KW_NULL,
1201 KW_is_buildable,
1202 /* 110 */
1203 KW_destroy_on_death,
1204 KW_NULL,
1205 };
1206
1207 int i;
1208
1209 /* This saves the key/value lists. We do it first so that any
1210 * keys that match field names will be overwritten by the loader.
1211 */
1212 for (key_value *my_field = op->key_values; my_field; my_field = my_field->next)
1213 {
1214 /* Find the field in the opposing member. */
1215 key_value *arch_field = get_ob_key_link (tmp, my_field->key);
1216
1217 /* If there's no partnering field, or it's got a different value, save our field. */
1218 if (!arch_field || my_field->value != arch_field->value)
1219 f.put (my_field->key, my_field->value);
1220 }
1221
1222 /* We don't need to worry about the arch's extra fields - they
1223 * will get taken care of the copy_to method.
1224 */
1225
1226 {
1227 char uids[64];
1228 snprintf (uids, sizeof (uids), "<1.%llx>", (unsigned long long)op->uuid.seq);
1229 f.put (KW_uuid, (const char *)uids);
1230 }
1231
1232 #define CMP_OUT(v) if (op->v != tmp->v) f.put (KW_ ## v, op->v)
1233 #define CMP_OUT2(k,v) if (op->v != tmp->v) f.put (KW_ ## k, op->v)
1234
1235 CMP_OUT (name);
1236 CMP_OUT (name_pl);
1237 CMP_OUT (custom_name);
1238 CMP_OUT (title);
1239 CMP_OUT (race);
1240 CMP_OUT (slaying);
1241
1242 if (op->msg != tmp->msg)
1243 f.put (KW_msg, KW_endmsg, op->msg);
1244 if (op->lore != tmp->lore)
1245 f.put (KW_lore, KW_endlore, op->lore);
1246
1247 CMP_OUT (other_arch);
1248 CMP_OUT (face);
1249
1250 if (op->animation_id != tmp->animation_id)
1251 if (op->animation_id)
1252 {
1253 f.put (KW_animation, animations[GET_ANIM_ID (op)].name);
1254
1255 if (!QUERY_FLAG (op, FLAG_ANIMATE))
1256 f.put (KW_is_animated, (sint32) 0);
1257 }
1258 else
1259 f.put (KW_animation, (const char *) 0);
1260
1261 CMP_OUT2 (str, stats.Str);
1262 CMP_OUT2 (dex, stats.Dex);
1263 CMP_OUT2 (con, stats.Con);
1264 CMP_OUT2 (wis, stats.Wis);
1265 CMP_OUT2 (pow, stats.Pow);
1266 CMP_OUT2 (cha, stats.Cha);
1267 CMP_OUT2 (int, stats.Int);
1268
1269 CMP_OUT2 (hp, stats.hp);
1270 CMP_OUT2 (maxhp, stats.maxhp);
1271 CMP_OUT2 (sp, stats.sp);
1272 CMP_OUT2 (maxsp, stats.maxsp);
1273 CMP_OUT2 (grace, stats.grace);
1274 CMP_OUT2 (maxgrace, stats.maxgrace);
1275 CMP_OUT2 (exp, stats.exp);
1276
1277 CMP_OUT (perm_exp);
1278 CMP_OUT (expmul);
1279
1280 CMP_OUT2 (food, stats.food);
1281 CMP_OUT2 (dam, stats.dam);
1282 CMP_OUT2 (luck, stats.luck);
1283 CMP_OUT2 (wc, stats.wc);
1284 CMP_OUT2 (ac, stats.ac);
1285
1286 CMP_OUT (x);
1287 CMP_OUT (y);
1288 CMP_OUT (speed);
1289 CMP_OUT (speed_left);
1290 CMP_OUT2 (move_state, move_status);
1291 CMP_OUT (attack_movement);
1292 CMP_OUT (nrof);
1293 CMP_OUT (level);
1294 CMP_OUT (direction);
1295 CMP_OUT (type);
1296 CMP_OUT (subtype);
1297 CMP_OUT (attacktype);
1298
1299 for (i = 0; i < NROFATTACKS; i++)
1300 if (op->resist[i] != tmp->resist[i])
1301 f.put (resist_save[i], op->resist[i]);
1302
1303 CMP_OUT (path_attuned);
1304 CMP_OUT (path_repelled);
1305 CMP_OUT (path_denied);
1306 CMP_OUT2 (material, materials);//TODO: nuke
1307 CMP_OUT (materialname);
1308 CMP_OUT (value);
1309 CMP_OUT (carrying);
1310 CMP_OUT (weight);
1311 CMP_OUT (invisible);
1312 CMP_OUT (state);
1313 CMP_OUT (magic);
1314 CMP_OUT (last_heal);
1315 CMP_OUT (last_sp);
1316 CMP_OUT (last_grace);
1317 CMP_OUT (last_eat);
1318 CMP_OUT (glow_radius);
1319
1320 if (QUERY_FLAG (op, FLAG_IS_LINKED) && (i = get_button_value (op)))
1321 f.put (KW_connected, i);
1322
1323 CMP_OUT (randomitems);
1324 CMP_OUT2 (container, weight_limit);
1325
1326 CMP_OUT (run_away);
1327 CMP_OUT (pick_up);
1328 CMP_OUT (will_apply);
1329 CMP_OUT (smoothlevel);
1330 CMP_OUT (weapontype);
1331 CMP_OUT (tooltype);
1332 CMP_OUT (elevation);
1333 CMP_OUT (client_type);
1334 CMP_OUT (item_power);
1335 CMP_OUT (duration);
1336 CMP_OUT (range);
1337 CMP_OUT (range_modifier);
1338 CMP_OUT (duration_modifier);
1339 CMP_OUT (dam_modifier);
1340 CMP_OUT (gen_sp_armour);
1341
1342 CMP_OUT (move_type);
1343 CMP_OUT (move_block);
1344 CMP_OUT (move_allow);
1345 CMP_OUT (move_on);
1346 CMP_OUT (move_off);
1347 CMP_OUT (move_slow);
1348 CMP_OUT (move_slow_penalty);
1349
1350 if (op->flag != tmp->flag)
1351 for (i = 0; i <= NUM_FLAGS; i++)
1352 if (flag_names [i] && op->flag [i] != tmp->flag [i])
1353 f.put (flag_names [i], op->flag [i] ? "1" : "0");
1354
1355 /* Save body locations */
1356 for (i = 0; i < NUM_BODY_LOCATIONS; i++)
1357 if (op->body_info[i] != tmp->body_info[i])
1358 f.put (body_locations[i].save_name, op->body_info[i]);
1359 }
1360
1361 /*
1362 * Dumps all variables in an object to a file.
1363 * If bit 0 of flag is set, unpaid objects will be saved. As of now,
1364 * the only place this is not set is when saving the player.
1365 */
1366 bool
1367 object::write (object_freezer &f)
1368 {
1369 /* Even if the object does have an owner, it would seem that we should
1370 * still save it.
1371 */
1372 if (owner)
1373 return true;
1374
1375 archetype *at = arch ? (archetype *)arch : empty_archetype;
1376
1377 f.put (KW_arch, at->name);
1378 write_diff (f, this, &at->clone);
1379
1380 for (object *tmp = inv; tmp; tmp = tmp->below)
1381 tmp->write (f);
1382
1383 f.put (this);
1384 f.put (KW_end);
1385
1386 return true;
1387 }
1388
1389 /////////////////////////////////////////////////////////////////////////////
1390
1391 bool load_resource_file (const char *filename)
1392 {
1393 object_thawer f (filename);
1394
1395 f.next ();
1396
1397 for (;;)
1398 {
1399 switch (f.kw)
1400 {
1401 case KW_region:
1402 if (!region::read (f))
1403 return false;
1404 break;
1405
1406 case KW_EOF:
1407 return true;
1408
1409 default:
1410 if (!f.parse_error ("resource file"))
1411 return false;
1412 }
1413
1414 f.next ();
1415 }
1416 }
1417