ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/button.C
(Generate patch)

Comparing deliantra/server/common/button.C (file contents):
Revision 1.1 by elmex, Sun Aug 13 17:16:00 2006 UTC vs.
Revision 1.25 by elmex, Tue Jan 9 22:14:29 2007 UTC

1/*
2 * static char *rcsid_button_c =
3 * "$Id: button.C,v 1.1 2006/08/13 17:16:00 elmex Exp $";
4 */
5
6/* 1/*
7 CrossFire, A Multiplayer game for X-windows 2 CrossFire, A Multiplayer game for X-windows
8 3
4 Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
9 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 5 Copyright (C) 2002 Mark Wedel & Crossfire Development Team
10 Copyright (C) 1992 Frank Tore Johansen 6 Copyright (C) 1992 Frank Tore Johansen
11 7
12 This program is free software; you can redistribute it and/or modify 8 This program is free software; you can redistribute it and/or modify
13 it under the terms of the GNU General Public License as published by 9 it under the terms of the GNU General Public License as published by
21 17
22 You should have received a copy of the GNU General Public License 18 You should have received a copy of the GNU General Public License
23 along with this program; if not, write to the Free Software 19 along with this program; if not, write to the Free Software
24 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 21
26 The authors can be reached via e-mail at crossfire-devel@real-time.com 22 The authors can be reached via e-mail at <crossfire@schmorp.de>
27*/ 23*/
28 24
29#include <global.h> 25#include <global.h>
30#include <funcpoint.h> 26#include <funcpoint.h>
31 27
32/* 28/*
33 * This code is no longer highly inefficient 8) 29 * This code is no longer highly inefficient 8)
34 */ 30 */
35 31
36/* 32/*
33 * elmex:
34 * This function takes a objectlink list with all the objects are going to be activated.
35 * state is a true/false flag that will actiavte objects that have FLAG_ACTIVATE_ON_PUSH/RELEASE set.
36 * The source argument can be 0 or the source object for this activation.
37 */
38void
39activate_connection_link (objectlink * ol, bool state, object *source = 0)
40{
41 for (; ol; ol = ol->next)
42 {
43 if (!ol->ob)
44 {
45 LOG (llevError, "Internal error in activate_connection_link.\n");
46 continue;
47 }
48
49 /* a button link object can become freed when the map is saving. As
50 * a map is saved, objects are removed and freed, and if an object is
51 * on top of a button, this function is eventually called. If a map
52 * is getting moved out of memory, the status of buttons and levers
53 * probably isn't important - it will get sorted out when the map is
54 * re-loaded. As such, just exit this function if that is the case.
55 */
56
57 if (QUERY_FLAG (ol->ob, FLAG_FREED))
58 return;
59
60 object *tmp = ol->ob;
61
62 /* if the criteria isn't appropriate, don't do anything */
63 if (state && !QUERY_FLAG (tmp, FLAG_ACTIVATE_ON_PUSH))
64 continue;
65 if (!state && !QUERY_FLAG (tmp, FLAG_ACTIVATE_ON_RELEASE))
66 continue;
67
68 switch (tmp->type)
69 {
70 case GATE:
71 case HOLE:
72 tmp->value = tmp->stats.maxsp ? !state : state;
73 tmp->set_speed (0.5);
74 break;
75
76 case CF_HANDLE:
77 SET_ANIMATION (tmp, (tmp->value = tmp->stats.maxsp ? !state : state));
78 update_object (tmp, UP_OBJ_FACE);
79 break;
80
81 case SIGN:
82 if (!tmp->stats.food || tmp->last_eat < tmp->stats.food)
83 {
84 new_info_map (NDI_UNIQUE | NDI_NAVY, tmp->map, tmp->msg);
85 if (tmp->stats.food)
86 tmp->last_eat++;
87 }
88 break;
89
90 case ALTAR:
91 tmp->value = 1;
92 SET_ANIMATION (tmp, tmp->value);
93 update_object (tmp, UP_OBJ_FACE);
94 break;
95
96 case BUTTON:
97 case PEDESTAL:
98 tmp->value = state;
99 SET_ANIMATION (tmp, tmp->value);
100 update_object (tmp, UP_OBJ_FACE);
101 break;
102
103 case MOOD_FLOOR:
104 do_mood_floor (tmp, source);
105 break;
106
107 case TIMED_GATE:
108 tmp->set_speed (tmp->arch->clone.speed);
109 tmp->value = tmp->arch->clone.value;
110 tmp->stats.sp = 1;
111 tmp->stats.hp = tmp->stats.maxhp;
112 /* Handle multipart gates. We copy the value for the other parts
113 * from the head - this ensures that the data will consistent
114 */
115 for (tmp = tmp->more; tmp; tmp = tmp->more)
116 {
117 tmp->value = tmp->head->value;
118 tmp->stats.sp = tmp->head->stats.sp;
119 tmp->stats.hp = tmp->head->stats.hp;
120 tmp->set_speed (tmp->head->speed);
121 }
122 break;
123
124 case DIRECTOR:
125 case FIREWALL:
126 if (!QUERY_FLAG (tmp, FLAG_ANIMATE) && tmp->type == FIREWALL)
127 move_firewall (tmp);
128 else
129 {
130 if ((tmp->stats.sp += tmp->stats.maxsp) > 8) /* next direction */
131 tmp->stats.sp = ((tmp->stats.sp - 1) % 8) + 1;
132 animate_turning (tmp);
133 }
134 break;
135
136 case TELEPORTER:
137 move_teleporter (tmp);
138 break;
139
140 case CREATOR:
141 move_creator (tmp);
142 break;
143
144 case TRIGGER_MARKER:
145 move_marker (tmp);
146 break;
147
148 case DUPLICATOR:
149 move_duplicator (tmp);
150 break;
151 }
152 }
153}
154
155/*
156 * elmex:
157 * This is the new push_button function, it got split up so that
158 * you can activate connections without a button now!
159 * old but still valid comment:
160 *
37 * Push the specified object. This can affect other buttons/gates/handles 161 * Push the specified object. This can affect other buttons/gates/handles
38 * altars/pedestals/holes in the whole map. 162 * altars/pedestals/holes in the whole map.
39 * Changed the routine to loop through _all_ objects. 163 * Changed the routine to loop through _all_ objects.
40 * Better hurry with that linked list... 164 * Better hurry with that linked list...
41 */ 165 *
42
43void push_button(object *op) {
44 object *tmp;
45 objectlink *ol;
46
47/* LOG(llevDebug, "push_button: %s (%d)\n", op->name, op->count); */
48 for (ol = get_button_links(op); ol; ol = ol->next) {
49 if (!ol->ob || ol->ob->count != ol->id) {
50 LOG(llevError, "Internal error in push_button (%s).\n", op->name);
51 continue;
52 }
53 /* a button link object can become freed when the map is saving. As
54 * a map is saved, objects are removed and freed, and if an object is
55 * on top of a button, this function is eventually called. If a map
56 * is getting moved out of memory, the status of buttons and levers
57 * probably isn't important - it will get sorted out when the map is
58 * re-loaded. As such, just exit this function if that is the case.
59 */ 166 */
60 167void
61 if (QUERY_FLAG(ol->ob, FLAG_FREED)) return; 168push_button (object *op)
62 tmp = ol->ob; 169{
170 oblinkpt *obp = get_button_links (op);
63 171
64 /* if the criteria isn't appropriate, don't do anything */ 172 if (!obp)
65 if (op->value && !QUERY_FLAG(tmp, FLAG_ACTIVATE_ON_PUSH)) continue; 173 return;
66 if (!op->value && !QUERY_FLAG(tmp, FLAG_ACTIVATE_ON_RELEASE)) continue;
67 174
68 switch(tmp->type) { 175 if (INVOKE_MAP (TRIGGER, op->map, ARG_INT64 (obp->value), ARG_INT (op->value)))
176 return;
69 177
70 case GATE: 178 activate_connection_link (obp->link, op->value, op);
71 case HOLE: 179}
72 tmp->value=tmp->stats.maxsp?!op->value:op->value;
73 tmp->speed=0.5;
74 update_ob_speed(tmp);
75 break;
76 180
77 case CF_HANDLE: 181/*
78 SET_ANIMATION(tmp, (tmp->value=tmp->stats.maxsp?!op->value:op->value)); 182 * elmex:
79 update_object(tmp,UP_OBJ_FACE); 183 * This activates a connection, similar to push_button (object *op) but it takes
80 break; 184 * only a map, a connection value and a true or false flag that indicated whether
81 185 * the connection was 'state' or 'released'. So that you can activate objects
82 case SIGN: 186 * who have FLAG_ACTIVATE_ON_PUSH/RELEASE set properly.
83 if (!tmp->stats.food || tmp->last_eat < tmp->stats.food) { 187 *
84 new_info_map(NDI_UNIQUE | NDI_NAVY,tmp->map,tmp->msg);
85 if (tmp->stats.food) tmp->last_eat++;
86 }
87 break;
88
89 case ALTAR:
90 tmp->value = 1;
91 SET_ANIMATION(tmp, tmp->value);
92 update_object(tmp,UP_OBJ_FACE);
93 break;
94
95 case BUTTON:
96 case PEDESTAL:
97 tmp->value=op->value;
98 SET_ANIMATION(tmp, tmp->value);
99 update_object(tmp,UP_OBJ_FACE);
100 break;
101
102 case MOOD_FLOOR:
103 do_mood_floor(tmp, op);
104 break;
105
106 case TIMED_GATE:
107 tmp->speed = tmp->arch->clone.speed;
108 update_ob_speed(tmp); /* original values */
109 tmp->value = tmp->arch->clone.value;
110 tmp->stats.sp = 1;
111 tmp->stats.hp = tmp->stats.maxhp;
112 /* Handle multipart gates. We copy the value for the other parts
113 * from the head - this ensures that the data will consistent
114 */ 188 */
115 for (tmp=tmp->more; tmp!=NULL; tmp=tmp->more) { 189void
116 tmp->speed = tmp->head->speed; 190activate_connection (maptile *map, long connection, bool state)
117 tmp->value = tmp->head->value; 191{
118 tmp->stats.sp = tmp->head->stats.sp; 192 if (INVOKE_MAP (TRIGGER, map, ARG_INT64 (connection), ARG_INT (state)))
119 tmp->stats.hp = tmp->head->stats.hp; 193 return;
120 update_ob_speed(tmp);
121 }
122 break;
123 194
124 case DIRECTOR: 195 oblinkpt *obp = get_connection_links (map, connection);
125 case FIREWALL:
126 if(!QUERY_FLAG(tmp,FLAG_ANIMATE)&&tmp->type==FIREWALL) move_firewall(tmp);
127 else {
128 if ((tmp->stats.sp += tmp->stats.maxsp) > 8) /* next direction */
129 tmp->stats.sp = ((tmp->stats.sp-1)%8)+1;
130 animate_turning(tmp);
131 }
132 break;
133 196
134 case TELEPORTER: 197 if (obp)
135 move_teleporter(tmp); 198 activate_connection_link (obp->link, state);
136 break;
137
138 case CREATOR:
139 move_creator(tmp);
140 break;
141
142 case TRIGGER_MARKER:
143 move_marker(tmp);
144 break;
145
146 case DUPLICATOR:
147 move_duplicator(tmp);
148 break;
149 }
150 }
151} 199}
152 200
153/* 201/*
154 * Updates everything connected with the button op. 202 * Updates everything connected with the button op.
155 * After changing the state of a button, this function must be called 203 * After changing the state of a button, this function must be called
156 * to make sure that all gates and other buttons connected to the 204 * to make sure that all gates and other buttons connected to the
157 * button reacts to the (eventual) change of state. 205 * button reacts to the (eventual) change of state.
158 */ 206 */
159 207void
160void update_button(object *op) { 208update_button (object *op)
209{
161 object *ab,*tmp,*head; 210 object *ab, *tmp, *head;
162 int tot,any_down=0, old_value=op->value; 211 int tot, any_down = 0, old_value = op->value;
163 objectlink *ol; 212 oblinkpt *obp = 0;
164
165 /* LOG(llevDebug, "update_button: %s (%d)\n", op->name, op->count); */
166 for (ol = get_button_links(op); ol; ol = ol->next) {
167 if (!ol->ob || ol->ob->count != ol->id) {
168 LOG(llevDebug, "Internal error in update_button (%s).\n", op->name);
169 continue;
170 }
171 tmp = ol->ob;
172 if (tmp->type==BUTTON) {
173 for(ab=tmp->above,tot=0;ab!=NULL;ab=ab->above)
174 /* Bug? The pedestal code below looks for the head of
175 * the object, this bit doesn't. I'd think we should check
176 * for head here also. Maybe it also makese sense to
177 * make the for ab=tmp->above loop common, and alter
178 * behaviour based on object within that loop?
179 */
180
181 /* Basically, if the move_type matches that on what the
182 * button wants, we count it. The second check is so that
183 * objects don't move (swords, etc) will count. Note that
184 * this means that more work is needed to make buttons
185 * that are only triggered by flying objects.
186 */
187 if ((ab->move_type & tmp->move_on) || ab->move_type==0 )
188 tot+=ab->weight*(ab->nrof?ab->nrof:1)+ab->carrying;
189
190 tmp->value=(tot>=tmp->weight)?1:0;
191 if(tmp->value)
192 any_down=1;
193 } else if (tmp->type == PEDESTAL) {
194 tmp->value = 0;
195 for(ab=tmp->above; ab!=NULL; ab=ab->above) {
196 head = ab->head ? ab->head : ab;
197 /* Same note regarding move_type for buttons above apply here. */
198 if ( ((head->move_type & tmp->move_on) || ab->move_type==0) &&
199 (head->race==tmp->slaying ||
200 ((head->type==SPECIAL_KEY) && (head->slaying==tmp->slaying)) ||
201 (!strcmp (tmp->slaying, "player") &&
202 head->type == PLAYER)))
203 tmp->value = 1;
204 }
205 if(tmp->value)
206 any_down=1;
207 }
208 }
209 if(any_down) /* If any other buttons were down, force this to remain down */
210 op->value=1;
211
212 /* If this button hasn't changed, don't do anything */
213 if (op->value != old_value) {
214 SET_ANIMATION(op, op->value);
215 update_object(op, UP_OBJ_FACE);
216 push_button(op); /* Make all other buttons the same */
217 }
218}
219
220/*
221 * Updates every button on the map (by calling update_button() for them).
222 */
223
224void update_buttons(mapstruct *m) {
225 objectlink *ol; 213 objectlink *ol;
226 oblinkpt *obp; 214
227 for (obp = m->buttons; obp; obp = obp->next) 215 obp = get_button_links (op);
216 /* LOG(llevDebug, "update_button: %s (%d)\n", op->name, op->count); */
217 if (obp)
228 for (ol = obp->link; ol; ol = ol->next) { 218 for (ol = obp->link; ol; ol = ol->next)
229 if (!ol->ob || ol->ob->count != ol->id) { 219 {
230 LOG(llevError, "Internal error in update_button (%s (%dx%d):%d, connected %ld).\n", 220 if (!ol->ob)
231 ol->ob?ol->ob->name:"null", 221 {
232 ol->ob?ol->ob->x:-1, 222 LOG (llevDebug, "Internal error in update_button (%s).\n", &op->name);
233 ol->ob?ol->ob->y:-1,
234 ol->id,
235 obp->value);
236 continue; 223 continue;
224 }
225
226 tmp = ol->ob;
227 if (tmp->type == BUTTON)
228 {
229 for (ab = tmp->above, tot = 0; ab != NULL; ab = ab->above)
230 /* Bug? The pedestal code below looks for the head of
231 * the object, this bit doesn't. I'd think we should check
232 * for head here also. Maybe it also makese sense to
233 * make the for ab=tmp->above loop common, and alter
234 * behaviour based on object within that loop?
235 */
236
237 /* Basically, if the move_type matches that on what the
238 * button wants, we count it. The second check is so that
239 * objects don't move (swords, etc) will count. Note that
240 * this means that more work is needed to make buttons
241 * that are only triggered by flying objects.
242 */
243 if ((ab->move_type & tmp->move_on) || ab->move_type == 0)
244 tot += ab->weight * (ab->nrof ? ab->nrof : 1) + ab->carrying;
245
246 tmp->value = (tot >= tmp->weight) ? 1 : 0;
247 if (tmp->value)
248 any_down = 1;
249 }
250 else if (tmp->type == PEDESTAL)
251 {
252 tmp->value = 0;
253 for (ab = tmp->above; ab != NULL; ab = ab->above)
254 {
255 head = ab->head ? ab->head : ab;
256 /* Same note regarding move_type for buttons above apply here. */
257 if (((head->move_type & tmp->move_on) || ab->move_type == 0) &&
258 (head->race == tmp->slaying ||
259 ((head->type == SPECIAL_KEY) && (head->slaying == tmp->slaying)) ||
260 (!strcmp (tmp->slaying, "player") && head->type == PLAYER)))
261 tmp->value = 1;
262 }
263 if (tmp->value)
264 any_down = 1;
265 }
237 } 266 }
238 if (ol->ob->type==BUTTON || ol->ob->type==PEDESTAL) 267 if (any_down) /* If any other buttons were down, force this to remain down */
268 op->value = 1;
269
270 /* If this button hasn't changed, don't do anything */
271 if (op->value != old_value)
239 { 272 {
240 update_button(ol->ob); 273 SET_ANIMATION (op, op->value);
241 break; 274 update_object (op, UP_OBJ_FACE);
275 push_button (op); /* Make all other buttons the same */
242 } 276 }
243 }
244} 277}
245 278
279void
246void use_trigger(object *op) 280use_trigger (object *op)
247{ 281{
248
249 /* Toggle value */ 282 /* Toggle value */
250 op->value = !op->value; 283 op->value = !op->value;
251 push_button(op); 284 push_button (op);
252} 285}
253 286
254/* 287/*
255 * Note: animate_object should be used instead of this, 288 * Note: animate_object should be used instead of this,
256 * but it can't handle animations in the 8 directions 289 * but it can't handle animations in the 8 directions
257 */ 290 */
258 291void
259void animate_turning(object *op) /* only one part objects */ 292animate_turning (object *op) /* only one part objects */
260{ 293{
261 if (++op->state >= NUM_ANIMATIONS(op)/8) 294 if (++op->state >= NUM_ANIMATIONS (op) / 8)
262 op->state=0; 295 op->state = 0;
263 SET_ANIMATION(op, (op->stats.sp-1) * NUM_ANIMATIONS(op) / 8 + 296 SET_ANIMATION (op, (op->stats.sp - 1) * NUM_ANIMATIONS (op) / 8 + op->state);
264 op->state);
265 update_object(op,UP_OBJ_FACE); 297 update_object (op, UP_OBJ_FACE);
266} 298}
267 299
268#define ARCH_SACRIFICE(xyz) ((xyz)->slaying) 300#define ARCH_SACRIFICE(xyz) ((xyz)->slaying)
269#define NROF_SACRIFICE(xyz) ((uint32)(xyz)->stats.food) 301#define NROF_SACRIFICE(xyz) ((uint32)(xyz)->stats.food)
270 302
276 * 308 *
277 * 0.93.4: Linked objects (ie, objects that are connected) can not be 309 * 0.93.4: Linked objects (ie, objects that are connected) can not be
278 * sacrificed. This fixes a bug of trying to put multiple altars/related 310 * sacrificed. This fixes a bug of trying to put multiple altars/related
279 * objects on the same space that take the same sacrifice. 311 * objects on the same space that take the same sacrifice.
280 */ 312 */
281 313
314int
282int check_altar_sacrifice (const object *altar, const object *sacrifice) 315check_altar_sacrifice (const object *altar, const object *sacrifice)
283{ 316{
284 if ( ! QUERY_FLAG (sacrifice, FLAG_ALIVE) 317 if (!QUERY_FLAG (sacrifice, FLAG_ALIVE) && !QUERY_FLAG (sacrifice, FLAG_IS_LINKED) && sacrifice->type != PLAYER)
285 && ! QUERY_FLAG (sacrifice, FLAG_IS_LINKED)
286 && sacrifice->type != PLAYER)
287 { 318 {
288 if ((ARCH_SACRIFICE(altar) == sacrifice->arch->name || 319 if ((ARCH_SACRIFICE (altar) == sacrifice->arch->name ||
289 ARCH_SACRIFICE(altar) == sacrifice->name || 320 ARCH_SACRIFICE (altar) == sacrifice->name ||
290 ARCH_SACRIFICE(altar) == sacrifice->slaying || 321 ARCH_SACRIFICE (altar) == sacrifice->slaying ||
291 (!strcmp(ARCH_SACRIFICE(altar),query_base_name(sacrifice,0)))) 322 (!strcmp (ARCH_SACRIFICE (altar), query_base_name (sacrifice, 0))))
292 && NROF_SACRIFICE(altar) <= (sacrifice->nrof?sacrifice->nrof:1)) 323 && NROF_SACRIFICE (altar) <= (sacrifice->nrof ? sacrifice->nrof : 1))
293 return 1; 324 return 1;
325
294 if (strcmp (ARCH_SACRIFICE(altar), "money") == 0 326 if (strcmp (ARCH_SACRIFICE (altar), "money") == 0
295 && sacrifice->type == MONEY
296 && sacrifice->nrof * sacrifice->value >= NROF_SACRIFICE(altar)) 327 && sacrifice->type == MONEY && sacrifice->nrof * sacrifice->value >= NROF_SACRIFICE (altar))
297 return 1; 328 return 1;
298 } 329 }
330
299 return 0; 331 return 0;
300} 332}
301
302 333
303/* 334/*
304 * operate_altar checks if sacrifice was accepted and removes sacrificed 335 * operate_altar checks if sacrifice was accepted and removes sacrificed
305 * objects. If sacrifice was succeed return 1 else 0. Might be better to 336 * objects. If sacrifice was succeed return 1 else 0. Might be better to
306 * call check_altar_sacrifice (above) than depend on the return value, 337 * call check_altar_sacrifice (above) than depend on the return value,
307 * since operate_altar will remove the sacrifice also. 338 * since operate_altar will remove the sacrifice also.
308 * 339 *
309 * If this function returns 1, '*sacrifice' is modified to point to the 340 * If this function returns 1, '*sacrifice' is modified to point to the
310 * remaining sacrifice, or is set to NULL if the sacrifice was used up. 341 * remaining sacrifice, or is set to NULL if the sacrifice was used up.
311 */ 342 */
312 343int
313int operate_altar (object *altar, object **sacrifice) 344operate_altar (object *altar, object **sacrifice)
314{ 345{
315
316 if ( ! altar->map) { 346 if (!altar->map)
347 {
317 LOG (llevError, "BUG: operate_altar(): altar has no map\n"); 348 LOG (llevError, "BUG: operate_altar(): altar has no map\n");
318 return 0; 349 return 0;
319 } 350 }
320 351
321 if (!altar->slaying || altar->value) 352 if (!altar->slaying || altar->value)
322 return 0; 353 return 0;
323 354
324 if ( ! check_altar_sacrifice (altar, *sacrifice)) 355 if (!check_altar_sacrifice (altar, *sacrifice))
325 return 0; 356 return 0;
326 357
327 /* check_altar_sacrifice should have already verified that enough money 358 /* check_altar_sacrifice should have already verified that enough money
328 * has been dropped. 359 * has been dropped.
329 */ 360 */
330 if (!strcmp(ARCH_SACRIFICE(altar), "money")) { 361 if (!strcmp (ARCH_SACRIFICE (altar), "money"))
362 {
331 int number=NROF_SACRIFICE(altar) / (*sacrifice)->value; 363 int number = NROF_SACRIFICE (altar) / (*sacrifice)->value;
332 364
333 /* Round up any sacrifices. Altars don't make change either */ 365 /* Round up any sacrifices. Altars don't make change either */
334 if (NROF_SACRIFICE(altar) % (*sacrifice)->value) number++; 366 if (NROF_SACRIFICE (altar) % (*sacrifice)->value)
367 number++;
368
335 *sacrifice = decrease_ob_nr (*sacrifice, number); 369 *sacrifice = decrease_ob_nr (*sacrifice, number);
336 } 370 }
337 else 371 else
338 *sacrifice = decrease_ob_nr (*sacrifice, NROF_SACRIFICE(altar)); 372 *sacrifice = decrease_ob_nr (*sacrifice, NROF_SACRIFICE (altar));
339 373
340 if (altar->msg) 374 if (altar->msg)
341 new_info_map(NDI_BLACK, altar->map, altar->msg); 375 new_info_map (NDI_BLACK, altar->map, altar->msg);
376
342 return 1; 377 return 1;
343} 378}
344 379
380void
345void trigger_move (object *op, int state) /* 1 down and 0 up */ 381trigger_move (object *op, int state) /* 1 down and 0 up */
346{ 382{
347 op->stats.wc = state; 383 op->stats.wc = state;
348 if (state) { 384 if (state)
349 use_trigger(op); 385 {
350 if (op->stats.exp > 0) /* check sanity */
351 op->speed = 1.0 / op->stats.exp;
352 else
353 op->speed = 1.0;
354 update_ob_speed(op);
355 op->speed_left = -1;
356 } else {
357 use_trigger(op); 386 use_trigger (op);
358 op->speed = 0; 387 op->set_speed (op->stats.exp > 0 ? 1. / op->stats.exp : 1.);
359 update_ob_speed(op); 388 op->speed_left = -1;
389 }
390 else
391 {
392 use_trigger (op);
393 op->set_speed (0);
360 } 394 }
361} 395}
362 396
363 397
364/* 398/*
371 * 405 *
372 * TRIGGER: Returns 1 if handle could be moved, 0 if not. 406 * TRIGGER: Returns 1 if handle could be moved, 0 if not.
373 * 407 *
374 * TRIGGER_BUTTON, TRIGGER_PEDESTAL: Returns 0. 408 * TRIGGER_BUTTON, TRIGGER_PEDESTAL: Returns 0.
375 */ 409 */
410int
376int check_trigger (object *op, object *cause) 411check_trigger (object *op, object *cause)
377{ 412{
378 object *tmp; 413 object *tmp;
379 int push = 0, tot = 0; 414 int push = 0, tot = 0;
380 int in_movement = op->stats.wc || op->speed; 415 int in_movement = op->stats.wc || op->speed;
381 416
382 switch (op->type) { 417 switch (op->type)
418 {
383 case TRIGGER_BUTTON: 419 case TRIGGER_BUTTON:
384 if (op->weight > 0) { 420 if (op->weight > 0)
385 if (cause) { 421 {
422 if (cause)
423 {
386 for (tmp = op->above; tmp; tmp = tmp->above) 424 for (tmp = op->above; tmp; tmp = tmp->above)
387 /* Comment reproduced from update_buttons(): */ 425 /* Comment reproduced from update_buttons(): */
388 /* Basically, if the move_type matches that on what the 426 /* Basically, if the move_type matches that on what the
389 * button wants, we count it. The second check is so that 427 * button wants, we count it. The second check is so that
390 * objects that don't move (swords, etc) will count. Note that 428 * objects that don't move (swords, etc) will count. Note that
391 * this means that more work is needed to make buttons 429 * this means that more work is needed to make buttons
392 * that are only triggered by flying objects. 430 * that are only triggered by flying objects.
393 */ 431 */
394 432
395 if ((tmp->move_type & op->move_on) || tmp->move_type==0) { 433 if ((tmp->move_type & op->move_on) || tmp->move_type == 0)
396 tot += tmp->weight * (tmp->nrof ? tmp->nrof : 1) 434 {
397 + tmp->carrying; 435 tot += tmp->weight * (tmp->nrof ? tmp->nrof : 1) + tmp->carrying;
398 } 436 }
399 if (tot >= op->weight) 437 if (tot >= op->weight)
400 push = 1; 438 push = 1;
401 if (op->stats.ac == push) 439 if (op->stats.ac == push)
402 return 0; 440 return 0;
403 op->stats.ac = push; 441 op->stats.ac = push;
404 if (NUM_ANIMATIONS(op) > 1) { 442 if (NUM_ANIMATIONS (op) > 1)
443 {
405 SET_ANIMATION (op, push); 444 SET_ANIMATION (op, push);
406 update_object (op, UP_OBJ_FACE); 445 update_object (op, UP_OBJ_FACE);
407 } 446 }
408 if (in_movement || ! push) 447 if (in_movement || !push)
409 return 0; 448 return 0;
410 }
411 trigger_move (op, push);
412 }
413 return 0;
414
415 case TRIGGER_PEDESTAL:
416 if (cause) {
417 for (tmp = op->above; tmp; tmp = tmp->above) {
418 object *head = tmp->head ? tmp->head : tmp;
419
420 /* See comment in TRIGGER_BUTTON about move_types */
421 if (((head->move_type & op->move_on) || head->move_type==0)
422 && (head->race==op->slaying ||
423 (!strcmp (op->slaying, "player") && head->type == PLAYER))) {
424 push = 1;
425 break;
426 }
427 }
428 if (op->stats.ac == push)
429 return 0;
430 op->stats.ac = push;
431 if (NUM_ANIMATIONS(op) > 1) {
432 SET_ANIMATION (op, push);
433 update_object (op, UP_OBJ_FACE);
434 } 449 }
435 update_object(op,UP_OBJ_FACE);
436 if (in_movement || ! push)
437 return 0;
438 }
439 trigger_move (op, push); 450 trigger_move (op, push);
451 }
440 return 0; 452 return 0;
441 453
442 case TRIGGER_ALTAR: 454 case TRIGGER_PEDESTAL:
443 if (cause) { 455 if (cause)
444 if (in_movement) 456 {
445 return 0; 457 for (tmp = op->above; tmp; tmp = tmp->above)
446 if (operate_altar (op, &cause)) { 458 {
447 if (NUM_ANIMATIONS(op) > 1) { 459 object *head = tmp->head ? tmp->head : tmp;
448 SET_ANIMATION (op, 1); 460
449 update_object(op, UP_OBJ_FACE); 461 /* See comment in TRIGGER_BUTTON about move_types */
462 if (((head->move_type & op->move_on) || head->move_type == 0)
463 && (head->race == op->slaying || (!strcmp (op->slaying, "player") && head->type == PLAYER)))
464 {
465 push = 1;
466 break;
450 } 467 }
451 if (op->last_sp >= 0) {
452 trigger_move (op, 1);
453 if (op->last_sp > 0)
454 op->last_sp = -op->last_sp;
455 }
456 else {
457 /* for trigger altar with last_sp, the ON/OFF
458 * status (-> +/- value) is "simulated":
459 */
460 op->value = !op->value;
461 trigger_move (op, 1);
462 op->last_sp = -op->last_sp;
463 op->value = !op->value;
464 }
465 return cause == NULL;
466 } else {
467 return 0;
468 }
469 } else {
470 if (NUM_ANIMATIONS(op) > 1) {
471 SET_ANIMATION (op, 0);
472 update_object(op, UP_OBJ_FACE);
473 } 468 }
474 469 if (op->stats.ac == push)
475 /* If trigger_altar has "last_sp > 0" set on the map, 470 return 0;
476 * it will push the connected value only once per sacrifice. 471 op->stats.ac = push;
477 * Otherwise (default), the connected value will be
478 * pushed twice: First by sacrifice, second by reset! -AV
479 */
480 if (!op->last_sp)
481 trigger_move (op, 0);
482 else {
483 op->stats.wc = 0;
484 op->value = !op->value;
485 op->speed = 0;
486 update_ob_speed(op);
487 }
488 }
489 return 0;
490
491 case TRIGGER:
492 if (cause) {
493 if (in_movement)
494 return 0;
495 push = 1;
496 }
497 if (NUM_ANIMATIONS(op) > 1) { 472 if (NUM_ANIMATIONS (op) > 1)
473 {
498 SET_ANIMATION (op, push); 474 SET_ANIMATION (op, push);
499 update_object(op, UP_OBJ_FACE); 475 update_object (op, UP_OBJ_FACE);
476 }
477 update_object (op, UP_OBJ_FACE);
478 if (in_movement || !push)
479 return 0;
500 } 480 }
501 trigger_move (op, push); 481 trigger_move (op, push);
482 return 0;
483
484 case TRIGGER_ALTAR:
485 if (cause)
486 {
487 if (in_movement)
488 return 0;
489 if (operate_altar (op, &cause))
490 {
491 if (NUM_ANIMATIONS (op) > 1)
492 {
493 SET_ANIMATION (op, 1);
494 update_object (op, UP_OBJ_FACE);
495 }
496 if (op->last_sp >= 0)
497 {
498 trigger_move (op, 1);
499 if (op->last_sp > 0)
500 op->last_sp = -op->last_sp;
501 }
502 else
503 {
504 /* for trigger altar with last_sp, the ON/OFF
505 * status (-> +/- value) is "simulated":
506 */
507 op->value = !op->value;
508 trigger_move (op, 1);
509 op->last_sp = -op->last_sp;
510 op->value = !op->value;
511 }
512 return cause == NULL;
513 }
514 else
515 {
516 return 0;
517 }
518 }
519 else
520 {
521 if (NUM_ANIMATIONS (op) > 1)
522 {
523 SET_ANIMATION (op, 0);
524 update_object (op, UP_OBJ_FACE);
525 }
526
527 /* If trigger_altar has "last_sp > 0" set on the map,
528 * it will push the connected value only once per sacrifice.
529 * Otherwise (default), the connected value will be
530 * pushed twice: First by sacrifice, second by reset! -AV
531 */
532 if (!op->last_sp)
533 trigger_move (op, 0);
534 else
535 {
536 op->stats.wc = 0;
537 op->value = !op->value;
538 op->set_speed (0);
539 }
540 }
541 return 0;
542
543 case TRIGGER:
544 if (cause)
545 {
546 if (in_movement)
547 return 0;
548
549 push = 1;
550 }
551
552 if (NUM_ANIMATIONS (op) > 1)
553 {
554 SET_ANIMATION (op, push);
555 update_object (op, UP_OBJ_FACE);
556 }
557
558 trigger_move (op, push);
502 return 1; 559 return 1;
503 560
504 default: 561 default:
505 LOG(llevDebug, "Unknown trigger type: %s (%d)\n", op->name, op->type); 562 LOG (llevDebug, "Unknown trigger type: %s (%d)\n", &op->name, op->type);
506 return 0; 563 return 0;
507 } 564 }
508} 565}
509 566
567void
510void add_button_link(object *button, mapstruct *map, int connected) { 568add_button_link (object *button, maptile *map, int connected)
569{
511 oblinkpt *obp; 570 oblinkpt *obp;
512 objectlink *ol = get_objectlink(); 571 objectlink *ol = get_objectlink ();
513 572
514 if (!map) { 573 if (!map)
574 {
515 LOG(llevError, "Tried to add button-link without map.\n"); 575 LOG (llevError, "Tried to add button-link without map.\n");
516 return; 576 return;
517 } 577 }
578
518 if (!editor) button->path_attuned = connected; /* peterm: I need this so I can rebuild 579 button->path_attuned = connected; /* peterm: I need this so I can rebuild
519 a connected map from a template map. */ 580 a connected map from a template map. */
520/* LOG(llevDebug,"adding button %s (%d)\n", button->name, connected);*/
521 581
522 SET_FLAG(button,FLAG_IS_LINKED); 582 SET_FLAG (button, FLAG_IS_LINKED);
523 583
524 ol->ob = button; 584 ol->ob = button;
525 ol->id = button->count;
526 585
527 for (obp = map->buttons; obp && obp->value != connected; obp = obp->next); 586 for (obp = map->buttons; obp && obp->value != connected; obp = obp->next)
587 ;
528 588
529 if (obp) { 589 if (obp)
590 {
530 ol->next = obp->link; 591 ol->next = obp->link;
531 obp->link = ol; 592 obp->link = ol;
593 }
532 } else { 594 else
595 {
533 obp = get_objectlinkpt(); 596 obp = get_objectlinkpt ();
534 obp->value = connected; 597 obp->value = connected;
535 598
536 obp->next = map->buttons; 599 obp->next = map->buttons;
537 map->buttons = obp; 600 map->buttons = obp;
538 obp->link = ol; 601 obp->link = ol;
539 } 602 }
540} 603}
541 604
542/* 605/*
543 * Remove the object from the linked lists of buttons in the map. 606 * Remove the object from the linked lists of buttons in the map.
544 * This is only needed by editors. 607 * This is only needed by editors.
545 */ 608 */
546 609
610void
547void remove_button_link(object *op) { 611remove_button_link (object *op)
612{
548 oblinkpt *obp; 613 oblinkpt *obp;
549 objectlink **olp, *ol; 614 objectlink **olp, *ol;
550 615
551 if (op->map == NULL) { 616 if (op->map == NULL)
617 {
552 LOG(llevError, "remove_button_link() in object without map.\n"); 618 LOG (llevError, "remove_button_link() in object without map.\n");
553 return; 619 return;
554 } 620 }
621
555 if (!QUERY_FLAG(op,FLAG_IS_LINKED)) { 622 if (!QUERY_FLAG (op, FLAG_IS_LINKED))
623 {
556 LOG(llevError, "remove_button_linked() in unlinked object.\n"); 624 LOG (llevError, "remove_button_linked() in unlinked object.\n");
557 return; 625 return;
558 } 626 }
627
559 for (obp = op->map->buttons; obp; obp = obp->next) 628 for (obp = op->map->buttons; obp; obp = obp->next)
560 for (olp = &obp->link; (ol = *olp); olp = &ol->next) 629 for (olp = &obp->link; (ol = *olp); olp = &ol->next)
561 if (ol->ob == op) { 630 if (ol->ob == op)
631 {
632
562/* LOG(llevDebug, "Removed link %d in button %s and map %s.\n", 633/* LOG(llevDebug, "Removed link %d in button %s and map %s.\n",
563 obp->value, op->name, op->map->path); 634 obp->value, op->name, op->map->path);
564*/ 635*/
565 *olp = ol->next; 636 *olp = ol->next;
566 free(ol); 637 delete ol;
567 return; 638 return;
568 } 639 }
640
569 LOG(llevError, "remove_button_linked(): couldn't find object.\n"); 641 LOG (llevError, "remove_button_linked(): couldn't find object.\n");
570 CLEAR_FLAG(op,FLAG_IS_LINKED); 642 CLEAR_FLAG (op, FLAG_IS_LINKED);
571} 643}
572 644
645/*
646 * Gets the objectlink for this connection from the map.
647 */
648oblinkpt *
649get_connection_links (maptile *map, long connection)
650{
651 for (oblinkpt * obp = map->buttons; obp; obp = obp->next)
652 if (obp->value == connection)
653 return obp;
654
655 return 0;
656}
657
573/* 658/*
574 * Return the first objectlink in the objects linked to this one 659 * Return the first objectlink in the objects linked to this one
575 */ 660 */
576 661
662oblinkpt *
577objectlink *get_button_links(const object *button) { 663get_button_links (const object *button)
664{
578 oblinkpt *obp; 665 oblinkpt *obp;
579 objectlink *ol; 666 objectlink *ol;
580 667
581 if (!button->map) 668 if (!button->map)
582 return NULL; 669 return NULL;
670
583 for (obp = button->map->buttons; obp; obp = obp->next) 671 for (obp = button->map->buttons; obp; obp = obp->next)
584 for (ol = obp->link; ol; ol = ol->next) 672 for (ol = obp->link; ol; ol = ol->next)
585 if (ol->ob == button && ol->id == button->count) 673 if (ol->ob == button)
586 return obp->link; 674 return obp;
675
587 return NULL; 676 return NULL;
588} 677}
589 678
590/* 679/*
591 * Made as a separate function to increase efficiency 680 * Made as a separate function to increase efficiency
592 */ 681 */
593 682
683int
594int get_button_value(const object *button) { 684get_button_value (const object *button)
685{
595 oblinkpt *obp; 686 oblinkpt *obp;
596 objectlink *ol; 687 objectlink *ol;
597 688
598 if (!button->map) 689 if (!button->map)
599 return 0; 690 return 0;
600 for (obp = button->map->buttons; obp; obp = obp->next) 691 for (obp = button->map->buttons; obp; obp = obp->next)
601 for (ol = obp->link; ol; ol = ol->next) 692 for (ol = obp->link; ol; ol = ol->next)
602 if (ol->ob == button && ol->id == button->count) 693 if (ol->ob == button)
603 return obp->value; 694 return obp->value;
604 return 0; 695 return 0;
605} 696}
606 697
607/* This routine makes monsters who are 698/* This routine makes monsters who are
610 * If floor is to be triggered must have 701 * If floor is to be triggered must have
611 * a speed of zero (default is 1 for all 702 * a speed of zero (default is 1 for all
612 * but the charm floor type). 703 * but the charm floor type).
613 * by b.t. thomas@nomad.astro.psu.edu 704 * by b.t. thomas@nomad.astro.psu.edu
614 */ 705 */
615 706
707void
616void do_mood_floor(object *op, object *op2) { 708do_mood_floor (object *op, object *source)
709{
617 object *tmp; 710 object *tmp;
618 object *tmp2; 711 object *tmp2;
619 712
713 if (!source)
714 source = op;
715
620 for (tmp = GET_MAP_OB(op->map, op->x, op->y); tmp; tmp=tmp->above) 716 for (tmp = GET_MAP_OB (op->map, op->x, op->y); tmp; tmp = tmp->above)
621 if (QUERY_FLAG(tmp, FLAG_MONSTER)) break; 717 if (QUERY_FLAG (tmp, FLAG_MONSTER))
718 break;
622 719
623 /* doesn't effect players, and if there is a player on this space, won't also 720 /* doesn't effect players, and if there is a player on this space, won't also
624 * be a monster here. 721 * be a monster here.
625 */ 722 */
626 if (!tmp || tmp->type == PLAYER) return; 723 if (!tmp || tmp->type == PLAYER)
724 return;
627 725
628 switch(op->last_sp) { 726 switch (op->last_sp)
727 {
629 case 0: /* furious--make all monsters mad */ 728 case 0: /* furious--make all monsters mad */
630 if(QUERY_FLAG(tmp, FLAG_UNAGGRESSIVE))
631 CLEAR_FLAG(tmp, FLAG_UNAGGRESSIVE);
632 if(QUERY_FLAG(tmp, FLAG_FRIENDLY)) {
633 CLEAR_FLAG(tmp, FLAG_FRIENDLY);
634 remove_friendly_object(tmp);
635 tmp->attack_movement = 0;
636 /* lots of checks here, but want to make sure we don't
637 * dereference a null value
638 */
639 if (tmp->type == GOLEM && tmp->owner && tmp->owner->type==PLAYER &&
640 tmp->owner->contr->ranges[range_golem]==tmp) {
641 tmp->owner->contr->ranges[range_golem]=NULL;
642 tmp->owner->contr->golem_count = 0;
643 }
644 tmp->owner = 0;
645 }
646 break;
647 case 1: /* angry -- get neutral monsters mad */
648 if(QUERY_FLAG(tmp, FLAG_UNAGGRESSIVE)&& 729 if (QUERY_FLAG (tmp, FLAG_UNAGGRESSIVE))
649 !QUERY_FLAG(tmp, FLAG_FRIENDLY))
650 CLEAR_FLAG(tmp, FLAG_UNAGGRESSIVE); 730 CLEAR_FLAG (tmp, FLAG_UNAGGRESSIVE);
651 break; 731 if (QUERY_FLAG (tmp, FLAG_FRIENDLY))
732 {
733 CLEAR_FLAG (tmp, FLAG_FRIENDLY);
734 remove_friendly_object (tmp);
735 tmp->attack_movement = 0;
736 /* lots of checks here, but want to make sure we don't
737 * dereference a null value
738 */
739 if (tmp->type == GOLEM && tmp->owner && tmp->owner->type == PLAYER && tmp->owner->contr->ranges[range_golem] == tmp)
740 tmp->owner->contr->ranges[range_golem] = 0;
741
742 tmp->owner = 0;
743 }
744 break;
745 case 1: /* angry -- get neutral monsters mad */
746 if (QUERY_FLAG (tmp, FLAG_UNAGGRESSIVE) && !QUERY_FLAG (tmp, FLAG_FRIENDLY))
747 CLEAR_FLAG (tmp, FLAG_UNAGGRESSIVE);
748 break;
652 case 2: /* calm -- pacify unfriendly monsters */ 749 case 2: /* calm -- pacify unfriendly monsters */
653 if(!QUERY_FLAG(tmp, FLAG_UNAGGRESSIVE)) 750 if (!QUERY_FLAG (tmp, FLAG_UNAGGRESSIVE))
654 SET_FLAG(tmp, FLAG_UNAGGRESSIVE); 751 SET_FLAG (tmp, FLAG_UNAGGRESSIVE);
655 break; 752 break;
656 case 3: /* make all monsters fall asleep */ 753 case 3: /* make all monsters fall asleep */
657 if(!QUERY_FLAG(tmp, FLAG_SLEEP)) 754 if (!QUERY_FLAG (tmp, FLAG_SLEEP))
658 SET_FLAG(tmp, FLAG_SLEEP); 755 SET_FLAG (tmp, FLAG_SLEEP);
659 break; 756 break;
660 case 4: /* charm all monsters */ 757 case 4: /* charm all monsters */
758 if (op == source)
759 break; /* only if 'connected' */
661 760
662 if(op == op2) break; /* only if 'connected' */ 761 for (tmp2 = GET_MAP_OB (source->map, source->x, source->y); /* finding an owner */
663
664 for(tmp2=get_map_ob(op2->map,op2->x,op2->y); /* finding an owner */
665 tmp2->type!=PLAYER;tmp2=tmp2->above) 762 tmp2->type != PLAYER; tmp2 = tmp2->above)
666 if(tmp2->above==NULL) break; 763 if (tmp2->above == NULL)
764 break;
667 765
668 if (tmp2->type != PLAYER) 766 if (tmp2->type != PLAYER)
669 break; 767 break;
670 set_owner(tmp,tmp2); 768
769 tmp->set_owner (tmp2);
671 SET_FLAG(tmp,FLAG_MONSTER); 770 SET_FLAG (tmp, FLAG_MONSTER);
771
672 tmp->stats.exp = 0; 772 tmp->stats.exp = 0;
673 SET_FLAG(tmp, FLAG_FRIENDLY); 773
674 add_friendly_object (tmp); 774 add_friendly_object (tmp);
675 tmp->attack_movement = PETMOVE; 775 tmp->attack_movement = PETMOVE;
676 break; 776 break;
677 777
678 default: 778 default:
679 break; 779 break;
680
681 } 780 }
682} 781}
683 782
684/* this function returns the object it matches, or NULL if non. 783/* this function returns the object it matches, or NULL if non.
685 * It will descend through containers to find the object. 784 * It will descend through containers to find the object.
686 * slaying = match object slaying flag 785 * slaying = match object slaying flag
687 * race = match object archetype name flag 786 * race = match object archetype name flag
688 * hp = match object type (excpt type '0'== PLAYER) 787 * hp = match object type (excpt type '0'== PLAYER)
689 */ 788 */
690 789object *
691object * check_inv_recursive(object *op, const object *trig) 790check_inv_recursive (object *op, const object *trig)
692{ 791{
693 object *tmp,*ret=NULL; 792 object *tmp, *ret = NULL;
694 793
695 /* First check the object itself. */ 794 /* First check the object itself. */
696 if((trig->stats.hp && (op->type == trig->stats.hp)) 795 if ((trig->stats.hp && (op->type == trig->stats.hp))
697 || (trig->slaying && (op->slaying == trig->slaying)) 796 || (trig->slaying && (op->slaying == trig->slaying))
698 || (trig->race && (op->arch->name == trig->race))) 797 || (trig->race && (op->arch->name == trig->race)))
699 return op; 798 return op;
700 799
701 for(tmp=op->inv; tmp; tmp=tmp->below) { 800 for (tmp = op->inv; tmp; tmp = tmp->below)
702 if (tmp->inv) { 801 {
802 if (tmp->inv)
803 {
703 ret=check_inv_recursive(tmp, trig); 804 ret = check_inv_recursive (tmp, trig);
704 if (ret) return ret; 805 if (ret)
705 } 806 return ret;
807 }
706 else if((trig->stats.hp && (tmp->type == trig->stats.hp)) 808 else if ((trig->stats.hp && (tmp->type == trig->stats.hp))
707 || (trig->slaying && (tmp->slaying == trig->slaying)) 809 || (trig->slaying && (tmp->slaying == trig->slaying))
708 || (trig->race && (tmp->arch->name == trig->race))) 810 || (trig->race && (tmp->arch->name == trig->race)))
709 return tmp; 811 return tmp;
710 } 812 }
711 return NULL; 813 return NULL;
712} 814}
713 815
714/* check_inv(), a function to search the inventory, 816/* check_inv(), a function to search the inventory,
715 * of a player and then based on a set of conditions, 817 * of a player and then based on a set of conditions,
716 * the square will activate connected items. 818 * the square will activate connected items.
717 * Monsters can't trigger this square (for now) 819 * Monsters can't trigger this square (for now)
718 * Values are: last_sp = 1/0 obj/no obj triggers 820 * Values are: last_sp = 1/0 obj/no obj triggers
719 * last_heal = 1/0 remove/dont remove obj if triggered 821 * last_heal = 1/0 remove/dont remove obj if triggered
720 * -b.t. (thomas@nomad.astro.psu.edu 822 * -b.t. (thomas@nomad.astro.psu.edu
721 */ 823 *
722 824 * Tue Dec 19 15:34:00 CET 2006 elmex: changed the function to ignore op
825 * because the check-inventory semantic essentially only applies when
826 * something is above the inventory checker.
827 * The semantic prior this change was: trigger if something has moved on or off
828 * and has a matching item. Imagine what happens if someone steps on the inventory
829 * checker with a matching item, has it, activates the connection, throws the item
830 * away, and then leaves the inventory checker. That would've caused an always-enabled
831 * state in the inventory checker. This won't happen anymore now.
832 *
833 */
834void
723void check_inv (object *op, object *trig) { 835check_inv (object *op, object *trig)
724object *match; 836{
837 trig->value = 0; // deactivate if none of the following conditions apply
725 838
726 if(op->type != PLAYER) return; 839 if (object *pl = trig->ms ().player ())
840 {
727 match = check_inv_recursive(op,trig); 841 object *match = check_inv_recursive (pl, trig);
842
728 if (match && trig->last_sp) { 843 if (match && trig->last_sp) // match == having
729 if(trig->last_heal) 844 {
845 if (trig->last_heal)
730 decrease_ob(match); 846 decrease_ob (match);
731 use_trigger(trig); 847
732 } 848 trig->value = 1;
849 }
733 else if (!match && !trig->last_sp) 850 else if (!match && !trig->last_sp) // match == not having
734 use_trigger(trig); 851 trig->value = 1;
735}
736
737
738/* This does a minimal check of the button link consistency for object
739 * map. All it really does it much sure the object id link that is set
740 * matches what the object has.
741 */
742void verify_button_links(const mapstruct *map) {
743 oblinkpt *obp;
744 objectlink *ol;
745
746 if (!map) return;
747
748 for (obp = map->buttons; obp; obp = obp->next) {
749 for (ol=obp->link; ol; ol=ol->next) {
750 if (ol->id!=ol->ob->count)
751 LOG(llevError,"verify_button_links: object %s on list is corrupt (%d!=%d)\n",ol->ob->name, ol->id, ol->ob->count);
752 }
753 } 852 }
853
854 push_button (trig);
754} 855}
856

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines