ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/loader.l
Revision: 1.19
Committed: Sun Sep 3 00:18:40 2006 UTC (17 years, 8 months ago) by root
Branch: MAIN
Changes since 1.18: +23 -80 lines
Log Message:
THIS CODE WILL NOT COMPILE
use the STABLE tag instead.

- major changes in object lifetime and memory management
- replaced manual refcounting by shstr class
- removed quest system
- many optimisations
- major changes

File Contents

# User Rev Content
1 root 1.1 %{
2     /*
3     * static char *rcsid_object_c =
4 root 1.2 * "$Id$";
5 root 1.1 */
6    
7     /*
8     CrossFire, A Multiplayer game for X-windows
9    
10     Copyright (C) 2002 Mark Wedel & Crossfire Development Team
11     Copyright (C) 1992 Frank Tore Johansen
12    
13     This program is free software; you can redistribute it and/or modify
14     it under the terms of the GNU General Public License as published by
15     the Free Software Foundation; either version 2 of the License, or
16     (at your option) any later version.
17    
18     This program is distributed in the hope that it will be useful,
19     but WITHOUT ANY WARRANTY; without even the implied warranty of
20     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21     GNU General Public License for more details.
22    
23     You should have received a copy of the GNU General Public License
24     along with this program; if not, write to the Free Software
25     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26    
27     The authors can be reached via e-mail at crossfire-devel@real-time.com
28     */
29    
30     /* Eneq(@csd.uu.se): Added weight-modifiers in environment of objects.
31     sub/add_weight will transcend the environment updating the carrying
32     variable. */
33    
34    
35     #include <global.h>
36     #include <loader.h>
37     #include <newserver.h>
38     #include <sproto.h>
39    
40 root 1.10 #define YY_DECL int lex_load(object *op, object_thawer &thawer, int map_flags)
41 root 1.1
42     static char *yval();
43    
44     static int lex_error;
45 root 1.8 static char msgbuf[65536];
46     static char lorebuf[65536];
47 root 1.1
48 root 1.2 /* Maps the MOVE_* values to names */
49     static const char *const move_name[] = {"walk", "fly_low", "fly_high", "swim", "boat",
50     NULL};
51    
52 root 1.1 /* This table is only necessary to convert objects that existed before the
53     * spell object conversion to the new object. It was not practical
54     * to go through every mapping looking for every potion, rod, wand, etc
55     * that had a sp set and update to the new value. So this maps the
56     * old spell numbers to the name of the new archs.
57     * If you are adding a new spell, you should not modify this - you
58     * new spell won't have been used, and thus won't have any legacy object.
59     * NULL entries in this table are valid - to denote objects that should
60     * not be updated for whatever reason.
61     */
62 elmex 1.7 const char *spell_mapping[] = {
63 root 1.18 "spell_magic_bullet", /* 0 */
64     "spell_small_fireball", /* 1 */
65     "spell_medium_fireball", /* 2 */
66     "spell_large_fireball", /* 3 */
67     "spell_burning_hands", /* 4 */
68     "spell_sm_lightning", /* 5 */
69     "spell_large_lightning", /* 6 */
70     "spell_magic_missile", /* 7 */
71     "spell_create_bomb", /* 8 */
72     "spell_summon_golem", /* 9 */
73     "spell_summon_fire_elemental", /* 10 */
74     "spell_summon_earth_elemental", /* 11 */
75     "spell_summon_water_elemental", /* 12 */
76     "spell_summon_air_elemental", /* 13 */
77     "spell_dimension_door", /* 14 */
78     "spell_create_earth_wall", /* 15 */
79     "spell_paralyze", /* 16 */
80     "spell_icestorm", /* 17 */
81     "spell_magic_mapping", /* 18 */
82     "spell_turn_undead", /* 19 */
83     "spell_fear", /* 20 */
84     "spell_poison_cloud", /* 21 */
85     "spell_wonder", /* 22 */
86     "spell_destruction", /* 23 */
87     "spell_perceive_self", /* 24 */
88     "spell_word_of_recall", /* 25 */
89     "spell_invisible", /* 26 */
90     "spell_invisible_to_undead", /* 27 */
91     "spell_probe", /* 28 */
92     "spell_lg_magic_bullet", /* 29 */
93     "spell_improved_invisibility", /* 30 */
94     "spell_holy_word", /* 31 */
95     "spell_minor_healing", /* 32 */
96     "spell_medium_healing", /* 33 */
97     "spell_major_healing", /* 34 */
98     "spell_heal", /* 35 */
99     "spell_create_food", /* 36 */
100     "spell_earth_to_dust", /* 37 */
101     "spell_armour", /* 38 */
102     "spell_strength", /* 39 */
103     "spell_dexterity", /* 40 */
104     "spell_constitution", /* 41 */
105     "spell_charisma", /* 42 */
106     "spell_create_fire_wall", /* 43 */
107     "spell_create_frost_wall", /* 44 */
108     "spell_protection_from_cold", /* 45 */
109     "spell_protection_from_electricity", /* 46 */
110     "spell_protection_from_fire", /* 47 */
111     "spell_protection_from_poison", /* 48 */
112     "spell_protection_from_slow", /* 49 */
113     "spell_protection_from_paralysis", /* 50 */
114     "spell_protection_from_draining", /* 51 */
115     "spell_protection_from_magic", /* 52 */
116     "spell_protection_from_attack", /* 53 */
117     "spell_levitate", /* 54 */
118     "spell_small_speedball", /* 55 */
119     "spell_large_speedball", /* 56 */
120     "spell_hellfire", /* 57 */
121     "spell_dragonbreath", /* 58 */
122     "spell_large_icestorm", /* 59 */
123     "spell_charging", /* 60 */
124     "spell_polymorph", /* 61 */
125     "spell_cancellation", /* 62 */
126     "spell_confusion", /* 63 */
127     "spell_mass_confusion", /* 64 */
128     "spell_summon_pet_monster", /* 65 */
129     "spell_slow", /* 66 */
130     "spell_regenerate_spellpoints", /* 67 */
131     "spell_cure_poison", /* 68 */
132     "spell_protection_from_confusion", /* 69 */
133     "spell_protection_from_cancellation", /* 70 */
134     "spell_protection_from_depletion", /* 71 */
135     "spell_alchemy", /* 72 */
136     "spell_remove_curse", /* 73 */
137     "spell_remove_damnation", /* 74 */
138     "spell_identify", /* 75*/
139     "spell_detect_magic", /* 76 */
140     "spell_detect_monster", /* 77 */
141     "spell_detect_evil", /* 78 */
142     "spell_detect_curse", /* 79 */
143     "spell_heroism", /* 80 */
144     "spell_aggravation", /* 81 */
145     "spell_firebolt", /* 82 */
146     "spell_frostbolt", /* 83 */
147     "spell_shockwave", /* 84 */
148     "spell_color_spray", /* 85 */
149     "spell_haste", /* 86 */
150     "spell_face_of_death", /* 87 */
151     "spell_ball_lightning", /* 88 */
152     "spell_meteor_swarm", /* 89 */
153     "spell_comet", /* 90 */
154     "spell_mystic_fist", /* 91 */
155     "spell_raise_dead", /* 92 */
156     "spell_resurrection", /* 93 */
157     "spell_reincarnation", /* 94 */
158     "spell_immunity_to_cold", /* 95 */
159 root 1.1 "spell_immunity_to_electricity",/* 96 */
160 root 1.18 "spell_immunity_to_fire", /* 97 */
161     "spell_immunity_to_poison", /* 98 */
162     "spell_immunity_to_slow", /* 99 */
163     "spell_immunity_to_paralysis", /* 100 */
164     "spell_immunity_to_draining", /* 101 */
165     "spell_immunity_to_magic", /* 102 */
166     "spell_immunity_to_attack", /* 103 */
167     "spell_invulnerability", /* 104 */
168     "spell_defense", /* 105 */
169     "spell_rune_of_fire", /* 106 */
170     "spell_rune_of_frost", /* 107 */
171     "spell_rune_of_shocking", /* 108 */
172     "spell_rune_of_blasting", /* 109 */
173     "spell_rune_of_death", /* 110 */
174     "spell_marking_rune", /* 111 */
175     "spell_build_director", /* 112 */
176     "spell_create_pool_of_chaos", /* 113 */
177     "spell_build_bullet_wall", /* 114 */
178     "spell_build_lightning_wall", /* 115 */
179     "spell_build_fireball_wall", /* 116 */
180     "spell_magic_rune", /* 117 */
181     "spell_rune_of_magic_drain", /* 118 */
182     "spell_antimagic_rune", /* 119 */
183     "spell_rune_of_transference", /* 120 */
184     "spell_transference", /* 121 */
185     "spell_magic_drain", /* 122 */
186     "spell_counterspell", /* 123 */
187     "spell_disarm", /* 124 */
188     "spell_cure_confusion", /* 125 */
189     "spell_restoration", /* 126 */
190     "was summon evil monster", /* 127 */ /* Not implenented as nothing used it */
191     "spell_counterwall", /* 128 */
192     "spell_cause_light_wounds", /* 129 */
193     "spell_cause_medium_wounds", /* 130 */
194     "spell_cause_heavy_wounds", /* 131 */
195     "spell_charm_monsters", /* 132 */
196     "spell_banishment", /* 133 */
197     "spell_create_missile", /* 134 */
198     "spell_show_invisible", /* 135 */
199     "spell_xray", /* 136 */
200     "spell_pacify", /* 137 */
201     "spell_summon_fog", /* 138 */
202     "spell_steambolt", /* 139 */
203     "spell_command_undead", /* 140 */
204     "spell_holy_orb", /* 141 */
205     "spell_summon_avatar", /* 142 */
206     "spell_holy_possession", /* 143 */
207     "spell_bless", /* 144 */
208     "spell_curse", /* 145 */
209     "spell_regeneration", /* 146 */
210     "spell_consecrate", /* 147 */
211     "spell_summon_cult_monsters", /* 148 */
212     "spell_cause_critical_wounds", /* 149 */
213     "spell_holy_wrath", /* 150 */
214     "spell_retributive_strike", /* 151 */
215     "spell_finger_of_death", /* 152 */
216     "spell_insect_plague", /* 153 */
217     "spell_call_holy_servant", /* 154 */
218     "spell_wall_of_thorns", /* 155 */
219     "spell_staff_to_snake", /* 156 */
220     "spell_light", /* 157 */
221     "spell_darkness", /* 158 */
222     "spell_nightfall", /* 159 */
223     "spell_daylight", /* 160 */
224     "spell_sunspear", /* 161 */
225     "spell_faery_fire", /* 162 */
226     "spell_cure_blindness", /* 163 */
227     "spell_dark_vision", /* 164 */
228     "spell_bullet_swarm", /* 165 */
229     "spell_bullet_storm", /* 166 */
230     "spell_cause_many_wounds", /* 167 */
231     "spell_small_snowstorm", /* 168 */
232     "spell_medium_snowstorm", /* 169 */
233     "spell_large_snowstorm", /* 170 */
234     "spell_cure_disease", /* 171 */
235     "spell_cause_red_death", /* 172 */
236     "spell_cause_flu", /* 173 */
237     "spell_cause_black_death", /* 174 */
238     "spell_cause_leprosy", /* 175 */
239     "spell_cause_smallpox", /* 176 */
240     "spell_cause_white_death", /* 177 */
241     "spell_cause_anthrax", /* 178 */
242     "spell_cause_typhoid", /* 179 */
243     "spell_mana_blast", /* 180 */
244     "spell_small_manaball", /* 181 */
245     "spell_medium_manaball", /* 182 */
246     "spell_large_manaball", /* 183 */
247     "spell_manabolt", /* 184 */
248     "spell_dancing_sword", /* 185 */
249     "spell_animate_weapon", /* 186 */
250     "spell_cause_cold", /* 187 */
251     "spell_divine_shock", /* 188 */
252     "spell_windstorm", /* 189 */
253     "spell_sanctuary", /* 190 */
254     "spell_peace", /* 191 */
255     "spell_spiderweb", /* 192 */
256     "spell_conflict", /* 193 */
257     "spell_rage", /* 194 */
258     "spell_forked_lightning", /* 195 */
259     "spell_poison_fog", /* 196 */
260     "spell_flaming_aura", /* 197 */
261     "spell_vitriol", /* 198 */
262     "spell_vitriol_splash", /* 199 */
263     "spell_iron_skin", /* 200 */
264     "spell_wrathful_eye", /* 201 */
265     "spell_town_portal", /* 202 */
266     "spell_missile_swarm", /* 203 */
267     "spell_cause_rabies", /* 204 */
268     "spell_glyph", /* 205 */
269 root 1.1 NULL
270     };
271    
272     #define SET_OR_CLEAR_FLAG(op, flag, val) \
273 root 1.18 { if (val) SET_FLAG(op, flag); else CLEAR_FLAG(op, flag); }
274 root 1.1
275     #define SET_RESIST(op, type, val) op->resist[type] = val;
276    
277 root 1.18 #define IVAL atoi(yval())
278     #define FVAL atof(yval())
279 root 1.1 extern int arch_init;
280    
281     /* Put this here since it is used below */
282     static void set_protection(object *op, uint32 mask, uint16 pro_val)
283     {
284     int i;
285    
286 root 1.18 if (!mask) return; /* Unlikely, but might as well check */
287 root 1.1 for (i=0; i<NROFATTACKS; i++) {
288 root 1.18 if (mask & (1<<i)) SET_RESIST(op, i, pro_val);
289 root 1.1 }
290     }
291    
292    
293     static void set_body_info(object *op, char *params) {
294     int i;
295     char *cp;
296    
297     /* go to first space character */
298     for (cp=params; !isspace(*cp); cp++) ;
299    
300 root 1.18 *cp++ = 0; /* null it out */
301 root 1.1
302     for (i=0; i<NUM_BODY_LOCATIONS; i++) {
303 root 1.18 if (!strcmp(params, body_locations[i].save_name)) {
304     op->body_info[i] = atoi(cp);
305     return; /* Only one line passed in params */
306     }
307 root 1.1 }
308     LOG(llevError,"set_body_info called with bogus params: %s\n", params);
309     }
310    
311 root 1.3 // return a suitable strign describign an objetc in enough detail to find it
312     // used only in check_loaded_object: TODO remove static, move it elsewhere and
313     // use it in more log messages.
314     static char *op_debug_info_ (object *op, char *info)
315     {
316     char info2[256 * 3];
317     char *p = info;
318    
319 root 1.4 p += snprintf (p, 256, "%d=\"%s%s%s\"",
320     op->count,
321 root 1.18 op->name ? (const char *)op->name : "(anon)",
322 root 1.3 op->title ? " " : "",
323 root 1.18 op->title ? (const char *)op->title : "");
324 root 1.3
325     if (op->env)
326     p += snprintf (p, 256, "(in %s)", op_debug_info_ (op->env, info2));
327    
328     if (op->map)
329 root 1.4 p += snprintf (p, 256, "(on %s@%d+%d)", op->map->path, op->x, op->y);
330 root 1.3
331     return info;
332     }
333    
334     static char *op_debug_info (object *op)
335     {
336     static char info[256 * 3];
337    
338     return op_debug_info_ (op, info);
339     }
340 root 1.1
341     /* This function checks the object after it has been loaded (when we
342     * get the 'end' in the input stream). This function can be used to
343     * deal with legacy objects where fields may have changed. It can also be used
344     * to check for objects to make sure there are no common errors.
345     */
346     static void check_loaded_object(object *op) {
347     int ip;
348    
349     /* We do some specialized handling to handle legacy cases of name_pl.
350     * If the object doesn't have a name_pl, we just use the object name -
351     * this isn't perfect (things won't be properly pluralized), but works to
352     * that degree (5 heart is still quite understandable). But the case we
353     * also have to catch is if this object is not using the normal name for
354     * the object. In that case, we also want to use the loaded name.
355     * Otherwise, what happens is that the the plural name will lose
356     * information (appear as just 'hearts' and not 'goblins heart')
357     */
358 root 1.19 if (op->arch && op->name != op->arch->clone.name && op->name_pl == op->arch->clone.name_pl)
359     op->name_pl = NULL;
360    
361     if (!op->name_pl) op->name_pl = op->name;
362 root 1.1
363     /* objects now have a materialname. try to patch it in */
364     if (!(IS_WEAPON(op) && op->level > 0)) {
365     if (op->map != NULL)
366     set_materialname(op, op->map->difficulty, NULL);
367     else
368     set_materialname(op, 5, NULL);
369     }
370     /* only do these when program is first run - a bit
371     * excessive to do this at every run - most of this is
372     * really just to catch any errors - program will still run, but
373     * not in the ideal fashion.
374     */
375     if ((op->type == WEAPON || op->type==BOW) && arch_init) {
376 root 1.18 if (!op->skill) {
377     LOG(llevError,"Weapon %s lacks a skill.\n", op_debug_info (op));
378     } else if ((!strcmp(op->skill,"one handed weapons") && op->body_info[1] != -1) ||
379     (!strcmp(op->skill,"two handed weapons") && op->body_info[1] != -2)) {
380     LOG(llevError,"weapon %s arm usage does not match skill: %d, %s\n",
381 root 1.19 op_debug_info (op), op->body_info[1], &op->skill);
382 root 1.18 }
383 root 1.1 }
384    
385     /* We changed last_heal to gen_sp_armour, which is what it
386     * really does for many objects. Need to catch any in maps
387     * that may have an old value.
388     */
389     if ((op->type == WEAPON) ||
390     (op->type == ARMOUR) || (op->type == HELMET) ||
391     (op->type == SHIELD) || (op->type == RING) ||
392     (op->type == BOOTS) || (op->type == GLOVES) ||
393     (op->type == AMULET ) || (op->type == GIRDLE) ||
394     (op->type == BRACERS ) || (op->type == CLOAK)) {
395 root 1.18 if (op->last_heal) {
396     LOG(llevDebug,"Object %s still has last_heal set, not gen_sp_armour\n", op_debug_info (op));
397     op->gen_sp_armour = op->last_heal;
398     op->last_heal = 0;
399     }
400     if (editor) ip =0;
401     else ip = calc_item_power(op, 0);
402     /* Legacy objects from before item power was in the game */
403     if (!op->item_power && ip) {
404     if (ip > 3) {
405     LOG(llevDebug,"Object %s had no item power, using %d\n", op_debug_info (op), ip);
406     }
407     op->item_power = ip;
408     }
409     /* Check for possibly bogus values. Has to meet both these criteria -
410     * something that has item_power 1 is probably just fine if our calculated
411     * value is 1 or 2 - these values are small enough that hard to be precise.
412     * similarly, it item_power is 0, the first check will always pass,
413     * but not the second one.
414     */
415     if (ip > 2 *op->item_power && ip > (op->item_power + 3)) {
416     LOG(llevDebug,"Object %s seems to have too low item power? %d > %d\n",
417     op_debug_info (op), ip, op->item_power);
418     }
419 root 1.1
420     }
421     /* Old spellcasting object - need to load in the appropiate object */
422     if ((op->type == ROD || op->type == WAND || op->type == SCROLL || op->type == HORN
423 root 1.18 || op->type == FIREWALL ||
424     /* POTIONS and ALTARS don't always cast spells, but if they do, update them */
425     ((op->type == POTION || op->type == ALTAR) && op->stats.sp)) && !op->inv && !arch_init) {
426     object *tmp;
427    
428     /* Fireall is bizarre in that spell type was stored in dam. Rest are 'normal'
429     * in that spell was stored in sp.
430     */
431     tmp = get_archetype(spell_mapping[op->type == FIREWALL?op->stats.dam:op->stats.sp]);
432     insert_ob_in_ob(tmp, op);
433     op->randomitems = NULL; /* So another spell isn't created for this object */
434 root 1.1 }
435     /* spellbooks & runes use slaying. But not to arch name, but to spell name */
436    
437     if ((op->type == SPELLBOOK || op->type == RUNE) && op->slaying && !op->inv && !arch_init) {
438 root 1.18 object *tmp;
439 root 1.1
440 root 1.18 tmp = get_archetype_by_object_name(op->slaying);
441     insert_ob_in_ob(tmp, op);
442     op->randomitems = NULL; /* So another spell isn't created for this object */
443     /* without this, value is all screwed up */
444     op->value = op->arch->clone.value * op->inv->value;
445 root 1.1 }
446    
447     if (QUERY_FLAG(op, FLAG_MONSTER)) {
448 root 1.18 if (op->stats.hp > op->stats.maxhp)
449     LOG(llevDebug,"Monster %s has hp set higher than maxhp (%d>%d)\n",
450     op_debug_info (op),
451     op->stats.hp, op->stats.maxhp);
452 root 1.1
453 root 1.18 /* The archs just need to be updated for this */
454     if (op->move_type ==0) op->move_type = MOVE_WALK;
455 root 1.1 }
456     if ((QUERY_FLAG(op,FLAG_GENERATOR) && QUERY_FLAG(op,FLAG_CONTENT_ON_GEN))
457     || op->type == CREATOR
458     || op->type == CONVERTER) {
459     /* Object will duplicate it's content as part of the
460     * generation process. To do this, we must flag inventory
461     * so it remains unevaluated concerning the randomitems and
462     * the living (a demonlord shouldn't cast from inside generator!)
463     */
464     flag_inv(op,FLAG_IS_A_TEMPLATE);
465     }
466    
467     /* Handle player movers. We use move_type for player movers
468     * because they operate on their own time (move_on
469     * would potentially cause them to be triggered when someone steps
470     * on them). If move_type is set, presume person knows what they
471     * are doing, otherwise, set move_type based on maxhp value.
472     */
473     if (op->type == PLAYERMOVER) {
474 root 1.18 if (!op->move_type) {
475     if (op->stats.maxhp) {
476     op->move_type = MOVE_ALL;
477     op->stats.maxhp=0;
478     } else {
479     op->move_type = MOVE_WALK;
480     }
481     }
482 root 1.1 }
483    
484     }
485    
486     /* This extracts the key/value from the yytext field -
487     * calls set_ob_key_value() to actually set the value.
488     * Function basically has to find spaces, strip out extra,
489     * etc. strchr doesn't work as good because could also
490     * be tabs.
491     */
492     static void add_key_value(object * op) {
493     char * key = NULL;
494     char * value = NULL;
495     char * cp;
496     char * end;
497    
498     /* First, skip over leading whitespace. */
499     for (cp = yytext; isspace(*cp); cp++) { ; }
500    
501     key = cp;
502    
503     /* Now look for the end of the key/field name. */
504     for (; !isspace(*cp); cp++) {
505     if (*cp == '\0') {
506     /* Oops, ran out of string! Set the key with an empty value. */
507     set_ob_key_value(op, key, NULL, TRUE);
508     return;
509     }
510     }
511    
512     if (*cp == '\0') {
513     set_ob_key_value(op, key, NULL, TRUE);
514     return;
515     }
516    
517     /* Chop off the key, and start at the next character. */
518     *cp = '\0';
519     cp++;
520     if (*cp == '\0') {
521     /* Was followed by one space? */
522     set_ob_key_value(op, key, NULL, TRUE);
523     return;
524     }
525    
526     /* Now looking for the value. Skip over whitespace. */
527     for (; isspace(*cp); cp++) {
528     if (*cp == '\0') {
529     /* Guess not. */
530     set_ob_key_value(op, key, NULL, TRUE);
531     return;
532     }
533     }
534    
535     value = cp;
536    
537     /* Got last character before null and strip
538     * off tailing whitespace
539     */
540     for (end = value + (strlen(cp)-1); isspace(*end); end--) {
541 root 1.18 if (end == value) {
542     /* *blink blink* Still no value? */
543     set_ob_key_value(op, key, NULL, TRUE);
544     return;
545     }
546     *end='\0';
547 root 1.1 }
548     set_ob_key_value(op, key, value, TRUE);
549     }
550    
551 root 1.2 static void set_move(MoveType *mt, char *params) {
552     char *str;
553     int i, negate;
554    
555     if (isdigit(*params)) {
556 root 1.18 *mt = atoi(params);
557 root 1.2 } else {
558 root 1.18 *mt=0;
559     for (str=strtok(params, " "); str; str=strtok(NULL, " ")) {
560     negate=0;
561     if (!strcasecmp(str, "all"))
562     *mt |= MOVE_ALL;
563     else {
564     if (*str=='-') {
565     negate = 1;
566     str++;
567     }
568     for (i=0; move_name[i] != NULL; i++) {
569     if (!strcasecmp(move_name[i], str)) {
570     if (negate) {
571     *mt &= ~(1<<i);
572     } else {
573     *mt |= (1<<i);
574     }
575     break;
576     }
577     }
578     if (move_name[i] == NULL) {
579     /* fly is a special case - covers both fly_low and
580     * fly_high - since it doesn't match to a specific
581     * single bit, have to special case it.
582     */
583     if (!strcasecmp(str,"flying")) {
584     if (negate) {
585     *mt &= ~MOVE_FLYING;
586     } else {
587     *mt |= MOVE_FLYING;
588     }
589     } else {
590     LOG(llevDebug, "common/loader.l: set_move - unknown move string '%s'\n", str);
591     }
592     }
593     } /* Else not all move types */
594     } /* for strtok */
595 root 1.2 } /* Else not a numeric value */
596     }
597 root 1.1
598     %}
599    
600    
601    
602 root 1.18 S [ \t]+.*
603     WS [ \t]*
604     A .+
605 root 1.1
606     %x MESSAGE
607     %x LORE
608     %x SCRIPT
609    
610     /* Don't have to link with -lfl with this */
611     %option noyywrap
612    
613     /* need yy_push_state, yy_pop_state */
614     %option stack
615    
616     %%
617    
618     %{
619     /* Declare some local variables */
620     int ismore=0;
621    
622     lex_error=0;
623    
624     %}
625    
626 root 1.18 ^msg{WS}$ { BEGIN( MESSAGE ); msgbuf[0]='\0'; }
627     <MESSAGE>^endmsg{WS}$ { BEGIN( INITIAL );
628     /* Just print a warning so we can be reasonably safe
629     * about not overflowing the buffer.
630     */
631     if (strlen(msgbuf) >= HUGE_BUF)
632 root 1.5 {
633 root 1.18 LOG(llevDebug, "\n\tError message length >= %d: %d\n>%.80s<\n",
634 root 1.19 HUGE_BUF, strlen(op->msg), &op->msg);
635     op->msg = "ERROR, please report: string too long, winged.\n";
636 root 1.5 }
637     else
638 root 1.19 op->msg = msgbuf;
639 root 1.18 }
640     <MESSAGE>.* {strcat(msgbuf, yytext); strcat(msgbuf,"\n"); }
641    
642     ^lore{WS}$ { BEGIN( LORE ); lorebuf[0]='\0'; }
643     <LORE>^endlore{WS}$ { BEGIN( INITIAL );
644 root 1.19 op->lore=lorebuf;
645 root 1.18 /* Just print a warning so we can be reasonably safe
646     * about not overflowing the buffer.
647     */
648     if (strlen(op->lore) > (HUGE_BUF/2))
649     LOG(llevDebug, "\n\tWarning lore length > %d (max allowed=%d): %d\n>%.80s<\n",
650 root 1.19 HUGE_BUF/2, HUGE_BUF, strlen(op->lore), &op->lore);
651 root 1.18 }
652     <LORE>.* {strcat(lorebuf, yytext); strcat(lorebuf,"\n"); }
653    
654     ^object{S} { char *yv=yval();
655    
656     if (*yv=='\0') {
657     LOG(llevError,"Object lacks name.\n");
658     return LL_IGNORED;
659     }
660     if (!arch_init) {
661     LOG(llevError,"Got object info when not in arch_init (%s)?\n", yv);
662     } else {
663 root 1.19 if (op->arch!=NULL) op->arch->name=yv;
664     op->name = yv;
665 root 1.18 }
666     }
667    
668     ^name{S} { char *yv=yval();
669 root 1.1
670 root 1.18 if (*yv=='\0') LOG(llevError,"Name without val\n");
671 root 1.19 else op->name = yv;
672 root 1.18 }
673     ^name_pl{S} { char *yv=yval();
674    
675     if (*yv=='\0') LOG(llevError,"Name without val\n");
676 root 1.19 else op->name_pl = yv;
677 root 1.8 }
678 root 1.19 ^attach{S} op->attach = yval ();
679     ^skill{S} op->skill = yval();
680 root 1.18 ^custom_name{S} { char *yv=yval();
681 root 1.1
682 root 1.18 if (*yv=='\0') LOG(llevError,"Custom name without val\n");
683 root 1.19 else op->custom_name = yv;
684 root 1.18 }
685 root 1.19 ^race{S} op->race = yval();
686     ^slaying{S} op->slaying = yval();
687 root 1.18 ^inventory.*$ LOG(llevError,"Got depreciated Inventory command?\n");
688    
689    
690     ^arch{S} { /* If op->arch has been set, then this new object
691     * must be part of the inventory. So process
692     * appropriately.
693     */
694     if (op->arch) {
695     object *tmp;
696     char *yv=yval();
697    
698     archetype *arch = find_archetype(yv);
699     if (arch!=NULL)
700     tmp = arch_to_object (arch);
701     else {
702 root 1.9 tmp = get_object ();
703 root 1.18 /* record the name of the broken object */
704 root 1.19 tmp->name = yv;
705 root 1.18 }
706     strcpy(msgbuf, "");
707     strcpy(lorebuf, "");
708     lex_load(tmp, thawer, map_flags);
709     if (tmp->arch) {
710     insert_ob_in_ob(tmp,op);
711     }
712     else {
713     LOG(llevDebug,"Discarding object without arch: %s\n", tmp->name?(const char *)tmp->name:"(null)");
714     free_object(tmp);
715     }
716     }
717     /* This is the actual archetype definition then */
718     else {
719     char *yv=yval();
720 root 1.1
721 root 1.18 op->arch=find_archetype(yv);
722     if (op->arch!=NULL) {
723 root 1.9 copy_object(&op->arch->clone,op);
724     } else if (!arch_init) {
725 root 1.18 /* record the name of the broken object */
726 root 1.19 op->name = yv;
727 root 1.18 }
728     }
729     }
730 root 1.1
731     ^other_arch{S} op->other_arch=find_archetype(yval());
732 root 1.18 ^animation{S} {
733     if (strcmp (yval(), "NONE") == 0) {
734     op->animation_id = 0;
735     CLEAR_FLAG (op, FLAG_ANIMATE);
736     } else {
737     op->animation_id = find_animation (yval());
738     SET_FLAG (op, FLAG_ANIMATE);
739     }
740     }
741    
742     ^more{WS}$ { /* We need to record that this is a multipart object,
743     * so the calling function can glue things back together
744     */
745     ismore=1;
746     }
747     ^end{WS}$ { check_loaded_object(op);
748 root 1.11
749     if (!arch_init)
750 root 1.12 op->instantiate ();
751 root 1.11
752 root 1.18 if (ismore) return LL_MORE;
753     else return LL_NORMAL;
754     }
755 root 1.12 ^oid{S} {
756     thawer.get (op, IVAL);
757     }
758 root 1.18 ^last_heal{S} op->last_heal = IVAL;
759     ^last_sp{S} op->last_sp = IVAL;
760     ^last_grace{S} op->last_grace = IVAL;
761     ^last_eat{S} op->last_eat = IVAL;
762     ^speed{S} { op->speed = FVAL;
763     if (!(map_flags & MAP_STYLE)) {
764     if (op->speed<0) op->speed_left = op->speed_left-RANDOM()%100/100.0;
765     update_ob_speed(op);
766     }
767     }
768 root 1.1 ^speed_left{S} op->speed_left = FVAL;
769 root 1.18 ^slow_move{S} { op->move_slow |= MOVE_WALK;
770     op->move_slow_penalty = FVAL;
771     }
772     ^title{S} { char *y=yval();
773     if (*y=='\0') LOG(llevError,"Title without value.\n");
774 root 1.19 else op->title = y;
775 root 1.18 }
776    
777     ^face{S} op->face = &new_faces[FindFace(yval(), 0)];
778     ^str{S} op->stats.Str = IVAL;
779     ^dex{S} op->stats.Dex = IVAL;
780     ^con{S} op->stats.Con = IVAL;
781     ^wis{S} op->stats.Wis = IVAL;
782     ^cha{S} op->stats.Cha = IVAL;
783     ^int{S} op->stats.Int = IVAL;
784     ^pow{S} op->stats.Pow = IVAL;
785     ^hp{S} op->stats.hp = IVAL;
786     ^maxhp{S} op->stats.maxhp = IVAL;
787     ^sp{S} op->stats.sp = IVAL;
788     ^maxsp{S} op->stats.maxsp = IVAL;
789     ^grace{S} op->stats.grace = IVAL;
790     ^maxgrace{S} op->stats.maxgrace = IVAL;
791     ^exp{S} op->stats.exp = atoll(yval());
792     ^perm_exp{S} op->perm_exp = atoll(yval());
793     ^food{S} op->stats.food = IVAL;
794     ^dam{S} op->stats.dam = IVAL;
795     ^wc{S} op->stats.wc = IVAL;
796     ^ac{S} op->stats.ac = IVAL;
797     ^x{S} {op->x = IVAL; op->ox= op->x; }
798     ^y{S} {op->y = IVAL; op->oy= op->y; }
799     ^nrof{S} op->nrof= atol(yval());
800     ^level{S} op->level = IVAL;
801     ^direction{S} op->direction = IVAL;
802     ^type{S} op->type = IVAL;
803     ^subtype{S} op->subtype = IVAL;
804     ^material{S} op->material = IVAL;
805     ^materialname{S} { char *yv=yval();
806     if (*yv=='\0')
807     LOG(llevError,"Materialname without val\n");
808     else
809 root 1.19 op->materialname = yv;
810 root 1.18 }
811    
812     ^value{S} op->value = IVAL;
813     ^weight{S} op->weight = atol(yval());
814     ^carrying{S} op->carrying = atol(yval());
815 root 1.1 ^attacktype{S} op->attacktype = IVAL;
816     ^path_attuned{S} op->path_attuned = IVAL;
817     ^path_repelled{S} op->path_repelled = IVAL;
818     ^path_denied{S} op->path_denied = IVAL;
819 root 1.18 ^invisible{S} op->invisible = IVAL;
820     ^magic{S} op->magic = IVAL;
821     ^state{S} op->state = IVAL;
822     ^alive{S} SET_OR_CLEAR_FLAG(op, FLAG_ALIVE, IVAL);
823     ^applied{S} SET_OR_CLEAR_FLAG(op, FLAG_APPLIED, IVAL);
824     ^unpaid{S} SET_OR_CLEAR_FLAG(op, FLAG_UNPAID, IVAL);
825     ^need_an{S} { /* not used - just ignore */ }
826     ^need_ie{S} { /* not used - jsut ignore */ }
827     ^is_animated{S} SET_OR_CLEAR_FLAG(op, FLAG_ANIMATE, IVAL);
828     ^no_pick{S} SET_OR_CLEAR_FLAG(op, FLAG_NO_PICK, IVAL);
829 root 1.1
830     %{ /* These are all legacy - any new objects should use the move_ .. values */
831     %}
832 root 1.18 ^no_pass{S} { if (IVAL) op->move_block = MOVE_ALL; else op->move_block=0; }
833     ^walk_on{S} { if (IVAL) op->move_on |= MOVE_WALK; else op->move_on &= ~MOVE_WALK; }
834     ^walk_off{S} { if (IVAL) op->move_off |= MOVE_WALK; else op->move_off &= ~MOVE_WALK; }
835     ^fly_on{S} { if (IVAL) op->move_on |= MOVE_FLY_LOW; else op->move_on &= ~MOVE_FLY_LOW; }
836     ^fly_off{S} { if (IVAL) op->move_off |= MOVE_FLY_LOW; else op->move_off &= ~MOVE_FLY_LOW; }
837     ^flying{S} { if (IVAL) op->move_type |= MOVE_FLY_LOW; else op->move_type &= ~MOVE_FLY_LOW; }
838 root 1.1
839     %{ /* These are the new values */
840     %}
841 root 1.18 ^move_block{S} set_move(&op->move_block, yval());
842     ^move_allow{S} set_move(&op->move_allow, yval());
843     ^move_type{S} set_move(&op->move_type, yval());
844     ^move_on{S} set_move(&op->move_on, yval());
845     ^move_off{S} set_move(&op->move_off, yval());
846     ^move_slow{S} set_move(&op->move_slow, yval());
847     ^move_slow_penalty{S} op->move_slow_penalty = FVAL;
848    
849    
850     ^monster{S} SET_OR_CLEAR_FLAG(op, FLAG_MONSTER, IVAL);
851     ^neutral{S} SET_OR_CLEAR_FLAG(op, FLAG_NEUTRAL, IVAL);
852     ^no_attack{S} SET_OR_CLEAR_FLAG(op, FLAG_NO_ATTACK, IVAL);
853     ^no_damage{S} SET_OR_CLEAR_FLAG(op, FLAG_NO_DAMAGE, IVAL);
854     ^friendly{S} { if (IVAL) {
855     SET_FLAG(op, FLAG_FRIENDLY);
856     if (op->type != PLAYER)
857     add_friendly_object (op);
858     }
859     else CLEAR_FLAG(op, FLAG_FRIENDLY);
860     }
861     ^generator{S} SET_OR_CLEAR_FLAG(op, FLAG_GENERATOR, IVAL);
862 root 1.1 ^use_content_on_gen{S} SET_OR_CLEAR_FLAG (op,FLAG_CONTENT_ON_GEN, IVAL);
863 root 1.18 ^is_thrown{S} SET_OR_CLEAR_FLAG(op, FLAG_IS_THROWN, IVAL);
864     ^auto_apply{S} SET_OR_CLEAR_FLAG(op, FLAG_AUTO_APPLY, IVAL);
865     ^treasure{S} SET_OR_CLEAR_FLAG(op, FLAG_TREASURE, IVAL);
866 root 1.1 ^see_invisible{S} SET_OR_CLEAR_FLAG(op, FLAG_SEE_INVISIBLE, IVAL);
867 root 1.18 ^can_roll{S} SET_OR_CLEAR_FLAG(op, FLAG_CAN_ROLL, IVAL);
868 root 1.1 ^overlay_floor{S} SET_OR_CLEAR_FLAG(op, FLAG_OVERLAY_FLOOR, IVAL);
869 root 1.18 ^is_turnable{S} SET_OR_CLEAR_FLAG(op, FLAG_IS_TURNABLE, IVAL);
870     ^is_used_up{S} SET_OR_CLEAR_FLAG(op, FLAG_IS_USED_UP, IVAL);
871     ^identified{S} { if (IVAL) {
872     SET_FLAG(op, FLAG_IDENTIFIED);
873     CLEAR_FLAG(op, FLAG_KNOWN_MAGICAL);
874     }
875     else CLEAR_FLAG(op, FLAG_IDENTIFIED);
876     }
877     ^reflecting{S} SET_OR_CLEAR_FLAG(op, FLAG_REFLECTING, IVAL);
878     ^changing{S} SET_OR_CLEAR_FLAG(op, FLAG_CHANGING, IVAL);
879     ^splitting{S} SET_OR_CLEAR_FLAG(op, FLAG_SPLITTING, IVAL);
880     ^hitback{S} SET_OR_CLEAR_FLAG(op, FLAG_HITBACK, IVAL);
881     ^startequip{S} SET_OR_CLEAR_FLAG(op, FLAG_STARTEQUIP, IVAL);
882     ^blocksview{S} SET_OR_CLEAR_FLAG(op, FLAG_BLOCKSVIEW, IVAL);
883     ^editable{S} op->arch->editable = IVAL;
884 root 1.1 ^editor_folder{S} { }
885 root 1.18 ^undead{S} SET_OR_CLEAR_FLAG(op, FLAG_UNDEAD, IVAL);
886     ^scared{S} SET_OR_CLEAR_FLAG(op, FLAG_SCARED, IVAL);
887 root 1.1 ^unaggressive{S} SET_OR_CLEAR_FLAG(op, FLAG_UNAGGRESSIVE, IVAL);
888     ^reflect_missile{S} SET_OR_CLEAR_FLAG(op, FLAG_REFL_MISSILE, IVAL);
889     ^reflect_spell{S} SET_OR_CLEAR_FLAG(op, FLAG_REFL_SPELL, IVAL);
890 root 1.18 ^no_magic{S} SET_OR_CLEAR_FLAG(op, FLAG_NO_MAGIC, IVAL);
891     ^wiz{S} { if (IVAL) {
892     SET_FLAG(op, FLAG_WIZ);
893     SET_FLAG(op, FLAG_WAS_WIZ);
894     SET_FLAG(op, FLAG_WIZPASS);
895     SET_FLAG(op, FLAG_WIZCAST);
896     }
897     else {
898     CLEAR_FLAG(op, FLAG_WIZ);
899     CLEAR_FLAG(op, FLAG_WIZPASS);
900     CLEAR_FLAG(op, FLAG_WIZCAST);
901     }
902     }
903     ^was_wiz{S} SET_OR_CLEAR_FLAG(op, FLAG_WAS_WIZ, IVAL);
904 root 1.1 ^no_fix_player{S} SET_OR_CLEAR_FLAG(op, FLAG_NO_FIX_PLAYER, IVAL);
905     ^is_lightable{S} SET_OR_CLEAR_FLAG(op, FLAG_IS_LIGHTABLE, IVAL);
906 root 1.18 ^tear_down{S} SET_OR_CLEAR_FLAG(op, FLAG_TEAR_DOWN, IVAL);
907     ^luck{S} op->stats.luck = IVAL;
908     ^run_away{S} op->run_away = IVAL;
909     ^pick_up{S} op->pick_up = IVAL;
910     ^item_power{S} op->item_power = IVAL;
911 root 1.1 ^gen_sp_armour{S} op->gen_sp_armour = IVAL;
912 root 1.18 ^anim_speed{S} op->anim_speed = IVAL;
913     ^container{S} op->weight_limit = IVAL;
914     ^no_drop{S} SET_OR_CLEAR_FLAG(op, FLAG_NO_DROP, IVAL);
915     ^will_apply{S} op->will_apply = IVAL;
916     ^random_movement{S} SET_OR_CLEAR_FLAG(op, FLAG_RANDOM_MOVE, IVAL);
917     ^can_apply{S} { }
918 root 1.1 ^can_use_shield{S} SET_OR_CLEAR_FLAG(op, FLAG_USE_SHIELD, IVAL);
919 root 1.18 ^can_cast_spell{S} SET_OR_CLEAR_FLAG(op, FLAG_CAST_SPELL, IVAL);
920     ^can_use_scroll{S} SET_OR_CLEAR_FLAG(op, FLAG_USE_SCROLL, IVAL);
921     ^can_use_range{S} SET_OR_CLEAR_FLAG(op, FLAG_USE_RANGE, IVAL);
922     ^can_use_bow{S} SET_OR_CLEAR_FLAG(op, FLAG_USE_BOW, IVAL);
923     ^can_use_armour{S} SET_OR_CLEAR_FLAG(op, FLAG_USE_ARMOUR, IVAL);
924     ^can_use_weapon{S} SET_OR_CLEAR_FLAG(op, FLAG_USE_WEAPON, IVAL);
925     ^can_use_ring{S} SET_OR_CLEAR_FLAG(op, FLAG_USE_RING, IVAL);
926 root 1.1 ^has_ready_bow{S} SET_OR_CLEAR_FLAG(op, FLAG_READY_BOW, IVAL);
927 root 1.18 ^xrays{S} SET_OR_CLEAR_FLAG(op, FLAG_XRAYS, IVAL);
928     ^is_floor{S} SET_OR_CLEAR_FLAG(op, FLAG_IS_FLOOR, IVAL);
929     ^lifesave{S} SET_OR_CLEAR_FLAG(op, FLAG_LIFESAVE, IVAL);
930     ^no_strength{S} SET_OR_CLEAR_FLAG(op, FLAG_NO_STRENGTH, IVAL);
931     ^sleep{S} {
932     SET_OR_CLEAR_FLAG(op, FLAG_SLEEP, IVAL);
933     /*(LOG(llevDebug," Warning: Object %s has sleep set in arch.\n",op->name);*/
934     }
935     ^stand_still{S} SET_OR_CLEAR_FLAG(op, FLAG_STAND_STILL, IVAL);
936     ^random_move{S} SET_OR_CLEAR_FLAG(op, FLAG_RANDOM_MOVE, IVAL);
937     ^only_attack{S} SET_OR_CLEAR_FLAG(op, FLAG_ONLY_ATTACK, IVAL);
938 root 1.1
939 root 1.18 ^activate_on_push{S} SET_OR_CLEAR_FLAG(op, FLAG_ACTIVATE_ON_PUSH, IVAL);
940     ^activate_on_release{S} SET_OR_CLEAR_FLAG(op, FLAG_ACTIVATE_ON_RELEASE, IVAL);
941 root 1.1
942     /* armour is loaded for compatiblity reasons */
943 root 1.18 ^armour{S} SET_RESIST(op, ATNR_PHYSICAL, IVAL);
944 root 1.1 /* Start of various attacktypes */
945 root 1.18 ^resist_physical{S} SET_RESIST(op, ATNR_PHYSICAL, IVAL);
946     ^resist_magic{S} SET_RESIST(op, ATNR_MAGIC, IVAL);
947     ^resist_fire{S} SET_RESIST(op, ATNR_FIRE, IVAL);
948     ^resist_electricity{S} SET_RESIST(op, ATNR_ELECTRICITY, IVAL);
949     ^resist_cold{S} SET_RESIST(op, ATNR_COLD, IVAL);
950     ^resist_confusion{S} SET_RESIST(op, ATNR_CONFUSION, IVAL);
951     ^resist_acid{S} SET_RESIST(op, ATNR_ACID, IVAL);
952     ^resist_drain{S} SET_RESIST(op, ATNR_DRAIN, IVAL);
953     ^resist_weaponmagic{S} SET_RESIST(op, ATNR_WEAPONMAGIC, IVAL);
954     ^resist_ghosthit{S} SET_RESIST(op, ATNR_GHOSTHIT, IVAL);
955     ^resist_poison{S} SET_RESIST(op, ATNR_POISON, IVAL);
956     ^resist_slow{S} SET_RESIST(op, ATNR_SLOW, IVAL);
957     ^resist_paralyze{S} SET_RESIST(op, ATNR_PARALYZE, IVAL);
958     ^resist_turn_undead{S} SET_RESIST(op, ATNR_TURN_UNDEAD, IVAL);
959     ^resist_fear{S} SET_RESIST(op, ATNR_FEAR, IVAL);
960     ^resist_cancellation{S} SET_RESIST(op, ATNR_CANCELLATION, IVAL);
961     ^resist_deplete{S} SET_RESIST(op, ATNR_DEPLETE, IVAL);
962     ^resist_death{S} SET_RESIST(op, ATNR_DEATH, IVAL);
963     ^resist_chaos{S} SET_RESIST(op, ATNR_CHAOS, IVAL);
964     ^resist_counterspell{S} SET_RESIST(op, ATNR_COUNTERSPELL, IVAL);
965     ^resist_godpower{S} SET_RESIST(op, ATNR_GODPOWER, IVAL);
966     ^resist_holyword{S} SET_RESIST(op, ATNR_HOLYWORD, IVAL);
967     ^resist_blind{S} SET_RESIST(op, ATNR_BLIND, IVAL);
968     ^resist_internal{S} SET_RESIST(op, ATNR_INTERNAL, IVAL);
969     ^resist_life_stealing{S} SET_RESIST(op, ATNR_LIFE_STEALING, IVAL);
970     ^resist_disease{S} SET_RESIST(op, ATNR_DISEASE, IVAL);
971 root 1.1
972     /* Old style resistances */
973 root 1.18 ^immune{S} set_protection(op, IVAL, RESIST_IMMUNE);
974     ^protected{S} set_protection(op, IVAL, RESIST_PROT);
975     ^vulnerable{S} set_protection(op, IVAL, (uint16) RESIST_VULN);
976 root 1.1
977     /* old values - keep them around for now, but they should be removed at some point */
978 root 1.18 ^has_ready_rod{S} SET_OR_CLEAR_FLAG(op, FLAG_READY_RANGE, IVAL);
979     ^has_ready_horn{S} SET_OR_CLEAR_FLAG(op, FLAG_READY_RANGE, IVAL);
980     ^has_ready_wand{S} SET_OR_CLEAR_FLAG(op, FLAG_READY_RANGE, IVAL);
981     ^can_use_wand{S} SET_OR_CLEAR_FLAG(op, FLAG_USE_RANGE, IVAL);
982 root 1.1
983     ^attack_movement{S} op->attack_movement = IVAL;
984 root 1.18 ^move_state{S} op->move_status = IVAL;
985     ^confused{S} SET_OR_CLEAR_FLAG(op, FLAG_CONFUSED, IVAL);
986     ^stealth{S} SET_OR_CLEAR_FLAG(op, FLAG_STEALTH, IVAL);
987     ^connected{S} add_button_link(op, op->map, IVAL);
988     ^cursed{S} SET_OR_CLEAR_FLAG(op, FLAG_CURSED, IVAL);
989     ^damned{S} SET_OR_CLEAR_FLAG(op, FLAG_DAMNED, IVAL);
990 root 1.1 ^see_anywhere{S} SET_OR_CLEAR_FLAG(op, FLAG_SEE_ANYWHERE, IVAL);
991     ^known_magical{S} SET_OR_CLEAR_FLAG(op, FLAG_KNOWN_MAGICAL, IVAL);
992     ^known_cursed{S} SET_OR_CLEAR_FLAG(op, FLAG_KNOWN_CURSED, IVAL);
993     ^can_use_skill{S} SET_OR_CLEAR_FLAG(op, FLAG_CAN_USE_SKILL, IVAL);
994     ^been_applied{S} SET_OR_CLEAR_FLAG(op, FLAG_BEEN_APPLIED, IVAL);
995 root 1.18 ^has_ready_scroll{S} SET_OR_CLEAR_FLAG(op, FLAG_READY_SCROLL, IVAL);
996     ^can_use_rod{S} SET_OR_CLEAR_FLAG(op, FLAG_USE_ROD, IVAL);
997     ^can_use_horn{S} SET_OR_CLEAR_FLAG(op, FLAG_USE_HORN, IVAL);
998     ^expmul{S} op->expmul = FVAL;
999     ^unique{S} SET_OR_CLEAR_FLAG(op, FLAG_UNIQUE, IVAL);
1000     ^make_invisible{S} SET_OR_CLEAR_FLAG(op, FLAG_MAKE_INVIS, IVAL);
1001     ^inv_locked{S} SET_OR_CLEAR_FLAG(op, FLAG_INV_LOCKED, IVAL);
1002     ^is_wooded{S} SET_OR_CLEAR_FLAG(op, FLAG_IS_WOODED, IVAL);
1003     ^is_hilly{S} SET_OR_CLEAR_FLAG(op, FLAG_IS_HILLY, IVAL);
1004     ^is_water{S} SET_OR_CLEAR_FLAG(op, FLAG_IS_WATER, IVAL);
1005     ^has_ready_skill{S} SET_OR_CLEAR_FLAG(op, FLAG_READY_SKILL, IVAL);
1006     ^has_ready_weapon{S} SET_OR_CLEAR_FLAG(op, FLAG_READY_WEAPON, IVAL);
1007     ^no_skill_ident{S} SET_OR_CLEAR_FLAG(op, FLAG_NO_SKILL_IDENT, IVAL);
1008     ^glow_radius{S} op->glow_radius = IVAL;
1009     ^is_blind{S} SET_OR_CLEAR_FLAG(op, FLAG_BLIND, IVAL);
1010     ^can_see_in_dark{S} SET_OR_CLEAR_FLAG(op, FLAG_SEE_IN_DARK, IVAL);
1011     ^is_cauldron{S} SET_OR_CLEAR_FLAG(op, FLAG_IS_CAULDRON, IVAL);
1012     ^randomitems{S} op->randomitems = find_treasurelist(yval());
1013     ^no_steal{S} SET_OR_CLEAR_FLAG(op, FLAG_NO_STEAL, IVAL);
1014     ^one_hit{S} SET_OR_CLEAR_FLAG(op, FLAG_ONE_HIT, IVAL);
1015     ^berserk{S} SET_OR_CLEAR_FLAG(op, FLAG_BERSERK, IVAL);
1016    
1017     ^can_knockback{S} { /* Some archetypes have these values in them */ }
1018     ^can_parry{S} { /* Probably the pupland archetypes - I imagined */ }
1019     ^can_impale{S} { /* That these are for the new combat code */ }
1020     ^can_cut{S} { /* just ignore for now */ }
1021     ^can_dam_armour{S} { }
1022     ^weapontype{S} op->weapontype = IVAL;
1023 root 1.1 ^tooltype{S} op->tooltype = IVAL;
1024 root 1.18 ^casting_time{S} op->casting_time = (sint16) FVAL;
1025     ^elevation{S} op->elevation = IVAL;
1026     ^smoothlevel{S} op->smoothlevel = IVAL;
1027     ^client_type{S} op->client_type = IVAL;
1028     ^body_{A} set_body_info(op, yytext);
1029     ^duration{S} op->duration = IVAL;
1030     ^range{S} op->range = IVAL;
1031     ^range_modifier{S} op->range_modifier = IVAL;
1032     ^dam_modifier{S} op->dam_modifier = IVAL;
1033     ^duration_modifier{S} op->duration_modifier = IVAL;
1034     ^is_buildable{S} SET_OR_CLEAR_FLAG( op, FLAG_IS_BUILDABLE, IVAL );
1035 root 1.1
1036 root 1.18 ^event_ {
1037 root 1.14 LOG (llevError, "stray event_* in map file, skipping.");
1038 root 1.1 }
1039    
1040 root 1.18 <*>(^{WS}$)|\n {/* ignore empty lines, newlines we don't do above */}
1041     #.*\n {}
1042 root 1.1
1043 root 1.18 <<EOF>> {/* If we got an error, return the error. Otherwise, return that we got EOF */
1044     if (lex_error!=0) return lex_error; else return LL_EOF;}
1045     .* { add_key_value(op); }
1046 root 1.1 %%
1047    
1048    
1049     int yyerror(char *s)
1050     {
1051     LOG(llevError, "%s: %s\n", s, yytext);
1052     return -1;
1053     }
1054    
1055    
1056     /* Our save file syntax is very simple, so we can use a very simple
1057     * processing mechanism here instead using something like bison
1058     * This skips over the space and returns the value, or "" if no value
1059     * is found. Modified 4/26/2000 to also strip spaces at end of
1060     * line
1061     */
1062     static char *yval()
1063     {
1064     static char *em="";
1065     char *cp,*end;
1066    
1067     /* First skip over start of line, like animation or name */
1068     for (cp=yytext; *cp!=' '; cp++) {
1069 root 1.18 if (*cp=='\0') {
1070     return em;
1071     }
1072 root 1.1 }
1073    
1074     /* Skip over whitespace */
1075     for (; *cp==' '; cp++) {
1076 root 1.18 if (*cp=='\0') {
1077     return em;
1078     }
1079 root 1.1 }
1080     /* Got last character before null and strip
1081     * off tailing whitespace
1082     */
1083     for (end=cp+strlen(cp)-1; *end==' '; end--) {
1084 root 1.18 if (end==cp) return em;
1085     *end='\0';
1086 root 1.1 }
1087     return cp;
1088     }
1089    
1090    
1091     /*
1092     * Loads an object from the given file-pointer.
1093     * Variables will be read and parsed and patched into the object
1094     * until the string "end" is reached, or the end of the file.
1095     *
1096     * bufstat is used to determine various file attributes:
1097     * LO_REPATE (0): We are reading from the same buffer as the last call.
1098     * LO_LINEMODE (1): file that is being read from is multi purpose (ie, other functions
1099 root 1.18 * will also be reading from this (treasure file, artifacts.)
1100 root 1.1 * LO_NEWFILE (2): This is the first read from a particular file, so the buffers should
1101 root 1.18 * be reset.
1102 root 1.1 * LO_NOREAD (3): Reset the buffers, but don't read from it. (op can be null)
1103     *
1104     */
1105    
1106 root 1.13 int load_object(object_thawer &fp, object *op, int bufstate, int map_flags) {
1107 root 1.1 int retval;
1108     char inbuf[MAX_BUF];
1109    
1110     strcpy(msgbuf, "");
1111     strcpy(lorebuf, "");
1112     if (bufstate==LO_NEWFILE || bufstate==LO_NOREAD) {
1113 root 1.18 /* LOG(llevDebug,"Switching lex buffers\n");*/
1114     yy_delete_buffer(YY_CURRENT_BUFFER);
1115     yy_switch_to_buffer(yy_create_buffer(fp, YY_BUF_SIZE));
1116     if (bufstate==LO_NOREAD) return LL_NORMAL;
1117 root 1.1 }
1118     if (bufstate==LO_LINEMODE) {
1119 root 1.18 YY_BUFFER_STATE yybufstate;
1120     while (fgets(inbuf, MAX_BUF-3, fp)) {
1121     yybufstate=yy_scan_string(inbuf);
1122     retval=lex_load(op, fp, map_flags);
1123     yy_delete_buffer(yybufstate);
1124     if (retval==LL_NORMAL) return retval;
1125     }
1126     LOG(llevDebug,"Got eof while scanning strings\n");
1127     return LL_EOF;
1128 root 1.1 }
1129    
1130 root 1.13 retval=lex_load(op, fp, map_flags);
1131 root 1.1
1132     /* LOG(llevDebug," load completed, object=%s\n",op->name);*/
1133     return retval;
1134     }
1135    
1136    
1137     /* This takes a buffer, scans it for variables, and sets those variables
1138     * as appropriate in op.
1139     *
1140     * This function appears to be used in only 2 places - in crossedit to
1141     * override values and in c_wiz to mutate values.
1142     */
1143     int set_variable(object *op,char *buf) {
1144     YY_BUFFER_STATE yybufstate,yycurbuf=YY_CURRENT_BUFFER;
1145     int retval;
1146 root 1.13 object_thawer thawer (0);
1147 root 1.1
1148     strcpy(msgbuf, "");
1149     strcpy(lorebuf, "");
1150     yy_push_state(INITIAL);
1151     yybufstate=yy_scan_string(buf);
1152 root 1.10 retval=lex_load(op,thawer,0);
1153 root 1.1 yy_switch_to_buffer(yycurbuf);
1154     yy_delete_buffer(yybufstate);
1155     yy_pop_state();
1156     return retval;
1157     }
1158    
1159     /* Start of C code */
1160    
1161     /* This array equates the FLAG_ values with the V_ values. Use -1 to
1162     * put gaps in the array that should not be processed.
1163     * The order matches the order of the define values in 'define.h'.
1164     */
1165     /* This is a list of pointers that correspond to the FLAG_.. values.
1166     * This is a simple 1:1 mapping - if FLAG_FRIENDLY is 15, then
1167     * the 15'th element of this array should match that name.
1168     * If an entry is NULL, that is a flag not to loaded/saved.
1169     */
1170 root 1.2 static const char *const flag_names[NUM_FLAGS+1] = {
1171 root 1.1 "alive", "wiz", NULL, NULL, "was_wiz", "applied", "unpaid",
1172     "can_use_shield", "no_pick", NULL /* walk_on*/, NULL /* no_pass */, /* 10 */
1173     "is_animated", NULL /* slow_move */,
1174     NULL /* flying */, "monster", "friendly", "generator",
1175     "is_thrown", "auto_apply", "treasure", "player sold", /* 20 */
1176     "see_invisible", "can_roll", "overlay_floor",
1177     "is_turnable", NULL /* walk_off */, NULL /* fly_on */,
1178 root 1.18 NULL /*fly_off*/, "is_used_up", "identified", "reflecting", /* 30 */
1179 root 1.1 "changing", "splitting", "hitback", "startequip",
1180     "blocksview", "undead", "scared", "unaggressive",
1181     "reflect_missile", "reflect_spell", /* 40 */
1182     "no_magic", "no_fix_player", "is_lightable", "tear_down",
1183     "run_away", NULL /*pass_thru */, NULL /*can_pass_thru*/,
1184 root 1.18 "pick_up", "unique", "no_drop", /* 50 */
1185 root 1.1 NULL /* wizcast*/, "can_cast_spell", "can_use_scroll", "can_use_range",
1186     "can_use_bow", "can_use_armour", "can_use_weapon",
1187     "can_use_ring", "has_ready_range", "has_ready_bow", /* 60 */
1188     "xrays", NULL, "is_floor", "lifesave", "no_strength", "sleep",
1189     "stand_still", "random_move", "only_attack", "confused", /* 70 */
1190     "stealth", NULL, NULL, "cursed", "damned",
1191     "see_anywhere", "known_magical", "known_cursed",
1192     "can_use_skill", "been_applied", /* 80 */
1193     "has_ready_scroll", "can_use_rod", NULL,
1194     "can_use_horn", "make_invisible", "inv_locked", "is_wooded",
1195     "is_hilly", "has_ready_skill", "has_ready_weapon", /* 90 */
1196     "no_skill_ident", "is_blind", "can_see_in_dark", "is_cauldron",
1197 root 1.18 "is_dust", "no_steal", "one_hit", NULL, "berserk", "neutral", /* 100 */
1198 root 1.1 "no_attack", "no_damage", NULL, NULL, "activate_on_push",
1199     "activate_on_release", "is_water", "use_content_on_gen", NULL, "is_buildable", /* 110 */
1200     NULL
1201     };
1202    
1203    
1204     /*
1205     * Initialises the array of variable-names. Needed before any
1206     * objects can be loaded. Called by init_library().
1207     */
1208    
1209     void init_vars() {
1210     }
1211    
1212 root 1.2 /* This returns a string of the integer movement type */
1213     static char* get_string_move_type(MoveType mt)
1214     {
1215 root 1.18 static char retbuf[MAX_BUF], retbuf_all[MAX_BUF];
1216 root 1.2 int i, all_count=0, count;
1217    
1218     strcpy(retbuf,"");
1219     strcpy(retbuf_all," all");
1220    
1221     /* Quick check, and probably fairly common */
1222     if (mt == MOVE_ALL) return retbuf_all+1;
1223     if (mt == 0) {
1224 root 1.18 strcpy(retbuf,"0");
1225     return retbuf;
1226 root 1.2 }
1227    
1228     /* We basically slide the bits down. Why look at MOVE_ALL?
1229     * because we may want to return a string like 'all -swim',
1230     * and if we just looked at mt, we couldn't get that.
1231     */
1232     for (i=MOVE_ALL, count=0; i!=0; i >>= 1, count++) {
1233 root 1.18 if (mt & (1<<count)) {
1234     strcat(retbuf, " ");
1235     strcat(retbuf, move_name[count]);
1236     } else {
1237     strcat(retbuf_all, " -");
1238     strcat(retbuf_all, move_name[count]);
1239     all_count++;
1240     }
1241 root 1.2 }
1242     /* Basically, if there is a single negation, return it, eg
1243     * 'all -swim'. But more than that, just return the
1244     * enumerated values. It doesn't make sense to return
1245     * 'all -walk -fly_low' - it is shorter to return 'fly_high swim'
1246     */
1247     if (all_count <=1) return retbuf_all+1;
1248     else return retbuf+1;
1249     }
1250    
1251    
1252 root 1.18 // compare *op against *tmp and output differences
1253     void
1254     put (object_freezer &f, object *op, object *tmp)
1255     {
1256 root 1.1 int i;
1257    
1258     /* This saves the key/value lists. We do it first so that any
1259     * keys that match field names will be overwritten by the loader.
1260     */
1261 root 1.18 for (key_value *my_field = op->key_values; my_field != NULL; my_field = my_field->next)
1262     {
1263 root 1.1 /* Find the field in the opposing member. */
1264 root 1.18 key_value *arch_field = get_ob_key_link (tmp, my_field->key);
1265    
1266 root 1.1 /* If there's no partnering field, or it's got a different value, save our field. */
1267 root 1.18 if (arch_field == NULL || my_field->value != arch_field->value)
1268     f.put (my_field->key, my_field->value);
1269     }
1270    
1271 root 1.1 /* We don't need to worry about the arch's extra fields - they
1272     * will get taken care of the copy_object function.
1273     */
1274    
1275 root 1.18 # 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 root 1.1
1278 root 1.18 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 ) f.put (KW_msg , KW_endmsg , op->msg);
1286     if (op->lore != tmp->lore) f.put (KW_lore, KW_endlore, op->lore);
1287    
1288     CMP_OUT (other_arch);
1289     CMP_OUT (face);
1290    
1291     if (op->animation_id != tmp->animation_id)
1292     if (op->animation_id)
1293     {
1294     f.put (KW_animation, animations[GET_ANIM_ID (op)].name);
1295    
1296     if (!QUERY_FLAG (op, FLAG_ANIMATE))
1297     f.put (KW_is_animated, 0);
1298 root 1.1 }
1299 root 1.18 else
1300     f.put (KW_animation, "NONE");
1301 root 1.1
1302 root 1.18 CMP_OUT2 (str , stats.Str);
1303     CMP_OUT2 (dex , stats.Dex);
1304     CMP_OUT2 (con , stats.Con);
1305     CMP_OUT2 (wis , stats.Wis);
1306     CMP_OUT2 (pow , stats.Pow);
1307     CMP_OUT2 (cha , stats.Cha);
1308     CMP_OUT2 (int , stats.Int);
1309     CMP_OUT2 (hp , stats.hp);
1310     CMP_OUT2 (maxhp , stats.maxhp);
1311     CMP_OUT2 (sp , stats.sp);
1312     CMP_OUT2 (maxsp , stats.maxsp);
1313     CMP_OUT2 (grace , stats.grace);
1314     CMP_OUT2 (maxgrace, stats.maxgrace);
1315     CMP_OUT2 (exp , stats.exp);
1316    
1317     CMP_OUT (perm_exp);
1318     CMP_OUT (expmul);
1319    
1320     CMP_OUT2 (food , stats.food);
1321     CMP_OUT2 (dam , stats.dam);
1322     CMP_OUT2 (luck , stats.luck);
1323     CMP_OUT2 (wc , stats.wc);
1324     CMP_OUT2 (ac , stats.ac);
1325    
1326     CMP_OUT (x);
1327     CMP_OUT (y);
1328     CMP_OUT (speed);
1329     CMP_OUT (speed_left);
1330     CMP_OUT2 (move_state, move_status);
1331     CMP_OUT (attack_movement);
1332     CMP_OUT (nrof);
1333     CMP_OUT (level);
1334     CMP_OUT (direction);
1335     CMP_OUT (type);
1336     CMP_OUT (subtype);
1337     CMP_OUT (attacktype);
1338    
1339     for (i = 0; i < NROFATTACKS; i++)
1340     if (op->resist [i] != tmp->resist [i])
1341     f.put (resist_save [i], op->resist [i]);
1342    
1343     CMP_OUT (path_attuned);
1344     CMP_OUT (path_repelled);
1345     CMP_OUT (path_denied);
1346     CMP_OUT (material);
1347     CMP_OUT (materialname);
1348     CMP_OUT (value);
1349     CMP_OUT (carrying);
1350     CMP_OUT (weight);
1351     CMP_OUT (invisible);
1352     CMP_OUT (state);
1353     CMP_OUT (magic);
1354     CMP_OUT (last_heal);
1355     CMP_OUT (last_sp);
1356     CMP_OUT (last_grace);
1357     CMP_OUT (last_eat);
1358     CMP_OUT (glow_radius);
1359    
1360     if (QUERY_FLAG (op, FLAG_IS_LINKED) && (i = get_button_value (op)))
1361     f.put (KW_connected, i);
1362    
1363     CMP_OUT (randomitems);
1364     CMP_OUT2 (container, weight_limit);
1365    
1366     CMP_OUT (run_away);
1367     CMP_OUT (pick_up);
1368     CMP_OUT (will_apply);
1369     CMP_OUT (smoothlevel);
1370     CMP_OUT (weapontype);
1371     CMP_OUT (tooltype);
1372     CMP_OUT (elevation);
1373     CMP_OUT (client_type);
1374     CMP_OUT (item_power);
1375     CMP_OUT (duration);
1376     CMP_OUT (range);
1377     CMP_OUT (range_modifier);
1378     CMP_OUT (duration_modifier);
1379     CMP_OUT (dam_modifier);
1380     CMP_OUT (gen_sp_armour);
1381    
1382     CMP_OUT (move_type);
1383     CMP_OUT (move_block);
1384     CMP_OUT (move_allow);
1385     CMP_OUT (move_on);
1386     CMP_OUT (move_off);
1387     CMP_OUT (move_slow);
1388     CMP_OUT (move_slow_penalty);
1389    
1390     if (!COMPARE_FLAGS (op, tmp))
1391     for (i = 0; i <= NUM_FLAGS; i++)
1392     if (flag_names [i]
1393     && (QUERY_FLAG (op, i) != QUERY_FLAG (tmp, i)))
1394     f.put (flag_names [i], QUERY_FLAG (op, i) ? "1" : 0);
1395    
1396     /* Save body locations */
1397     for (i = 0; i < NUM_BODY_LOCATIONS; i++)
1398     if (op->body_info[i] != tmp->body_info[i])
1399     f.put (body_locations[i].save_name, op->body_info[i]);
1400 root 1.1 }
1401    
1402     /*
1403     * Dumps all variables in an object to a file.
1404     * If bit 0 of flag is set, unpaid objects will be saved. As of now,
1405     * the only place this is not set is when saving the player.
1406     * If bit 1 of flag is set, don't remove the object after save. As of now,
1407     * all of the callers are setting this.
1408     */
1409    
1410 root 1.18 void
1411     save_object (object_freezer &fp, object *op, int flag)
1412     {
1413     archetype *at;
1414     object *tmp, *old;
1415 root 1.1
1416 root 1.18 /* Even if the object does have an owner, it would seem that we should
1417     * still save it.
1418     */
1419     if (op->owner != NULL)
1420     return;
1421 root 1.1
1422 root 1.18 /* If it is unpaid and we don't want to save those, just return. */
1423     if (!(flag & 1) && (QUERY_FLAG (op, FLAG_UNPAID)))
1424     return;
1425 root 1.1
1426 root 1.18 if ((at = op->arch) == NULL)
1427     at = empty_archetype;
1428 root 1.1
1429 root 1.18 fp.put (KW_arch, at->name);
1430 root 1.1
1431 root 1.18 put (fp, op, &at->clone);
1432 root 1.1
1433 root 1.18 /* Eneq(@csd.uu.se): Added this to allow containers being saved with contents */
1434 root 1.1
1435 root 1.18 old = NULL;
1436 root 1.1
1437 root 1.18 if (flag & 2)
1438     for (tmp = op->inv; tmp != NULL; tmp = tmp->below)
1439     save_object (fp, tmp, flag);
1440     else
1441 root 1.1 /* Slightly different logic because tmp/op will be removed by
1442     * the save_object we call. So we just keep looking at op->inv
1443     * until there is nothing left. In theory, the variable old
1444     * should not be needed, as recursive loops shouldn't happen.
1445     */
1446 root 1.18 while ((tmp = op->inv) != NULL)
1447     {
1448     if (old == tmp)
1449     {
1450     LOG (llevError, " Recursive loop in inventory\n");
1451     break;
1452     }
1453    
1454     save_object (fp, tmp, flag);
1455     old = tmp;
1456     }
1457    
1458     if (!(flag & 2))
1459     {
1460     remove_ob (op);
1461     free_object (op);
1462 root 1.1 }
1463    
1464 root 1.18 fp.put (op);
1465     fprintf (fp, "end\n");
1466 root 1.1 }
1467