ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/loader.C
Revision: 1.90
Committed: Sun Jul 1 05:00:17 2007 UTC (16 years, 11 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.89: +11 -12 lines
Log Message:
- upgrade crossfire trt to the GPL version 3 (hopefully correctly).
- add a single file covered by the GNU Affero General Public License
  (which is not yet released, so I used the current draft, which is
  legally a bit wavy, but its likely better than nothing as it expresses
  direct intent by the authors, and we can upgrade as soon as it has been
  released).
  * this should ensure availability of source code for the server at least
    and hopefully also archetypes and maps even when modified versions
    are not being distributed, in accordance of section 13 of the agplv3.

File Contents

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