1 /* $Id$ */
2 /* Purpose: Angband game engine */
3
4 /*
5 * Copyright (c) 1989 James E. Wilson, Robert A. Koeneke
6 *
7 * This software may be copied and distributed for educational, research, and
8 * not for profit purposes provided that this copyright and statement are
9 * included in all such copies.
10 */
11
12 #define SERVER
13
14 #include "angband.h"
15 #include "externs.h"
16
17 /* chance of townie respawning like other monsters, randint(chance)==0 means respawn */
18 /* Default */
19 #define TOWNIE_RESPAWN_CHANCE 250
20 /* better for Halloween event */
21 #define HALLOWEEN_TOWNIE_RESPAWN_CHANCE 125
22
23 /* if defined, player ghost loses exp slowly. [10000]
24 * see GHOST_XP_CASHBACK in xtra2.c also.
25 */
26 #define GHOST_FADING 10000
27
28 /* How fast HP/MP regenerate when 'resting'. [3] */
29 #define RESTING_RATE (cfg.resting_rate)
30
31 /* Chance of items damaged when drowning, in % [3] */
32 #define WATER_ITEM_DAMAGE_CHANCE 3
33
34 /* Maximum wilderness radius a player can travel with WoR [16]
35 * TODO: Add another method to allow wilderness travels */
36 #define RECALL_MAX_RANGE 24
37
38 /* duration of GoI when getting recalled. [2] (Must be 0<=n<=4) */
39 #define RECALL_GOI_LENGTH 3
40
41
42 /* forward declarations */
43 static void process_firework_creation(void);
44 #ifndef CLIENT_SIDE_WEATHER
45 static void process_weather_control(void);
46 static void process_weather_effect_creation(void);
47 #else
48 #ifndef CLIENT_WEATHER_GLOBAL
49
50 static void wild_weather_init(void);
51 static void process_wild_weather(void);
52 static void cloud_set_movement(int i);
53 static void cloud_move(int i, bool newly_created);
54 static void cloud_erase(int i);
55 /* cdsum*87/200 : sin 60 deg */
56 #define CLOUD_XS(cx1, cy1, cx2, cy2, cdsum) ((cx1 - (cdsum - (cx2 - cx1)) / 2) / MAX_WID)
57 #define CLOUD_YS(cx1, cy1, cx2, cy2, cdsum) ((cy1 - ((cdsum * 87) / 200)) / MAX_HGT)
58 #define CLOUD_XD(cx1, cy1, cx2, cy2, cdsum) ((cx2 + (cdsum - (cx2 - cx1)) / 2) / MAX_WID)
59 #define CLOUD_YD(cx1, cy1, cx2, cy2, cdsum) ((cy2 + ((cdsum * 87) / 200)) / MAX_HGT)
60
61 /* Enable wind in general? */
62 #define WEATHER_WINDS
63
64 /* Activate hack that disables all cloud movement,
65 as a workaround for the 'eternal rain' bug for now - C. Blue */
66 #define WEATHER_NO_CLOUD_MOVEMENT
67
68 #else
69
70 static void process_weather_control(void);
71 #endif
72 #endif
73
74 #define SHUTDOWN_IGNORE_IDDC(p_ptr) \
75 (in_irondeepdive(&(p_ptr)->wpos) \
76 && (p_ptr)->idle_char > 900) /* just after 15 minutes flat */
77 //&& p_ptr->afk
78 //&& p_ptr->idle_char > STARVE_KICK_TIMER) //reuse idle-starve-kick-timer for this
79
80
81 /*
82 * Return a "feeling" (or NULL) about an item. Method 1 (Heavy).
83 */
value_check_aux1(object_type * o_ptr)84 cptr value_check_aux1(object_type *o_ptr)
85 {
86 object_kind *k_ptr = &k_info[o_ptr->k_idx];
87
88 /* Artifacts */
89 if (artifact_p(o_ptr)) {
90 /* Cursed/Broken */
91 if (cursed_p(o_ptr) || broken_p(o_ptr)) return "terrible";
92
93 /* Normal */
94 return "special";
95 }
96
97 /* Ego-Items */
98 if (ego_item_p(o_ptr)) {
99 /* Hack for Stormbringer, so it doesn't show as "worthless" */
100 if (o_ptr->name2 == EGO_STORMBRINGER) return "terrible";
101
102 #if 0
103 /* Cursed/Broken */
104 if (cursed_p(o_ptr) || broken_p(o_ptr)) return "worthless";
105 #else
106 /* Cursed items */
107 if (cursed_p(o_ptr)) return "cursed";
108
109 /* Broken items */
110 if (broken_p(o_ptr)) return "worthless";
111 #endif
112
113 /* Normal */
114
115 /* All exploding or ego-ammo is excellent */
116 if (is_ammo(o_ptr->tval) && (o_ptr->pval || o_ptr->name2 || o_ptr->name2b)) return "excellent";
117
118 if (!object_value(0, o_ptr)) return "worthless";
119 if (object_value(0, o_ptr) < 4000) return "good";
120 return "excellent";
121 }
122
123 /* Cursed items */
124 if (cursed_p(o_ptr)) return "cursed";
125
126 /* Broken items */
127 if (broken_p(o_ptr)) return "broken";
128
129 /* Valid "tval" codes */
130 switch (o_ptr->tval) {
131 case TV_DIGGING:
132 case TV_BLUNT:
133 case TV_POLEARM:
134 case TV_SWORD:
135 case TV_BOOTS:
136 case TV_GLOVES:
137 case TV_HELM:
138 case TV_CROWN:
139 case TV_SHIELD:
140 case TV_CLOAK:
141 case TV_SOFT_ARMOR:
142 case TV_HARD_ARMOR:
143 case TV_DRAG_ARMOR:
144 case TV_AXE:
145 case TV_SHOT:
146 case TV_ARROW:
147 case TV_BOLT:
148 case TV_BOW:
149 case TV_BOOMERANG:
150 /* Good "armor" bonus */
151 if ((o_ptr->to_a > k_ptr->to_a) &&
152 (o_ptr->to_a > 0)) return "good";
153 /* Good "weapon" bonus */
154 if ((o_ptr->to_h - k_ptr->to_h + o_ptr->to_d - k_ptr->to_d > 0) &&
155 (o_ptr->to_h > 0 || o_ptr->to_d > 0)) return "good";
156 break;
157 default:
158 /* Good "armor" bonus */
159 if (o_ptr->to_a > 0) return "good";
160 /* Good "weapon" bonus */
161 if (o_ptr->to_h + o_ptr->to_d > 0) return "good";
162 break;
163 }
164
165 /* Default to "average" */
166 return "average";
167 }
168
value_check_aux1_magic(object_type * o_ptr)169 cptr value_check_aux1_magic(object_type *o_ptr)
170 {
171 object_kind *k_ptr = &k_info[o_ptr->k_idx];
172
173
174 switch (o_ptr->tval) {
175 /* Scrolls, Potions, Wands, Staves and Rods */
176 case TV_SCROLL:
177 /* hack for cheques */
178 if (k_ptr->sval == SV_SCROLL_CHEQUE) return "good";
179 case TV_POTION:
180 case TV_POTION2:
181 case TV_WAND:
182 case TV_STAFF:
183 case TV_ROD:
184 case TV_ROD_MAIN:
185 /* "Cursed" scrolls/potions have a cost of 0 */
186 if (k_ptr->cost == 0) return "bad";//"terrible";
187
188 /* Artifacts */
189 if (artifact_p(o_ptr)) return "special";
190
191 /* Scroll of Nothing, Apple Juice, etc. */
192 if (k_ptr->cost < 3) return "worthless"; //"average" or "worthless"
193
194 /*
195 * Identify, Phase Door, Cure Light Wounds, etc. are
196 * just average
197 */
198 if (k_ptr->cost < 100) return "average";
199
200 /* Enchant Armor, *Identify*, Restore Stat, etc. */
201 if (k_ptr->cost < 4000) return "good";
202
203 /* Acquirement, Deincarnation, Strength, Blood of Life, ... */
204 if (k_ptr->cost >= 4000) return "excellent";
205
206 break;
207 /* Food */
208 case TV_FOOD:
209 /* "Cursed" food */
210 if (k_ptr->cost == 0) return "bad";//"terrible";
211
212 /* Artifacts */
213 if (artifact_p(o_ptr)) return "special";
214
215 /* Normal food (no magical properties) */
216 if (k_ptr->cost <= 10) return "average";
217
218 /* Everything else is good */
219 if (k_ptr->cost > 10) return "good";
220
221 break;
222 }
223
224 /* No feeling */
225 // return "";
226 return (NULL);
227 }
228
229
230 /*
231 * Return a "feeling" (or NULL) about an item. Method 2 (Light).
232 */
value_check_aux2(object_type * o_ptr)233 cptr value_check_aux2(object_type *o_ptr)
234 {
235 object_kind *k_ptr = &k_info[o_ptr->k_idx];
236
237 /* Cursed items (all of them) */
238 if (cursed_p(o_ptr)) return "cursed";
239
240 /* Broken items (all of them) */
241 if (broken_p(o_ptr)) return "broken";
242
243 /* Artifacts -- except cursed/broken ones */
244 if (artifact_p(o_ptr)) return "good";
245
246 /* Ego-Items -- except cursed/broken ones */
247 if (!k_ptr->cost) return "broken";
248 if (ego_item_p(o_ptr)) {
249 if (!object_value(0, o_ptr)) return "worthless";
250 return "good";
251 }
252
253 switch (o_ptr->tval) {
254 case TV_DIGGING:
255 case TV_BLUNT:
256 case TV_POLEARM:
257 case TV_SWORD:
258 case TV_BOOTS:
259 case TV_GLOVES:
260 case TV_HELM:
261 case TV_CROWN:
262 case TV_SHIELD:
263 case TV_CLOAK:
264 case TV_SOFT_ARMOR:
265 case TV_HARD_ARMOR:
266 case TV_DRAG_ARMOR:
267 case TV_AXE:
268 case TV_SHOT:
269 case TV_ARROW:
270 case TV_BOLT:
271 case TV_BOW:
272 case TV_BOOMERANG:
273 /* Good "armor" bonus */
274 if (o_ptr->to_a > k_ptr->to_a) return "good";
275 /* Good "weapon" bonus */
276 if (o_ptr->to_h - k_ptr->to_h + o_ptr->to_d - k_ptr->to_d > 0) return "good";
277 break;
278 default:
279 /* Good "armor" bonus */
280 if (o_ptr->to_a > 0) return "good";
281 /* Good "weapon" bonus */
282 if (o_ptr->to_h + o_ptr->to_d > 0) return "good";
283 break;
284 }
285
286 /* No feeling */
287 return (NULL);
288 }
289
value_check_aux2_magic(object_type * o_ptr)290 cptr value_check_aux2_magic(object_type *o_ptr)
291 {
292 object_kind *k_ptr = &k_info[o_ptr->k_idx];
293
294
295 switch (o_ptr->tval) {
296 /* Scrolls, Potions, Wands, Staves and Rods */
297 case TV_SCROLL:
298 /* hack for cheques */
299 if (k_ptr->sval == SV_SCROLL_CHEQUE) return "good";
300 case TV_POTION:
301 case TV_POTION2:
302 case TV_WAND:
303 case TV_STAFF:
304 case TV_ROD:
305 /* "Cursed" scrolls/potions have a cost of 0 */
306 if (k_ptr->cost == 0) return "bad";//"cursed";
307
308 /* Artifacts */
309 if (artifact_p(o_ptr)) return "good";
310
311 /* Scroll of Nothing, Apple Juice, etc. */
312 if (k_ptr->cost < 3) return "average";//or "worthless"
313
314 /*
315 * Identify, Phase Door, Cure Light Wounds, etc. are
316 * just average
317 */
318 if (k_ptr->cost < 100) return "average";
319
320 /* Enchant Armor, *Identify*, Restore Stat, etc. */
321 if (k_ptr->cost < 4000) return "good";
322
323 /* Acquirement, Deincarnation, Strength, Blood of Life, ... */
324 if (k_ptr->cost >= 4000) return "good";
325
326 break;
327
328 /* Food */
329 case TV_FOOD:
330 /* "Cursed" food */
331 if (k_ptr->cost == 0) return "bad";//"cursed";
332
333 /* Artifacts */
334 if (artifact_p(o_ptr)) return "good";
335
336 /* Normal food (no magical properties) */
337 if (k_ptr->cost <= 10) return "average";
338
339 /* Everything else is good */
340 if (k_ptr->cost > 10) return "good";
341
342 break;
343 }
344
345 /* No feeling */
346 // return "";
347 return (NULL);
348 }
349
350 /*
351 * Sense the inventory
352 */
sense_inventory(int Ind)353 static void sense_inventory(int Ind)
354 {
355 player_type *p_ptr = Players[Ind];
356
357 int i;
358
359 bool heavy = FALSE, heavy_magic = FALSE, heavy_archery = FALSE;
360 bool ok_combat = FALSE, ok_magic = FALSE, ok_archery = FALSE;
361 bool ok_curse = FALSE;
362
363 cptr feel;
364 bool felt_heavy;
365
366 object_type *o_ptr;
367 char o_name[ONAME_LEN];
368
369
370 /*** Check for "sensing" ***/
371
372 /* No sensing when confused */
373 if (p_ptr->confused) return;
374
375 #if 0 /* no more linear ;) */
376 if (!rand_int(133 - get_skill_scale(p_ptr, SKILL_COMBAT, 130))) ok_combat = TRUE;
377 if (!rand_int(133 - get_skill_scale(p_ptr, SKILL_ARCHERY, 130))) ok_archery = TRUE;
378 if (!rand_int(133 - get_skill_scale(p_ptr, SKILL_MAGIC, 130))) {
379 ok_magic = TRUE;
380 ok_curse = TRUE;
381 }
382 if (!rand_int(133 - get_skill_scale(p_ptr, SKILL_PRAY, 130))) ok_curse = TRUE;
383 #else
384 /* instead, allow more use at lower SKILL_COMBAT levels already,
385 otherwise huge stacks of ID scrolls will remain mandatory for maybe too long a time - C. Blue */
386 // if (!rand_int(399 / (get_skill_scale(p_ptr, SKILL_COMBAT, 97) + 3))) ok_combat = TRUE;
387 // if (!rand_int(2 * (101 - (get_skill_scale(p_ptr, SKILL_COMBAT, 70) + 30)))) ok_combat = TRUE;
388 // if (!rand_int(102 - (get_skill_scale(p_ptr, SKILL_COMBAT, 80) + 20))) ok_combat = TRUE;
389 // if (!rand_int(102 - (get_skill_scale(p_ptr, SKILL_COMBAT, 70) + 30))) ok_combat = TRUE;
390 // if (!rand_int(2000 / (get_skill_scale(p_ptr, SKILL_COMBAT, 80) + 20) - 18)) ok_combat = TRUE;
391 if (!rand_int(3000 / (get_skill_scale(p_ptr, SKILL_COMBAT, 80) + 20) - 28)) ok_combat = TRUE;
392 if (!rand_int(3000 / (get_skill_scale(p_ptr, SKILL_ARCHERY, 80) + 20) - 28)) ok_archery = TRUE;
393 if (!rand_int(3000 / (get_skill_scale(p_ptr, SKILL_MAGIC, 80) + 20) - 28)) {
394 ok_magic = TRUE;
395 ok_curse = TRUE;
396 }
397 /* note: SKILL_PRAY is currently unused */
398 if (!rand_int(3000 / (get_skill_scale(p_ptr, SKILL_PRAY, 80) + 20) - 28)) ok_curse = TRUE;
399 #endif
400
401 /* A powerful warrior can pseudo-id ranged weapons and ammo too,
402 even if (s)he's not good at archery in general */
403 if (get_skill(p_ptr, SKILL_COMBAT) >= 31) {
404 #if 1 /* (apply 33% chance, see below) - allow basic feelings */
405 ok_archery = TRUE;
406 #else /* (apply 33% chance, see below) - allow more distinctive feelings */
407 heavy_archery = TRUE;
408 #endif
409 }
410
411 /* A very powerful warrior can even distinguish magic items */
412 if (get_skill(p_ptr, SKILL_COMBAT) >= 41) {
413 #if 0 /* too much? */
414 ok_magic = TRUE;
415 #endif
416 ok_curse = TRUE;
417 }
418
419 #if 1
420 /* extra class-specific boni */
421 i = 150 - ((p_ptr->lev <= 50) ? (p_ptr->lev * 2) : (p_ptr->lev + 50));
422 if ((p_ptr->pclass == CLASS_PRIEST) && !rand_int(i)) ok_curse = TRUE;
423 #if 0 /* out of line? */
424 if ((p_ptr->pclass == CLASS_ISTAR ||
425 p_ptr->pclass == CLASS_SHAMAN) && !rand_int(i)) ok_magic = TRUE;
426 if ((p_ptr->pclass == CLASS_MINDCRAFTER) && !rand_int(i)) {
427 ok_curse = TRUE;
428 ok_magic = TRUE;
429 ok_combat = TRUE;
430 }
431 #endif
432 #endif
433
434 /* nothing to feel? exit */
435 if (!ok_combat && !ok_magic && !ok_archery) return;
436
437 heavy = (get_skill(p_ptr, SKILL_COMBAT) >= 11) ? TRUE : FALSE;
438 heavy_magic = (get_skill(p_ptr, SKILL_MAGIC) >= 11) ? TRUE : FALSE;
439 heavy_archery = (get_skill(p_ptr, SKILL_ARCHERY) >= 11) ? TRUE : FALSE;
440
441 /*** Sense everything ***/
442
443 /* Check everything */
444 for (i = 0; i < INVEN_TOTAL; i++) {
445 o_ptr = &p_ptr->inventory[i];
446
447 /* Skip empty slots */
448 if (!o_ptr->k_idx) continue;
449 /* We know about it already, do not tell us again */
450 if (o_ptr->ident & ID_SENSE) continue;
451 /* It is fully known, no information needed */
452 if (object_known_p(Ind, o_ptr)) continue;
453 /* Occasional failure on inventory items */
454 if ((i < INVEN_WIELD) &&
455 (magik(80) || UNAWARENESS(p_ptr))) continue;
456
457 feel = NULL;
458 felt_heavy = FALSE;
459
460 if (ok_curse && cursed_p(o_ptr)) feel = value_check_aux1(o_ptr);
461
462 /* Valid "tval" codes */
463 switch (o_ptr->tval) {
464 case TV_DIGGING:
465 case TV_BLUNT:
466 case TV_POLEARM:
467 case TV_SWORD:
468 case TV_BOOTS:
469 case TV_GLOVES:
470 case TV_HELM:
471 case TV_CROWN:
472 case TV_SHIELD:
473 case TV_CLOAK:
474 case TV_SOFT_ARMOR:
475 case TV_HARD_ARMOR:
476 case TV_DRAG_ARMOR:
477 case TV_AXE:
478 case TV_TRAPKIT:
479 if (ok_combat)
480 feel = (heavy ? value_check_aux1(o_ptr) :
481 value_check_aux2(o_ptr));
482 if (heavy) felt_heavy = TRUE;
483 break;
484 case TV_MSTAFF:
485 if (ok_magic)
486 feel = (heavy_magic ? value_check_aux1(o_ptr) :
487 value_check_aux2(o_ptr));
488 if (heavy_magic) felt_heavy = TRUE;
489 break;
490 case TV_SCROLL:
491 /* hack for cheques: Don't try to pseudo-id them at all. */
492 if (o_ptr->sval == SV_SCROLL_CHEQUE) continue;
493 case TV_POTION:
494 case TV_POTION2:
495 case TV_WAND:
496 case TV_STAFF:
497 case TV_ROD:
498 case TV_FOOD:
499 if (ok_magic && !object_aware_p(Ind, o_ptr))
500 feel = (heavy_magic ? value_check_aux1_magic(o_ptr) :
501 value_check_aux2_magic(o_ptr));
502 if (heavy_magic) felt_heavy = TRUE;
503 break;
504 case TV_SHOT:
505 case TV_ARROW:
506 case TV_BOLT:
507 case TV_BOW:
508 case TV_BOOMERANG:
509 if (ok_archery || (ok_combat && magik(25)))
510 feel = (heavy_archery ? value_check_aux1(o_ptr) :
511 value_check_aux2(o_ptr));
512 if (heavy_archery) felt_heavy = TRUE;
513 break;
514 }
515
516 /* Skip non-feelings */
517 if (!feel) continue;
518
519 /* Stop everything */
520 if (p_ptr->disturb_minor) disturb(Ind, 0, 0);
521
522 /* Get an object description */
523 object_desc(Ind, o_name, o_ptr, FALSE, 0);
524
525 /* Hack -- suppress messages */
526 if (p_ptr->taciturn_messages) suppress_message = TRUE;
527
528 /* Message (equipment) */
529 if (i >= INVEN_WIELD) {
530 msg_format(Ind, "You feel the %s (%c) you are %s %s %s...",
531 o_name, index_to_label(i), describe_use(Ind, i),
532 ((o_ptr->number == 1) ? "is" : "are"), feel);
533 }
534 /* Message (inventory) */
535 else {
536 msg_format(Ind, "You feel the %s (%c) in your pack %s %s...",
537 o_name, index_to_label(i),
538 ((o_ptr->number == 1) ? "is" : "are"), feel);
539 }
540
541 suppress_message = FALSE;
542
543 /* We have "felt" it */
544 o_ptr->ident |= (ID_SENSE | ID_SENSED_ONCE);
545 if (felt_heavy) o_ptr->ident |= ID_SENSE_HEAVY;
546
547 /* Remember feeling of that flavour, if and only if an item is always the same!
548 For example, rings might be cursed by ego power. Wands may not.
549 Other than that, this way an interesting middle-way between RPG-style
550 remember-items-seen-in-shops and normal ID-remembrance can be created:
551 Remember static items seen in shops just by feeling before having IDed one. :)
552 - C. Blue */
553 switch(o_ptr->tval) {
554 case TV_WAND:
555 case TV_STAFF:
556 case TV_ROD:
557 case TV_ROD_MAIN:
558 case TV_SCROLL:
559 case TV_POTION:
560 case TV_POTION2:
561 case TV_FOOD:
562 p_ptr->obj_felt[o_ptr->k_idx] = TRUE;
563 if (felt_heavy) p_ptr->obj_felt_heavy[o_ptr->k_idx] = TRUE;
564 }
565
566 /* Inscribe it textually */
567 #if 0 /* make pseudo-id remove previous unique tag? */
568 if (!o_ptr->note || o_ptr->note_utag) {
569 o_ptr->note = quark_add(feel);
570 o_ptr->note_utag = 0;
571 }
572 #else /* keep unique tag until removed manually by player? */
573 if (!o_ptr->note) o_ptr->note = quark_add(feel);
574 #endif
575 /* Still add an inscription, so unique loot doesn't cause major annoyances - C. Blue */
576 /* for items that were already pseudo-id-inscribed but then forgotten:
577 only add inscription if it doesn't exist on the item yet (*) - 2 checks */
578 else if (strcmp(quark_str(o_ptr->note), feel)) { // (*) check 1 of 2 (exact match)
579 strcpy(o_name, feel); /* just abusing o_name for this since it's not needed anymore anyway */
580 strcat(o_name, "-");
581 if (!strstr(quark_str(o_ptr->note), o_name)) { // (*) check 2 of 2 (partial match)
582 strcat(o_name, quark_str(o_ptr->note));
583 o_ptr->note = quark_add(o_name);
584 }
585 }
586
587 /* Combine / Reorder the pack (later) */
588 p_ptr->notice |= (PN_COMBINE | PN_REORDER);
589
590 /* Window stuff */
591 p_ptr->window |= (PW_INVEN | PW_EQUIP);
592 }
593 }
594
595 #if 0 /* the results might be too incorrect! for example 'average' can still mean enchantment, etc. */
596 /* for NEW_ID_SCREEN's pseudo-id handling: */
597
598 static int quality_check_aux1(object_type *o_ptr) {
599 object_kind *k_ptr = &k_info[o_ptr->k_idx];
600
601 if (artifact_p(o_ptr)) return 3;
602
603 if (ego_item_p(o_ptr)) {
604 if (o_ptr->name2 == EGO_STORMBRINGER) return 3;
605 if (cursed_p(o_ptr) || broken_p(o_ptr)) return 2;
606 if (is_ammo(o_ptr->tval) && (o_ptr->pval || o_ptr->name2 || o_ptr->name2b)) return 2;
607 if (object_value(0, o_ptr) < 4000) return 1;
608 return 2;
609 }
610
611 if (cursed_p(o_ptr)) return -1;
612 if (broken_p(o_ptr)) return -1;
613
614 switch (o_ptr->tval) {
615 case TV_DIGGING:
616 case TV_BLUNT:
617 case TV_POLEARM:
618 case TV_SWORD:
619 case TV_BOOTS:
620 case TV_GLOVES:
621 case TV_HELM:
622 case TV_CROWN:
623 case TV_SHIELD:
624 case TV_CLOAK:
625 case TV_SOFT_ARMOR:
626 case TV_HARD_ARMOR:
627 case TV_DRAG_ARMOR:
628 case TV_AXE:
629 case TV_SHOT:
630 case TV_ARROW:
631 case TV_BOLT:
632 case TV_BOW:
633 case TV_BOOMERANG:
634 if ((o_ptr->ident & ID_SENSE_GOOD)) return 1;
635 break;
636 default:
637 if ((o_ptr->ident & ID_SENSE_GOOD)) return 1;
638 }
639
640 return 0;
641 }
642
643 /*
644 * Return a "feeling" (or NULL) about an item. Method 2 (Light).
645 */
646 static int quality_check_aux2(object_type *o_ptr) {
647 object_kind *k_ptr = &k_info[o_ptr->k_idx];
648
649 if (cursed_p(o_ptr)) -1;
650 if (broken_p(o_ptr)) -1;
651 if (artifact_p(o_ptr)) return 1;
652 if (!k_ptr->cost) return -1;
653 if (ego_item_p(o_ptr)) {
654 return 1;
655 }
656
657 switch (o_ptr->tval) {
658 case TV_DIGGING:
659 case TV_BLUNT:
660 case TV_POLEARM:
661 case TV_SWORD:
662 case TV_BOOTS:
663 case TV_GLOVES:
664 case TV_HELM:
665 case TV_CROWN:
666 case TV_SHIELD:
667 case TV_CLOAK:
668 case TV_SOFT_ARMOR:
669 case TV_HARD_ARMOR:
670 case TV_DRAG_ARMOR:
671 case TV_AXE:
672 case TV_SHOT:
673 case TV_ARROW:
674 case TV_BOLT:
675 case TV_BOW:
676 case TV_BOOMERANG:
677 if ((o_ptr->ident & ID_SENSE_GOOD)) return 1;
678 break;
679 default:
680 if ((o_ptr->ident & ID_SENSE_GOOD)) return 1;
681 }
682
683 return 0;
684 }
685
686 int pseudo_id_result(object_type *o_ptr) {
687 int quality = 0;
688
689 switch (o_ptr->tval) {
690 case TV_DIGGING:
691 case TV_BLUNT:
692 case TV_POLEARM:
693 case TV_SWORD:
694 case TV_BOOTS:
695 case TV_GLOVES:
696 case TV_HELM:
697 case TV_CROWN:
698 case TV_SHIELD:
699 case TV_CLOAK:
700 case TV_SOFT_ARMOR:
701 case TV_HARD_ARMOR:
702 case TV_DRAG_ARMOR:
703 case TV_AXE:
704 case TV_TRAPKIT:
705
706 case TV_MSTAFF:
707
708 case TV_SHOT:
709 case TV_ARROW:
710 case TV_BOLT:
711 case TV_BOW:
712 case TV_BOOMERANG:
713 quality = ((o_ptr->ident & ID_SENSE_HEAVY) ? quality_check_aux1(o_ptr) :
714 quality_check_aux2(o_ptr));
715 break;
716
717 case TV_SCROLL:
718 case TV_POTION:
719 case TV_POTION2:
720 case TV_WAND:
721 case TV_STAFF:
722 case TV_ROD:
723 case TV_FOOD:
724 return 0;
725 }
726
727 return quality;
728 }
729 #endif
730
731 /*
732 * Regenerate hit points -RAK-
733 */
regenhp(int Ind,int percent)734 static void regenhp(int Ind, int percent)
735 {
736 player_type *p_ptr = Players[Ind];
737
738 s32b new_chp, new_chp_frac;
739 int old_chp;
740 int freeze_test_heal = p_ptr->test_heal;
741
742 /* Save the old hitpoints */
743 old_chp = p_ptr->chp;
744
745 /* Extract the new hitpoints */
746 new_chp = ((s32b)p_ptr->mhp) * percent + PY_REGEN_HPBASE;
747 /* Apply the healing */
748 hp_player_quiet(Ind, new_chp >> 16, TRUE);
749 //p_ptr->chp += new_chp >> 16; /* div 65536 */
750
751 /* check for overflow -- this is probably unneccecary */
752 if ((p_ptr->chp < 0) && (old_chp > 0)) p_ptr->chp = MAX_SHORT;
753
754 /* handle fractional hit point healing */
755 new_chp_frac = (new_chp & 0xFFFF) + p_ptr->chp_frac; /* mod 65536 */
756 if (new_chp_frac >= 0x10000L) {
757 hp_player_quiet(Ind, 1, TRUE);
758 p_ptr->chp_frac = new_chp_frac - 0x10000L;
759 } else {
760 p_ptr->chp_frac = new_chp_frac;
761 }
762
763 p_ptr->test_heal = freeze_test_heal;
764 }
765
766
767 /*
768 * Regenerate mana points -RAK-
769 */
regenmana(int Ind,int percent)770 static void regenmana(int Ind, int percent) {
771 player_type *p_ptr = Players[Ind];
772 s32b new_mana, new_mana_frac;
773 int old_csp;
774
775 old_csp = p_ptr->csp;
776 new_mana = ((s32b)p_ptr->msp) * percent + PY_REGEN_MNBASE;
777
778 p_ptr->csp += new_mana >> 16; /* div 65536 */
779 /* check for overflow */
780 if ((p_ptr->csp < 0) && (old_csp > 0))
781 p_ptr->csp = MAX_SHORT;
782
783 new_mana_frac = (new_mana & 0xFFFF) + p_ptr->csp_frac; /* mod 65536 */
784 if (new_mana_frac >= 0x10000L) {
785 p_ptr->csp_frac = new_mana_frac - 0x10000L;
786 p_ptr->csp++;
787 } else {
788 p_ptr->csp_frac = new_mana_frac;
789 }
790
791 /* Must set frac to zero even if equal */
792 if (p_ptr->csp >= p_ptr->msp) {
793 p_ptr->csp = p_ptr->msp;
794 p_ptr->csp_frac = 0;
795 }
796
797 /* Redraw mana */
798 if (old_csp != p_ptr->csp) {
799 /* Redraw */
800 p_ptr->redraw |= (PR_MANA);
801
802 /* Window stuff */
803 p_ptr->window |= (PW_PLAYER);
804 }
805 }
806
807
808 #define pelpel
809 #ifdef pelpel
810
811 /* Wipeout the effects - Jir - */
erase_effects(int effect)812 static void erase_effects(int effect)
813 {
814 int i, j, l;
815 effect_type *e_ptr = &effects[effect];
816 worldpos *wpos = &e_ptr->wpos;
817 cave_type **zcave;
818 cave_type *c_ptr;
819 int rad = e_ptr->rad;
820 int cy = e_ptr->cy;
821 int cx = e_ptr->cx;
822
823 e_ptr->time = 0;
824
825 e_ptr->interval = 0;
826 e_ptr->type = 0;
827 e_ptr->dam = 0;
828 e_ptr->time = 0;
829 e_ptr->flags = 0;
830 e_ptr->sx = 0;
831 e_ptr->sy = 0;
832 e_ptr->cx = 0;
833 e_ptr->cy = 0;
834 e_ptr->rad = 0;
835
836 if (!(zcave = getcave(wpos))) return;
837
838 /* XXX +1 is needed.. */
839 for (l = 0; l < tdi[rad + 0]; l++)
840 {
841 j = cy + tdy[l];
842 i = cx + tdx[l];
843 if (!in_bounds2(wpos, j, i)) continue;
844
845 c_ptr = &zcave[j][i];
846
847 if (c_ptr->effect == effect)
848 {
849 c_ptr->effect = 0;
850 everyone_lite_spot(wpos, j, i);
851 }
852 }
853 }
854
855 /*
856 * Handle staying spell effects once every 10 game turns
857 */
858 /*
859 * TODO:
860 * - excise dead effect for efficiency
861 * - allow players/monsters to 'cancel' the effect
862 * - implement EFF_LAST eraser (for now, no spell has this flag)
863 * - reduce the use of everyone_lite_spot (one call, one packet)
864 */
865 /*
866 * XXX Check it:
867 * - what happens if the player dies?
868 * - what happens to the storm/wave when player changes floor?
869 * (A. the storm is left on the original floor, and still try to follow
870 * the caster, pfft)
871 */
872 /* Set these to animate the colours of an effect if they aren't already flickering
873 colours such as TERM_POIS etc. but instead static colours that are picked randomly
874 in spell_color(). - C. Blue */
875 #define ANIMATE_EFFECTS /* animates spell_color() randomness, costs more bandwidth */
876 #define FREQUENT_EFFECT_ANIMATION /* costs even more bandwidth */
process_effects(void)877 static void process_effects(void) {
878 int i, j, k, l;
879 worldpos *wpos;
880 cave_type **zcave;
881 cave_type *c_ptr;
882 int who = PROJECTOR_EFFECT;
883 player_type *p_ptr;
884
885 /* Every 10 game turns */
886 // if (turn % 10) return;
887
888 /* Not in the small-scale wilderness map */
889 // if (p_ptr->wild_mode) return;
890
891
892 for (k = 0; k < MAX_EFFECTS; k++) {
893 // int e = cave[j][i].effect;
894 effect_type *e_ptr = &effects[k];
895
896 /* Skip empty slots */
897 if (e_ptr->time == 0) continue;
898
899 wpos = &e_ptr->wpos;
900 if (!(zcave = getcave(wpos))) {
901 e_ptr->time = 0;
902 /* TODO - excise it */
903 continue;
904 }
905
906 #ifdef ARCADE_SERVER
907 #if 0
908 if ((e_ptr->flags & EFF_CROSSHAIR_A) || (e_ptr->flags & EFF_CROSSHAIR_B) || (e_ptr->flags & EFF_CROSSHAIR_C)) {
909
910 /* e_ptr->interval is player who controls it */
911 if (e_ptr->interval >= NumPlayers) {
912 p_ptr = Players[e_ptr->interval];
913 if (k == p_ptr->e) {
914 if (e_ptr->cy != p_ptr->arc_b || e_ptr->cx != p_ptr->arc_a) {
915 if (!in_bounds2(wpos, e_ptr->cy, e_ptr->cx)) continue;
916 c_ptr = &zcave[e_ptr->cy][e_ptr->cx];
917 c_ptr->effect = 0;
918 everyone_lite_spot(wpos, e_ptr->cy, e_ptr->cx);
919 e_ptr->cy = p_ptr->arc_b;
920 e_ptr->cx = p_ptr->arc_a;
921 if (!in_bounds2(wpos, e_ptr->cy, e_ptr->cx)) continue;
922 c_ptr = &zcave[e_ptr->cy][e_ptr->cx];
923 c_ptr->effect = k;
924 everyone_lite_spot(wpos, e_ptr->cy, e_ptr->cx);
925 }
926
927 } else {
928 erase_effects(k);
929 }
930 } else {
931 erase_effects(k);
932 }
933 continue;
934 }
935 #endif
936 #endif
937
938 #ifndef EXTENDED_TERM_COLOURS
939 #ifdef ANIMATE_EFFECTS
940 #ifdef FREQUENT_EFFECT_ANIMATION
941 /* hack: animate the effect! Note that this is independant of the effect interval,
942 as opposed to the other animation code below. - C. Blue */
943 if (!(turn % (cfg.fps / 5)) && e_ptr->time && spell_color_animation(e_ptr->type))
944 for (l = 0; l < tdi[e_ptr->rad]; l++) {
945 j = e_ptr->cy + tdy[l];
946 i = e_ptr->cx + tdx[l];
947 if (!in_bounds2(wpos, j, i)) continue;
948 everyone_lite_spot(wpos, j, i);
949 }
950 #endif
951 #endif
952 #endif
953
954 /* check if it's time to process this effect now (depends on level_speed) */
955 if ((turn % (e_ptr->interval * level_speed(wpos) / (level_speeds[0] * 5))) != 0) continue;
956
957 /* Reduce duration */
958 e_ptr->time--;
959
960 /* It ends? */
961 if (e_ptr->time <= 0) {
962 erase_effects(k);
963 continue;
964 }
965
966 /* effect belongs to a non-player? */
967 if (e_ptr->who > 0) who = e_ptr->who;
968 else { /* or to a player? */
969 /* Make the effect friendly after logging out - mikaelh */
970 who = PROJECTOR_PLAYER;
971
972 /* XXX Hack -- is the trapper online? */
973 for (i = 1; i <= NumPlayers; i++) {
974 p_ptr = Players[i];
975
976 /* Check if they are in here */
977 if (e_ptr->who != 0 - p_ptr->id) continue;
978
979 /* additionally check if player left level --
980 avoids panic save on killing a dungeon boss with a lasting effect while
981 already having been prematurely recalled to town meanwhile (insta-res!) - C. Blue */
982 if (!inarea(&p_ptr->wpos, wpos)) break;
983
984 /* it's fine */
985 who = 0 - i;
986 break;
987 }
988 }
989
990 /* Storm ends if the cause is gone */
991 if (e_ptr->flags & EFF_STORM && (who == PROJECTOR_EFFECT || who == PROJECTOR_PLAYER)) {
992 erase_effects(k);
993 continue;
994 }
995
996 /* Snowflakes disappear if they reach end of traversed screen */
997 if ((e_ptr->flags & EFF_SNOWING) && e_ptr->cy == MAX_HGT - 2) {
998 erase_effects(k);
999 continue;
1000 }
1001 /* Raindrops disappear if they reach end of traversed screen */
1002 if ((e_ptr->flags & EFF_RAINING) && e_ptr->cy == MAX_HGT - 2) {
1003 erase_effects(k);
1004 continue;
1005 }
1006
1007 /* Handle spell effects */
1008 for (l = 0; l < tdi[e_ptr->rad]; l++) {
1009 j = e_ptr->cy + tdy[l];
1010 i = e_ptr->cx + tdx[l];
1011 if (!in_bounds2(wpos, j, i)) continue;
1012
1013 c_ptr = &zcave[j][i];
1014
1015 //if (c_ptr->effect != k) continue;
1016 if (c_ptr->effect != k) /* Nothing */;
1017 else {
1018 if (e_ptr->time) {
1019 int flg = PROJECT_NORF | PROJECT_GRID | PROJECT_KILL | PROJECT_ITEM | PROJECT_HIDE | PROJECT_JUMP;
1020 //PROJECT_KILL | PROJECT_ITEM | PROJECT_HIDE | PROJECT_JUMP
1021
1022 flg = mod_ball_spell_flags(e_ptr->type, flg);
1023
1024 /* Apply damage */
1025 project(who, 0, wpos, j, i, e_ptr->dam, e_ptr->type, flg, "");
1026
1027 /* Oh, destroyed? RIP */
1028 if (who < 0 && who != PROJECTOR_EFFECT && who != PROJECTOR_PLAYER &&
1029 Players[0 - who]->conn == NOT_CONNECTED)
1030 {
1031 /* Make the effect friendly after death - mikaelh */
1032 who = PROJECTOR_PLAYER;
1033 }
1034
1035 #ifndef EXTENDED_TERM_COLOURS
1036 #ifdef ANIMATE_EFFECTS
1037 #ifndef FREQUENT_EFFECT_ANIMATION
1038 /* C. Blue - hack: animate effects inbetween
1039 ie allow random changes in spell_color().
1040 Note: animation speed depends on effect interval. */
1041 if (spell_color_animation(e_ptr->type))
1042 everyone_lite_spot(wpos, j, i);
1043 #endif
1044 #endif
1045 #endif
1046 } else {
1047 c_ptr->effect = 0;
1048 everyone_lite_spot(wpos, j, i);
1049 }
1050
1051 /* Hack -- notice death */
1052 // if (!alive || death) return;
1053 /* Storm ends if the cause is gone */
1054 if (e_ptr->flags & EFF_STORM &&
1055 (who == PROJECTOR_PLAYER || Players[0 - who]->death)) {
1056 erase_effects(k);
1057 break;
1058 }
1059 }
1060
1061
1062 #if 0
1063 if (((e_ptr->flags & EFF_WAVE) && !(e_ptr->flags & EFF_LAST)) || ((e_ptr->flags & EFF_STORM) && !(e_ptr->flags & EFF_LAST))) {
1064 if (distance(e_ptr->cy, e_ptr->cx, j, i) < e_ptr->rad - 2)
1065 c_ptr->effect = 0;
1066 }
1067 #else // 0
1068
1069 if (!(e_ptr->flags & EFF_LAST)) {
1070 if ((e_ptr->flags & EFF_WAVE)) {
1071 if (distance(e_ptr->cy, e_ptr->cx, j, i) < e_ptr->rad - 2) {
1072 c_ptr->effect = 0;
1073 everyone_lite_spot(wpos, j, i);
1074 }
1075 } else if ((e_ptr->flags & EFF_STORM)) {
1076 c_ptr->effect = 0;
1077 everyone_lite_spot(wpos, j, i);
1078 } else if ((e_ptr->flags & EFF_SNOWING)) {
1079 c_ptr->effect = 0;
1080 everyone_lite_spot(wpos, j, i);
1081 } else if ((e_ptr->flags & EFF_RAINING)) {
1082 c_ptr->effect = 0;
1083 everyone_lite_spot(wpos, j, i);
1084 } else if (e_ptr->flags & (EFF_FIREWORKS1 | EFF_FIREWORKS2 | EFF_FIREWORKS3)) {
1085 c_ptr->effect = 0;
1086 everyone_lite_spot(wpos, j, i);
1087 #if 0 /* no need to erase inbetween, while effect is still expanding - at the same time this fixes ugly tile flickering from redrawing (lava!) */
1088 } else if (e_ptr->flags & (EFF_LIGHTNING1 | EFF_LIGHTNING2 | EFF_LIGHTNING3)) {
1089 c_ptr->effect = 0;
1090 everyone_lite_spot(wpos, j, i);
1091 #endif
1092 }
1093 }
1094 #endif // 0
1095
1096 /* Creates a "wave" effect*/
1097 if (e_ptr->flags & EFF_WAVE) {
1098 if (los(wpos, e_ptr->cy, e_ptr->cx, j, i) &&
1099 (distance(e_ptr->cy, e_ptr->cx, j, i) == e_ptr->rad)) {
1100 c_ptr->effect = k;
1101 everyone_lite_spot(wpos, j, i);
1102 }
1103 }
1104
1105 /* Generate fireworks effects */
1106 if (e_ptr->flags & (EFF_FIREWORKS1 | EFF_FIREWORKS2 | EFF_FIREWORKS3)) {
1107 int semi = (e_ptr->time + e_ptr->rad) / 2;
1108 /* until half-time (or half-radius) the fireworks rise into the air */
1109 if (e_ptr->rad < e_ptr->time) {
1110 if (i == e_ptr->cx && j == e_ptr->cy - e_ptr->rad) {
1111 c_ptr->effect = k;
1112 everyone_lite_spot(wpos, j, i);
1113 }
1114 } else { /* after that, they explode (w00t) */
1115 /* explosion is faster than flying upwards */
1116 //doesn't work e_ptr->interval = 2;
1117
1118 #ifdef USE_SOUND_2010
1119 if (e_ptr->rad == e_ptr->time) {
1120 if ((e_ptr->flags & EFF_FIREWORKS3))
1121 //sound_near_site(e_ptr->cy, e_ptr->cx, wpos, 0, "fireworks_big", "", SFX_TYPE_AMBIENT, FALSE);
1122 sound_floor_vol(wpos, "fireworks_big", "", SFX_TYPE_AMBIENT, randint(26) + 75);
1123 else if ((e_ptr->flags & EFF_FIREWORKS2))
1124 //sound_near_site(e_ptr->cy, e_ptr->cx, wpos, 0, "fireworks_norm", "", SFX_TYPE_AMBIENT, FALSE);
1125 sound_floor_vol(wpos, "fireworks_norm", "", SFX_TYPE_AMBIENT, randint(26) + 75);
1126 else
1127 //sound_near_site(e_ptr->cy, e_ptr->cx, wpos, 0, "fireworks_small", "", SFX_TYPE_AMBIENT, FALSE);
1128 sound_floor_vol(wpos, "fireworks_small", "", SFX_TYPE_AMBIENT, randint(26) + 75);
1129 }
1130 #endif
1131
1132 #if 0
1133 if (e_ptr->flags & EFF_FIREWORKS1) { /* simple rocket (line) */
1134 if (i == e_ptr->cx && j == e_ptr->cy - e_ptr->rad) {
1135 c_ptr->effect = k;
1136 everyone_lite_spot(wpos, j, i);
1137 }
1138 #endif
1139 if (e_ptr->flags & EFF_FIREWORKS1) { /* 3-star */
1140 if (((i == e_ptr->cx && j >= e_ptr->cy - e_ptr->rad) && /* up */
1141 (i == e_ptr->cx && j <= e_ptr->cy + 1 - e_ptr->rad)) ||
1142 ((i >= e_ptr->cx + semi - e_ptr->rad && j == e_ptr->cy - semi) && /* left */
1143 (i <= e_ptr->cx + semi + 1 - e_ptr->rad && j == e_ptr->cy - semi)) ||
1144 ((i <= e_ptr->cx - semi + e_ptr->rad && j == e_ptr->cy - semi) && /* right */
1145 (i >= e_ptr->cx - semi - 1 + e_ptr->rad && j == e_ptr->cy - semi))) {
1146 c_ptr->effect = k;
1147 everyone_lite_spot(wpos, j, i);
1148 }
1149 } else if (e_ptr->flags & EFF_FIREWORKS2) { /* 5-star */
1150 if (((i == e_ptr->cx && j >= e_ptr->cy - e_ptr->rad) && /* up */
1151 (i == e_ptr->cx && j <= e_ptr->cy + 1 - e_ptr->rad)) ||
1152 ((i >= e_ptr->cx + semi - e_ptr->rad && j >= e_ptr->cy - e_ptr->rad) && /* up-left */
1153 (i <= e_ptr->cx + semi + 1 - e_ptr->rad && j <= e_ptr->cy + 1 - e_ptr->rad)) ||
1154 ((i <= e_ptr->cx - semi + e_ptr->rad && j >= e_ptr->cy - e_ptr->rad) && /* up-right */
1155 (i >= e_ptr->cx - semi - 1 + e_ptr->rad && j <= e_ptr->cy + 1 - e_ptr->rad)) ||
1156 ((i >= e_ptr->cx + semi - e_ptr->rad && j <= e_ptr->cy - 2 * semi + e_ptr->rad) && /* down-left */
1157 (i <= e_ptr->cx + semi + 1 - e_ptr->rad && j >= e_ptr->cy - 0 - 2 * semi + e_ptr->rad)) ||
1158 ((i <= e_ptr->cx - semi + e_ptr->rad && j <= e_ptr->cy - 2 * semi + e_ptr->rad) && /* down-right */
1159 (i >= e_ptr->cx - semi - 1 + e_ptr->rad && j >= e_ptr->cy - 0 - 2 * semi + e_ptr->rad))) {
1160 c_ptr->effect = k;
1161 everyone_lite_spot(wpos, j, i);
1162 }
1163 } else { /* EFF_FIREWORKS3 */ /* 7-star whoa */
1164 if (((i == e_ptr->cx && j >= e_ptr->cy - e_ptr->rad) && /* up */
1165 (i == e_ptr->cx && j <= e_ptr->cy + 1 - e_ptr->rad)) ||
1166 ((i >= e_ptr->cx + semi - e_ptr->rad && j == e_ptr->cy - semi) && /* left */
1167 (i <= e_ptr->cx + semi + 1 - e_ptr->rad && j == e_ptr->cy - semi)) ||
1168 ((i <= e_ptr->cx - semi + e_ptr->rad && j == e_ptr->cy - semi) && /* right */
1169 (i >= e_ptr->cx - semi - 1 + e_ptr->rad && j == e_ptr->cy - semi)) ||
1170 ((i >= e_ptr->cx + semi - e_ptr->rad && j >= e_ptr->cy - e_ptr->rad) && /* up-left */
1171 (i <= e_ptr->cx + semi + 1 - e_ptr->rad && j <= e_ptr->cy + 1 - e_ptr->rad)) ||
1172 ((i <= e_ptr->cx - semi + e_ptr->rad && j >= e_ptr->cy - e_ptr->rad) && /* up-right */
1173 (i >= e_ptr->cx - semi - 1 + e_ptr->rad && j <= e_ptr->cy + 1 - e_ptr->rad)) ||
1174 ((i >= e_ptr->cx + semi - e_ptr->rad && j <= e_ptr->cy - 2 * semi + e_ptr->rad) && /* down-left */
1175 (i <= e_ptr->cx + semi + 1 - e_ptr->rad && j >= e_ptr->cy - 0 - 2 * semi + e_ptr->rad)) ||
1176 ((i <= e_ptr->cx - semi + e_ptr->rad && j <= e_ptr->cy - 2 * semi + e_ptr->rad) && /* down-right */
1177 (i >= e_ptr->cx - semi - 1 + e_ptr->rad && j >= e_ptr->cy - 0 - 2 * semi + e_ptr->rad))) {
1178 c_ptr->effect = k;
1179 everyone_lite_spot(wpos, j, i);
1180 }
1181 }
1182 }
1183 }
1184
1185 /* Generate lightning effects -- effect_xtra: -1\ 0| 1/ 2_ */
1186 if (e_ptr->flags & (EFF_LIGHTNING1 | EFF_LIGHTNING2 | EFF_LIGHTNING3)) {
1187 int mirrored = (e_ptr->dam == 0) ? -1 : 1;
1188
1189 if ((e_ptr->flags & EFF_LIGHTNING1)) {
1190 int stage = e_ptr->rad;
1191
1192 if (stage > 15) stage = 15; /* afterglow */
1193
1194 switch (stage) {
1195 case 15:
1196 if (i == e_ptr->cx + mirrored * 14 && j == e_ptr->cy + 4) {///
1197 c_ptr->effect = k;
1198 c_ptr->effect_xtra = -mirrored;
1199 everyone_lite_spot(wpos, j, i);
1200 }
1201 case 14:
1202 if (i == e_ptr->cx + mirrored * 13 && j == e_ptr->cy + 3) {//_
1203 c_ptr->effect = k;
1204 c_ptr->effect_xtra = 2;
1205 everyone_lite_spot(wpos, j, i);
1206 }
1207 case 13:
1208 if (i == e_ptr->cx + mirrored * 12 && j == e_ptr->cy + 3) {///
1209 c_ptr->effect = k;
1210 c_ptr->effect_xtra = -mirrored;
1211 everyone_lite_spot(wpos, j, i);
1212 }
1213 if (i == e_ptr->cx + mirrored * 6 && j == e_ptr->cy + 5) {//_
1214 c_ptr->effect = k;
1215 c_ptr->effect_xtra = 2;
1216 everyone_lite_spot(wpos, j, i);
1217 }
1218 case 12:
1219 if (i == e_ptr->cx + mirrored * 11 && j == e_ptr->cy + 2) {//_
1220 c_ptr->effect = k;
1221 c_ptr->effect_xtra = 2;
1222 everyone_lite_spot(wpos, j, i);
1223 }
1224 if (i == e_ptr->cx + mirrored * 5 && j == e_ptr->cy + 5) {//_
1225 c_ptr->effect = k;
1226 c_ptr->effect_xtra = 2;
1227 everyone_lite_spot(wpos, j, i);
1228 }
1229 case 11:
1230 if (i == e_ptr->cx + mirrored * 10 && j == e_ptr->cy + 2) {//_
1231 c_ptr->effect = k;
1232 c_ptr->effect_xtra = 2;
1233 everyone_lite_spot(wpos, j, i);
1234 }
1235 if (i == e_ptr->cx + mirrored * 4 && j == e_ptr->cy + 5) {///
1236 c_ptr->effect = k;
1237 c_ptr->effect_xtra = -mirrored;
1238 everyone_lite_spot(wpos, j, i);
1239 }
1240 case 10:
1241 if (i == e_ptr->cx + mirrored * 9 && j == e_ptr->cy + 2) {//_
1242 c_ptr->effect = k;
1243 c_ptr->effect_xtra = 2;
1244 everyone_lite_spot(wpos, j, i);
1245 }
1246 if (i == e_ptr->cx + mirrored * 3 && j == e_ptr->cy + 4) {///
1247 c_ptr->effect = k;
1248 c_ptr->effect_xtra = -mirrored;
1249 everyone_lite_spot(wpos, j, i);
1250 }
1251 case 9:
1252 if (i == e_ptr->cx + mirrored * 8 && j == e_ptr->cy + 2) {///
1253 c_ptr->effect = k;
1254 c_ptr->effect_xtra = -mirrored;
1255 everyone_lite_spot(wpos, j, i);
1256 }
1257 if (i == e_ptr->cx + mirrored * 3 && j == e_ptr->cy + 3) {//_
1258 c_ptr->effect = k;
1259 c_ptr->effect_xtra = 2;
1260 everyone_lite_spot(wpos, j, i);
1261 }
1262 case 8:
1263 if (i == e_ptr->cx + mirrored * 7 && j == e_ptr->cy + 1) {//_
1264 c_ptr->effect = k;
1265 c_ptr->effect_xtra = 2;
1266 everyone_lite_spot(wpos, j, i);
1267 }
1268 if (i == e_ptr->cx + mirrored * 4 && j == e_ptr->cy + 3) {//`
1269 c_ptr->effect = k;
1270 c_ptr->effect_xtra = mirrored;
1271 everyone_lite_spot(wpos, j, i);
1272 }
1273 case 7:
1274 if (i == e_ptr->cx + mirrored * 6 && j == e_ptr->cy + 1) {//_
1275 c_ptr->effect = k;
1276 c_ptr->effect_xtra = 2;
1277 everyone_lite_spot(wpos, j, i);
1278 }
1279 if (i == e_ptr->cx + mirrored * 5 && j == e_ptr->cy + 2) {//`
1280 c_ptr->effect = k;
1281 c_ptr->effect_xtra = mirrored;
1282 everyone_lite_spot(wpos, j, i);
1283 }
1284 case 6:
1285 if (i == e_ptr->cx + mirrored * 5 && j == e_ptr->cy + 1) {//_
1286 c_ptr->effect = k;
1287 c_ptr->effect_xtra = 2;
1288 everyone_lite_spot(wpos, j, i);
1289 }
1290 case 5:
1291 if (i == e_ptr->cx + mirrored * 4 && j == e_ptr->cy + 1) {///
1292 c_ptr->effect = k;
1293 c_ptr->effect_xtra = -mirrored;
1294 everyone_lite_spot(wpos, j, i);
1295 }
1296 case 4:
1297 if (i == e_ptr->cx + mirrored * 3 && j == e_ptr->cy) {//_
1298 c_ptr->effect = k;
1299 c_ptr->effect_xtra = 2;
1300 everyone_lite_spot(wpos, j, i);
1301 }
1302 case 3:
1303 if (i == e_ptr->cx + mirrored * 2 && j == e_ptr->cy) {//_
1304 c_ptr->effect = k;
1305 c_ptr->effect_xtra = 2;
1306 everyone_lite_spot(wpos, j, i);
1307 }
1308 case 2:
1309 if (i == e_ptr->cx + mirrored * 1 && j == e_ptr->cy) {//_
1310 c_ptr->effect = k;
1311 c_ptr->effect_xtra = 2;
1312 everyone_lite_spot(wpos, j, i);
1313 }
1314 case 1:
1315 if (i == e_ptr->cx && j == e_ptr->cy) {//_
1316 c_ptr->effect = k;
1317 c_ptr->effect_xtra = 2;
1318 everyone_lite_spot(wpos, j, i);
1319 }
1320 }
1321 } else if ((e_ptr->flags & EFF_LIGHTNING2)) {
1322 int stage = e_ptr->rad;
1323
1324 if (stage > 8) stage = 8; /* afterglow */
1325
1326 switch (stage) {
1327 case 8:
1328 if (i == e_ptr->cx + mirrored * 6 && j == e_ptr->cy + 5) {
1329 c_ptr->effect = k;
1330 c_ptr->effect_xtra = mirrored;
1331 everyone_lite_spot(wpos, j, i);
1332 }
1333 case 7:
1334 if (i == e_ptr->cx + mirrored * 6 && j == e_ptr->cy + 4) {
1335 c_ptr->effect = k;
1336 c_ptr->effect_xtra = -mirrored;
1337 everyone_lite_spot(wpos, j, i);
1338 }
1339 case 6:
1340 if (i == e_ptr->cx + mirrored * 5 && j == e_ptr->cy + 3) {
1341 c_ptr->effect = k;
1342 c_ptr->effect_xtra = 2;
1343 everyone_lite_spot(wpos, j, i);
1344 }
1345 if (i == e_ptr->cx - mirrored * (4+1) && j == e_ptr->cy + 3) {
1346 c_ptr->effect = k;
1347 c_ptr->effect_xtra = 2;
1348 everyone_lite_spot(wpos, j, i);
1349 }
1350 case 5:
1351 if (i == e_ptr->cx + mirrored * 4 && j == e_ptr->cy + 3) {
1352 c_ptr->effect = k;
1353 c_ptr->effect_xtra = -mirrored;
1354 everyone_lite_spot(wpos, j, i);
1355 }
1356 if (i == e_ptr->cx - mirrored * (3+1) && j == e_ptr->cy + 3) {
1357 c_ptr->effect = k;
1358 c_ptr->effect_xtra = 2;
1359 everyone_lite_spot(wpos, j, i);
1360 }
1361 case 4:
1362 if (i == e_ptr->cx + mirrored * 3 && j == e_ptr->cy + 2) {
1363 c_ptr->effect = k;
1364 c_ptr->effect_xtra = 2;
1365 everyone_lite_spot(wpos, j, i);
1366 }
1367 if (i == e_ptr->cx - mirrored * (2+1) && j == e_ptr->cy + 3) {
1368 c_ptr->effect = k;
1369 c_ptr->effect_xtra = mirrored;
1370 everyone_lite_spot(wpos, j, i);
1371 }
1372 case 3:
1373 if (i == e_ptr->cx + mirrored * 2 && j == e_ptr->cy + 2) {
1374 c_ptr->effect = k;
1375 c_ptr->effect_xtra = -mirrored;
1376 everyone_lite_spot(wpos, j, i);
1377 }
1378 if (i == e_ptr->cx - mirrored * 2 && j == e_ptr->cy + 2) {
1379 c_ptr->effect = k;
1380 c_ptr->effect_xtra = 0;
1381 everyone_lite_spot(wpos, j, i);
1382 }
1383 case 2:
1384 if (i == e_ptr->cx + mirrored * 1 && j == e_ptr->cy + 1) {
1385 c_ptr->effect = k;
1386 c_ptr->effect_xtra = -mirrored;
1387 everyone_lite_spot(wpos, j, i);
1388 }
1389 if (i == e_ptr->cx - mirrored * 1 && j == e_ptr->cy + 1) {
1390 c_ptr->effect = k;
1391 c_ptr->effect_xtra = mirrored;
1392 everyone_lite_spot(wpos, j, i);
1393 }
1394 case 1:
1395 if (i == e_ptr->cx && j == e_ptr->cy) {
1396 c_ptr->effect = k;
1397 c_ptr->effect_xtra = 0;
1398 everyone_lite_spot(wpos, j, i);
1399 }
1400 }
1401 } else if ((e_ptr->flags & EFF_LIGHTNING3)) {
1402 int stage = e_ptr->rad;
1403
1404 if (stage > 10) stage = 10; /* afterglow */
1405
1406 switch (stage) {
1407 case 10:
1408 if (i == e_ptr->cx - mirrored * 8 && j == e_ptr->cy + 6) {
1409 c_ptr->effect = k;
1410 c_ptr->effect_xtra = 0;
1411 everyone_lite_spot(wpos, j, i);
1412 }
1413 case 9:
1414 if (i == e_ptr->cx - mirrored * 7 && j == e_ptr->cy + 5) {
1415 c_ptr->effect = k;
1416 c_ptr->effect_xtra = mirrored;
1417 everyone_lite_spot(wpos, j, i);
1418 }
1419 case 8:
1420 if (i == e_ptr->cx - mirrored * 6 && j == e_ptr->cy + 4) {
1421 c_ptr->effect = k;
1422 c_ptr->effect_xtra = mirrored;
1423 everyone_lite_spot(wpos, j, i);
1424 }
1425 case 7:
1426 if (i == e_ptr->cx - mirrored * 5 && j == e_ptr->cy + 3) {
1427 c_ptr->effect = k;
1428 c_ptr->effect_xtra = 0;
1429 everyone_lite_spot(wpos, j, i);
1430 }
1431 case 6:
1432 if (i == e_ptr->cx - mirrored * 5 && j == e_ptr->cy + 2) {
1433 c_ptr->effect = k;
1434 c_ptr->effect_xtra = mirrored;
1435 everyone_lite_spot(wpos, j, i);
1436 }
1437 if (i == e_ptr->cx - mirrored && j == e_ptr->cy + 4) {
1438 c_ptr->effect = k;
1439 c_ptr->effect_xtra = 0;
1440 everyone_lite_spot(wpos, j, i);
1441 }
1442 case 5:
1443 if (i == e_ptr->cx - mirrored * 4 && j == e_ptr->cy + 1) {
1444 c_ptr->effect = k;
1445 c_ptr->effect_xtra = 2;
1446 everyone_lite_spot(wpos, j, i);
1447 }
1448 if (i == e_ptr->cx - mirrored * 2 && j == e_ptr->cy + 3) {
1449 c_ptr->effect = k;
1450 c_ptr->effect_xtra = -mirrored;
1451 everyone_lite_spot(wpos, j, i);
1452 }
1453 case 4:
1454 if (i == e_ptr->cx - mirrored * 3 && j == e_ptr->cy + 1) {
1455 c_ptr->effect = k;
1456 c_ptr->effect_xtra = 2;
1457 everyone_lite_spot(wpos, j, i);
1458 }
1459 if (i == e_ptr->cx - mirrored * 3 && j == e_ptr->cy + 2) {
1460 c_ptr->effect = k;
1461 c_ptr->effect_xtra = 0;
1462 everyone_lite_spot(wpos, j, i);
1463 }
1464 case 3:
1465 if (i == e_ptr->cx - mirrored * 2 && j == e_ptr->cy + 1) {
1466 c_ptr->effect = k;
1467 c_ptr->effect_xtra = mirrored;
1468 everyone_lite_spot(wpos, j, i);
1469 }
1470 case 2:
1471 if (i == e_ptr->cx - mirrored * 1 && j == e_ptr->cy) {
1472 c_ptr->effect = k;
1473 c_ptr->effect_xtra = 2;
1474 everyone_lite_spot(wpos, j, i);
1475 }
1476 case 1:
1477 if (i == e_ptr->cx && j == e_ptr->cy) {
1478 c_ptr->effect = k;
1479 c_ptr->effect_xtra = mirrored;
1480 everyone_lite_spot(wpos, j, i);
1481 }
1482 }
1483 }
1484 }
1485 }
1486
1487 if (e_ptr->flags & EFF_WAVE) e_ptr->rad++;
1488 /* Creates a "storm" effect*/
1489 else if (e_ptr->flags & EFF_STORM && who > PROJECTOR_EFFECT) {
1490 p_ptr = Players[0 - who];
1491
1492 e_ptr->cy = p_ptr->py;
1493 e_ptr->cx = p_ptr->px;
1494
1495 for (l = 0; l < tdi[e_ptr->rad]; l++) {
1496 j = e_ptr->cy + tdy[l];
1497 i = e_ptr->cx + tdx[l];
1498 if (!in_bounds2(wpos, j, i)) continue;
1499
1500 c_ptr = &zcave[j][i];
1501
1502 if (los(wpos, e_ptr->cy, e_ptr->cx, j, i) &&
1503 (distance(e_ptr->cy, e_ptr->cx, j, i) <= e_ptr->rad))
1504 {
1505 c_ptr->effect = k;
1506 everyone_lite_spot(wpos, j, i);
1507 }
1508 }
1509 }
1510 /* snowflakes */
1511 else if (e_ptr->flags & EFF_SNOWING) {
1512 e_ptr->cy++; /* for now just fall straight downwards */
1513 /* gusts of wind */
1514 if (wind_gust > 0) {
1515 e_ptr->cx--;
1516 if (e_ptr->cx < 1) e_ptr->cx = MAX_WID - 2;
1517 }
1518 if (wind_gust < 0) {
1519 e_ptr->cx++;
1520 if (e_ptr->cx >= MAX_WID - 1) e_ptr->cx = 1;
1521 }
1522 c_ptr = &zcave[e_ptr->cy][e_ptr->cx];
1523 c_ptr->effect = k;
1524 everyone_lite_spot(wpos, e_ptr->cy, e_ptr->cx);
1525 }
1526 /* raindrops */
1527 else if (e_ptr->flags & EFF_RAINING) {
1528 e_ptr->cy++; /* for now just fall straight downwards */
1529 /* gusts of wind */
1530 if (wind_gust > 0) {
1531 e_ptr->cx--;
1532 if (e_ptr->cx < 1) e_ptr->cx = MAX_WID - 2;
1533 }
1534 if (wind_gust < 0) {
1535 e_ptr->cx++;
1536 if (e_ptr->cx >= MAX_WID - 1) e_ptr->cx = 1;
1537 }
1538 c_ptr = &zcave[e_ptr->cy][e_ptr->cx];
1539 c_ptr->effect = k;
1540 everyone_lite_spot(wpos, e_ptr->cy, e_ptr->cx);
1541 }
1542
1543 /* fireworks */
1544 else if (e_ptr->flags & (EFF_FIREWORKS1 | EFF_FIREWORKS2 | EFF_FIREWORKS3)) {
1545 e_ptr->rad++; /* while radius < time/2 -> "rise into the air", otherwise "explode" */
1546 }
1547
1548 /* lightning */
1549 else if ((e_ptr->flags & (EFF_LIGHTNING1 | EFF_LIGHTNING2 | EFF_LIGHTNING3))
1550 && e_ptr->rad < 15) {
1551 e_ptr->rad++;
1552 }
1553 }
1554
1555
1556
1557 /* Apply sustained effect in the player grid, if any */
1558 // apply_effect(py, px);
1559 }
1560
1561 #endif /* pelpel */
1562
1563
1564
1565 /*
1566 * Queued drawing at the beginning of a new turn.
1567 */
1568 static void process_lite_later(void)
1569 {
1570 int i;
1571 struct worldspot *wspot;
1572
1573 for (i = 0; i < lite_later_num; i++)
1574 {
1575 wspot = &lite_later[i];
1576
1577 /* Draw now */
1578 everyone_lite_spot(&wspot->wpos, wspot->y, wspot->x);
1579 }
1580
1581 /* All done */
1582 lite_later_num = 0;
1583 }
1584
1585
1586
1587 /*
1588 * Regenerate the monsters (once per 100 game turns)
1589 *
1590 * XXX XXX XXX Should probably be done during monster turns.
1591 */
1592 /* Note that since this is done in real time, monsters will regenerate
1593 * faster in game time the deeper they are in the dungeon.
1594 */
1595 static void regen_monsters(void)
1596 {
1597 int i, frac;
1598
1599 /* Regenerate everyone */
1600 for (i = 1; i < m_max; i++)
1601 {
1602 /* Check the i'th monster */
1603 monster_type *m_ptr = &m_list[i];
1604 monster_race *r_ptr = race_inf(m_ptr);
1605
1606 /* Skip dead monsters */
1607 if (!m_ptr->r_idx) continue;
1608
1609 /* Allow regeneration (if needed) */
1610 if (m_ptr->hp < m_ptr->maxhp)
1611 {
1612 /* Hack -- Base regeneration */
1613 frac = m_ptr->maxhp / 100;
1614
1615 /* Hack -- Minimal regeneration rate */
1616 if (!frac) frac = 1;
1617
1618 /* Hack -- Some monsters regenerate quickly */
1619 if (r_ptr->flags2 & RF2_REGENERATE) frac *= 2;
1620
1621 /* Hack -- Regenerate */
1622 m_ptr->hp += frac;
1623
1624 /* Do not over-regenerate */
1625 if (m_ptr->hp > m_ptr->maxhp) m_ptr->hp = m_ptr->maxhp;
1626
1627 /* Update health bars */
1628 update_health(i);
1629 }
1630 }
1631 }
1632
1633
1634
1635 /* update a particular player's view to daylight, assuming he's on world surface */
1636 bool player_day(int Ind) {
1637 player_type *p_ptr = Players[Ind];
1638 int x, y;
1639 struct dun_level *l_ptr = getfloor(&p_ptr->wpos);
1640
1641 if (p_ptr->wpos.wz) return FALSE;
1642 if (in_sector00(&p_ptr->wpos))
1643 return FALSE;
1644 if (l_ptr && (l_ptr->flags2 & LF2_INDOORS)) return FALSE;
1645
1646 // if (p_ptr->tim_watchlist) p_ptr->tim_watchlist--;
1647 if (p_ptr->prace == RACE_VAMPIRE ||
1648 (p_ptr->body_monster && r_info[p_ptr->body_monster].d_char == 'V'))
1649 calc_boni(Ind); /* daylight */
1650
1651 /* Hack -- Scan the level */
1652 for (y = 0; y < MAX_HGT; y++)
1653 for (x = 0; x < MAX_WID; x++) {
1654 /* Hack -- Memorize lit grids if allowed */
1655 if (istownarea(&p_ptr->wpos, MAX_TOWNAREA)
1656 && (p_ptr->view_perma_grids)) {
1657 p_ptr->cave_flag[y][x] |= CAVE_MARK;
1658 }
1659 note_spot(Ind, y, x);
1660 }
1661
1662 /* Update the monsters */
1663 p_ptr->update |= (PU_MONSTERS);
1664 /* Redraw map */
1665 p_ptr->redraw |= (PR_MAP);
1666 /* Window stuff */
1667 p_ptr->window |= (PW_OVERHEAD);
1668
1669 #ifdef USE_SOUND_2010
1670 if (p_ptr->is_day) return FALSE;
1671 p_ptr->is_day = TRUE;
1672 handle_music(Ind);
1673 {
1674 cave_type **zcave;
1675 if (!(zcave = getcave(&p_ptr->wpos))) {
1676 s_printf("DEBUG_DAY: Ind %d, wpos %d,%d,%d\n", Ind, p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz);
1677 return FALSE; /* paranoia */
1678 }
1679 handle_ambient_sfx(Ind, &zcave[p_ptr->py][p_ptr->px], &p_ptr->wpos, TRUE);
1680 }
1681 #endif
1682
1683 return TRUE;
1684 }
1685 /* update a particular player's view to night, assuming he's on world surface */
1686 bool player_night(int Ind) {
1687 player_type *p_ptr = Players[Ind];
1688 cave_type **zcave = getcave(&p_ptr->wpos);
1689 int x, y;
1690 struct dun_level *l_ptr = getfloor(&p_ptr->wpos);
1691
1692 if (!zcave) return FALSE; /* paranoia */
1693
1694 if (p_ptr->wpos.wz) return FALSE;
1695 if (in_sector00(&p_ptr->wpos))
1696 return FALSE;
1697 if (l_ptr && (l_ptr->flags2 & LF2_INDOORS)) return FALSE;
1698
1699 // if (p_ptr->tim_watchlist) p_ptr->tim_watchlist--;
1700 if (p_ptr->prace == RACE_VAMPIRE ||
1701 (p_ptr->body_monster && r_info[p_ptr->body_monster].d_char == 'V'))
1702 calc_boni(Ind); /* no more daylight */
1703
1704 /* Hack -- Scan the level */
1705 for (y = 0; y < MAX_HGT; y++)
1706 for (x = 0; x < MAX_WID; x++) {
1707 /* Darken "boring" features */
1708 if (cave_plain_floor_grid(&zcave[y][x]) && !(zcave[y][x].info & CAVE_ROOM)) { /* keep house grids */
1709 /* Forget the grid */
1710 p_ptr->cave_flag[y][x] &= ~CAVE_MARK;
1711 /* Always remember interesting features in town areas */
1712 } else if (istownarea(&p_ptr->wpos, MAX_TOWNAREA)
1713 && (p_ptr->view_perma_grids)) {
1714 p_ptr->cave_flag[y][x] |= CAVE_MARK;
1715 }
1716
1717 note_spot(Ind, y, x);
1718 }
1719
1720 /* Update the monsters */
1721 p_ptr->update |= (PU_MONSTERS);
1722 /* Redraw map */
1723 p_ptr->redraw |= (PR_MAP);
1724 /* Window stuff */
1725 p_ptr->window |= (PW_OVERHEAD);
1726
1727 #ifdef USE_SOUND_2010
1728 if (!p_ptr->is_day) return FALSE;
1729 p_ptr->is_day = FALSE;
1730 handle_music(Ind);
1731 #if 0 /*done above already*/
1732 {
1733 cave_type **zcave;
1734 if (!(zcave = getcave(&p_ptr->wpos))) {
1735 s_printf("DEBUG_NIGHT: Ind %d, wpos %d,%d,%d\n", Ind, p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz);
1736 return FALSE; /* paranoia */
1737 }
1738 handle_ambient_sfx(Ind, &zcave[p_ptr->py][p_ptr->px], &p_ptr->wpos, TRUE);
1739 }
1740 #else
1741 handle_ambient_sfx(Ind, &zcave[p_ptr->py][p_ptr->px], &p_ptr->wpos, TRUE);
1742 #endif
1743 #endif
1744
1745 return TRUE;
1746 }
1747
1748 /* update a particular player's view as a town looks at night, just for dungeon towns */
1749 void player_dungeontown(int Ind) {
1750 player_type *p_ptr = Players[Ind];
1751 cave_type **zcave = getcave(&p_ptr->wpos);
1752 int x, y;
1753
1754 if (!zcave) return; /* paranoia */
1755 s_printf("DUNGEON_TOWN_MAP: %s\n", p_ptr->name);
1756
1757 /* Hack -- Scan the level */
1758 for (y = 0; y < MAX_HGT; y++)
1759 for (x = 0; x < MAX_WID; x++) {
1760 /* Always remember interesting features in town areas */
1761 #if 0
1762 if (!(cave_plain_floor_grid(&zcave[y][x]) && !(zcave[y][x].info & CAVE_ROOM))
1763 && p_ptr->view_perma_grids)
1764 #endif
1765 if (!(cave_plain_floor_grid(&zcave[y][x])) || (zcave[y][x].info & CAVE_ROOM))
1766 p_ptr->cave_flag[y][x] |= CAVE_MARK;
1767
1768 note_spot(Ind, y, x);
1769 }
1770
1771 /* Update the monsters */
1772 p_ptr->update |= (PU_MONSTERS);
1773 /* Redraw map */
1774 p_ptr->redraw |= (PR_MAP);
1775 /* Window stuff */
1776 p_ptr->window |= (PW_OVERHEAD);
1777 }
1778
1779 /* turn an allocated wpos to bright day and update view of players on it */
1780 void world_surface_day(struct worldpos *wpos) {
1781 cave_type **zcave = getcave(wpos), *c_ptr;
1782 struct dun_level *l_ptr = getfloor(wpos);
1783 int y, x;
1784
1785 if (!zcave) return; /* paranoia */
1786
1787 if (sector00separation && 0 == WPOS_SECTOR00_Z &&
1788 wpos->wx == WPOS_SECTOR00_X && wpos->wy == WPOS_SECTOR00_Y) return;
1789 if (l_ptr && (l_ptr->flags2 & LF2_INDOORS)) return;
1790
1791 /* Hack -- Scan the level */
1792 for (y = 0; y < MAX_HGT; y++)
1793 for (x = 0; x < MAX_WID; x++) {
1794 /* Get the cave grid */
1795 c_ptr = &zcave[y][x];
1796
1797 /* Assume lit */
1798 c_ptr->info |= CAVE_GLOW;
1799 c_ptr->info &= ~CAVE_DARKEN;
1800 }
1801 }
1802
1803 /* turn an allocated wpos to dark night and update view of players on it */
1804 void world_surface_night(struct worldpos *wpos) {
1805 cave_type **zcave = getcave(wpos), *c_ptr;
1806 struct dun_level *l_ptr = getfloor(wpos);
1807 int y, x;
1808 int stores = 0, y1, x1, i;
1809 byte sx[255], sy[255];
1810
1811 if (!zcave) return; /* paranoia */
1812
1813 if (sector00separation && 0 == WPOS_SECTOR00_Z &&
1814 wpos->wx == WPOS_SECTOR00_X && wpos->wy == WPOS_SECTOR00_Y) return;
1815 if (l_ptr && (l_ptr->flags2 & LF2_INDOORS)) return;
1816
1817 /* Hack -- Scan the level */
1818 for (y = 0; y < MAX_HGT; y++)
1819 for (x = 0; x < MAX_WID; x++) {
1820 /* Get the cave grid */
1821 c_ptr = &zcave[y][x];
1822
1823 /* darken all */
1824 if (!(f_info[c_ptr->feat].flags1 & FF1_PROTECTED) &&
1825 !(c_ptr->info & CAVE_ROOM)) { /* keep houses' contents lit */
1826 c_ptr->info &= ~CAVE_GLOW;
1827 c_ptr->info |= CAVE_DARKEN;
1828 }
1829
1830 if (c_ptr->feat == FEAT_SHOP && stores < 254) {
1831 sx[stores] = x;
1832 sy[stores] = y;
1833 stores++;
1834 }
1835 }
1836
1837 /* Hack -- illuminate the stores */
1838 for (i = 0; i < stores; i++) {
1839 x = sx[i];
1840 y = sy[i];
1841
1842 for (y1 = y - 1; y1 <= y + 1; y1++)
1843 for (x1 = x - 1; x1 <= x + 1; x1++) {
1844 /* Get the grid */
1845 c_ptr = &zcave[y1][x1];
1846
1847 /* Illuminate the store */
1848 // c_ptr->info |= CAVE_ROOM | CAVE_GLOW;
1849 c_ptr->info |= CAVE_GLOW;
1850 }
1851 }
1852 }
1853
1854 /* Day starts */
1855 static void sun_rises() {
1856 struct worldpos wrpos;
1857 int wx, wy, i;
1858
1859 night_surface = FALSE;
1860 wrpos.wz = 0;
1861
1862 /* scan through all currently allocated world surface levels */
1863 for (wx = 0; wx < MAX_WILD_X; wx++)
1864 for (wy = 0; wy < MAX_WILD_Y; wy++) {
1865 wrpos.wx = wx;
1866 wrpos.wy = wy;
1867 world_surface_day(&wrpos);
1868 }
1869
1870 /* Message all players who witness switch */
1871 for (i = 1; i <= NumPlayers; i++) {
1872 if (Players[i]->conn == NOT_CONNECTED) continue;
1873 if (player_day(i)) msg_print(i, "The sun has risen.");
1874 }
1875 }
1876
1877 /* Night starts */
1878 static void night_falls() {
1879 struct worldpos wrpos;
1880 int wx, wy, i;
1881
1882 night_surface = TRUE;
1883 wrpos.wz = 0;
1884
1885 /* scan through all currently allocated world surface levels */
1886 for (wx = 0; wx < MAX_WILD_X; wx++)
1887 for (wy = 0; wy < MAX_WILD_Y; wy++) {
1888 wrpos.wx = wx;
1889 wrpos.wy = wy;
1890 world_surface_night(&wrpos);
1891 }
1892
1893 /* Message all players who witness switch */
1894 for (i = 1; i <= NumPlayers; i++) {
1895 if (Players[i]->conn == NOT_CONNECTED) continue;
1896 if (player_night(i)) msg_print(i, "The sun has fallen.");
1897 }
1898
1899 /* If it's new year's eve, start the fireworks! */
1900 if (season_newyearseve) fireworks = 1;
1901 }
1902
1903 /* take care of day/night changes, on world surface.
1904 NOTE: assumes that it gets called every HOUR turns only! */
1905 static void process_day_and_night() {
1906 bool sunrise, nightfall;
1907
1908 /* Check for sunrise or nightfall */
1909 sunrise = (((turn / HOUR) % 24) == SUNRISE) && IS_DAY; /* IS_DAY checks for events, that's why it's here. - C. Blue */
1910 nightfall = (((turn / HOUR) % 24) == NIGHTFALL) && IS_NIGHT; /* IS_NIGHT is pointless at the time of coding this, just for consistencies sake with IS_DAY above. */
1911
1912 /* Day breaks - not during Halloween {>_>} or during NEW_YEARS_EVE (fireworks)! -- covered by IS_DAY now. */
1913 if (sunrise)
1914 sun_rises();
1915 /* Night falls - but only if it was actually day so far:
1916 During HALLOWEEN as well as NEW_YEARS_EVE it stays night all the time >:) (see above) */
1917 else if (nightfall && !night_surface)
1918 night_falls();
1919 }
1920
1921 /* Called when the server starts up */
1922 static void init_day_and_night() {
1923 if (IS_DAY)
1924 sun_rises();
1925 else /* assume IS_NIGHT ;) */
1926 night_falls();
1927 }
1928
1929 /*
1930 * Handle certain things once every 50 game turns
1931 */
1932
1933 static void process_world(int Ind)
1934 {
1935 player_type *p_ptr = Players[Ind];
1936 int i;
1937 // int regen_amount, NumPlayers_old = NumPlayers;
1938
1939
1940 /*** Process the monsters ***/
1941 /* Note : since monsters are added at a constant rate in real time,
1942 * this corresponds in game time to them appearing at faster rates
1943 * deeper in the dungeon.
1944 */
1945
1946 #if 0 //see below o_O
1947 /* Check for creature generation */
1948 if ((!istown(&p_ptr->wpos) && (rand_int(MAX_M_ALLOC_CHANCE) == 0)) ||
1949 #ifndef HALLOWEEN
1950 (istown(&p_ptr->wpos) && (rand_int(TOWNIE_RESPAWN_CHANCE * ((3 / NumPlayers) + 1)) == 0)))
1951 #else
1952 (istown(&p_ptr->wpos) && (rand_int((in_bree(&p_ptr->wpos) ?
1953 HALLOWEEN_TOWNIE_RESPAWN_CHANCE : TOWNIE_RESPAWN_CHANCE) * ((3 / NumPlayers) + 1)) == 0)))
1954 #endif
1955 #endif//0
1956
1957 /* Check for creature generation */
1958 #if 0 /* too many people idling all day.. ;) */
1959 if ((!istown(&p_ptr->wpos) && (rand_int(MAX_M_ALLOC_CHANCE) == 0)) ||
1960 (!season_halloween && (istown(&p_ptr->wpos) && (rand_int(TOWNIE_RESPAWN_CHANCE * ((3 / NumPlayers) + 1)) == 0))) ||
1961 (season_halloween && (istown(&p_ptr->wpos) && (rand_int((in_bree(&p_ptr->wpos) ?
1962 HALLOWEEN_TOWNIE_RESPAWN_CHANCE : TOWNIE_RESPAWN_CHANCE) * ((3 / NumPlayers) + 1)) == 0))))
1963 #else /* ..so no longer depending on amount of players in town: */
1964 if ((!istown(&p_ptr->wpos) && (rand_int(MAX_M_ALLOC_CHANCE) == 0)) ||
1965 (!season_halloween && istown(&p_ptr->wpos) && (rand_int(TOWNIE_RESPAWN_CHANCE) == 0)) ||
1966 (season_halloween && istown(&p_ptr->wpos) &&
1967 (rand_int(in_bree(&p_ptr->wpos) ?
1968 HALLOWEEN_TOWNIE_RESPAWN_CHANCE : TOWNIE_RESPAWN_CHANCE) == 0)))
1969 #endif
1970 {
1971 dun_level *l_ptr = getfloor(&p_ptr->wpos);
1972 /* Should we disallow those with MULTIPLY flags to spawn on surface? */
1973 if (!l_ptr || !(l_ptr->flags1 & LF1_NO_NEW_MONSTER))
1974 {
1975 /* Set the monster generation depth */
1976 monster_level = getlevel(&p_ptr->wpos);
1977
1978 if (p_ptr->wpos.wz) (void)alloc_monster(&p_ptr->wpos, MAX_SIGHT + 5, FALSE);
1979 else wild_add_monster(&p_ptr->wpos);
1980 }
1981 }
1982
1983 /* Every 1500 turns, warn about any Black Breath not gotten from an equipped
1984 * object, and stop any resting. -LM-
1985 */
1986 /* Probably better done in process_player_end? - Jir - */
1987 if (!(turn % 3000) && (p_ptr->black_breath))
1988 {
1989 msg_print(Ind, "\377WThe Black Breath saps your soul!");
1990
1991 /* alert to the neighbors also */
1992 msg_format_near(Ind, "\377WA dark aura seems to surround %s!", p_ptr->name);
1993
1994 disturb(Ind, 0, 0);
1995 }
1996
1997 /* Cold Turkey */
1998 i = (p_ptr->csane << 7) / p_ptr->msane;
1999 if (!(turn % 4200) && !magik(i))
2000 {
2001 msg_print(Ind, "\377rA flashback storms your head!");
2002
2003 /* alert to the neighbors also */
2004 if (magik(20)) msg_format_near(Ind, "You see %s's eyes bloodshot.", p_ptr->name);
2005
2006 set_image(Ind, p_ptr->image + 12 - i / 8);
2007 disturb(Ind, 0, 0);
2008 }
2009
2010 #ifdef GHOST_FADING
2011 if (p_ptr->ghost && !p_ptr->admin_dm &&
2012 // !(turn % GHOST_FADING))
2013 // !(turn % ((5100L - p_ptr->lev * 50)*GHOST_FADING)))
2014 !(turn % (GHOST_FADING / p_ptr->lev * 50)))
2015 // (rand_int(10000) < p_ptr->lev * p_ptr->lev))
2016 take_xp_hit(Ind, 1 + p_ptr->lev / 5 + p_ptr->max_exp / 10000L, "fading", TRUE, TRUE, FALSE);
2017 #endif // GHOST_FADING
2018
2019 }
2020
2021 /*
2022 * Quick hack to allow mimics to retaliate with innate powers - Jir -
2023 * It's high time we redesign auto-retaliator XXX
2024 */
2025 static int retaliate_mimic_power(int Ind, int choice)
2026 {
2027 player_type *p_ptr = Players[Ind];
2028 int i, k, num = 3;
2029
2030 /* Check for "okay" spells */
2031 for (k = 0; k < 3; k++) {
2032 for (i = 0; i < 32; i++) {
2033 /* Look for "okay" spells */
2034 if (p_ptr->innate_spells[k] & (1L << i)) {
2035 if (num == choice) return (k * 32 + i);
2036 num++;
2037 }
2038 }
2039 }
2040
2041 return (0);
2042 }
2043
2044 /*
2045 * Handle items for auto-retaliation - Jir -
2046 * use_old_target is *strongly* recommended to actually make use of it.
2047 * If fallback is TRUE the melee weapon will be used if the intended means failed. - C. Blue
2048 */
2049 static bool retaliate_item(int Ind, int item, cptr inscription, bool fallback) {
2050 player_type *p_ptr = Players[Ind];
2051 object_type *o_ptr;;
2052 int cost, choice = 0, spell = 0;
2053
2054 if (item < 0) return FALSE;
2055 o_ptr = &p_ptr->inventory[item];
2056 if (!o_ptr->k_idx) return FALSE;
2057
2058 /* 'Do nothing' inscription */
2059 if (inscription != NULL && *inscription == 'x') return TRUE;
2060
2061 /* Is it variant @Ot for town-only auto-retaliation? - C. Blue */
2062 if (*inscription == 't') {
2063 if (!istownarea(&p_ptr->wpos, MAX_TOWNAREA)) return FALSE;
2064 inscription++;
2065 }
2066
2067 #ifndef AUTO_RET_CMD
2068 /* Hack -- use innate power via inscription on any item */
2069 if (inscription != NULL && *inscription == 'M' && get_skill(p_ptr, SKILL_MIMIC)) {
2070 /* Spell to cast */
2071 if (*(inscription + 1)) {
2072 choice = *(inscription + 1) - 97;
2073
2074 /* valid inscription? */
2075 if (choice >= 0) {
2076 /* shape-changing for retaliation is not so nice idea, eh? */
2077 if (choice < 4) { /* 3 polymorph powers + immunity preference */
2078 #if 1
2079 return FALSE;
2080 #else
2081 /* hack: prevent 'polymorph into...' power */
2082 if (choice == 2) do_cmd_mimic(Ind, 1, 5);
2083 else do_cmd_mimic(Ind, choice, 5);
2084 return TRUE;
2085 #endif
2086 } else {
2087 int power = retaliate_mimic_power(Ind, choice - 1); /* immunity preference */
2088 bool dir = FALSE;
2089 if (innate_powers[power].smana > p_ptr->csp && fallback) return (p_ptr->fail_no_melee);
2090 #if 0
2091 if (power) {
2092 /* undirected power? */
2093 switch (power) {
2094 case 0:
2095 case 64: case 66:
2096 case 68: case 69:
2097 case 76:
2098 do_cmd_mimic(Ind, power + 3, 0);
2099 return TRUE;
2100 }
2101 /* power requires direction? */
2102 do_cmd_mimic(Ind, power + 3, 5);
2103 return TRUE;
2104 }
2105 #else
2106 switch (power / 32) {
2107 case 0: dir = monster_spells4[power].uses_dir;
2108 break;
2109 case 1: dir = monster_spells5[power - 32].uses_dir;
2110 break;
2111 case 2: dir = monster_spells6[power - 64].uses_dir;
2112 break;
2113 }
2114 do_cmd_mimic(Ind, power + 3, dir ? 5 : 0);
2115 return TRUE;
2116 #endif
2117 }
2118 }
2119 }
2120 return FALSE;
2121 }
2122 #endif
2123
2124 #ifndef AUTO_RET_NEW
2125 /* Only fighter classes can use various items for this */
2126 if (is_fighter(p_ptr)) {
2127 #if 0
2128 /* item with {@O-} is used only when in danger */
2129 if (*inscription == '-' && p_ptr->chp > p_ptr->mhp / 2) return FALSE;
2130 #endif
2131
2132 switch (o_ptr->tval) {
2133 /* non-directional ones */
2134 case TV_SCROLL:
2135 do_cmd_read_scroll(Ind, item);
2136 return TRUE;
2137 case TV_POTION:
2138 do_cmd_quaff_potion(Ind, item);
2139 return TRUE;
2140 case TV_STAFF:
2141 do_cmd_use_staff(Ind, item);
2142 return TRUE;
2143 case TV_ROD:
2144 do_cmd_zap_rod(Ind, item, 5);
2145 return TRUE;
2146 case TV_WAND:
2147 do_cmd_aim_wand(Ind, item, 5);
2148 return TRUE;
2149 }
2150 }
2151 #else
2152 switch (o_ptr->tval) {
2153 case TV_STAFF:
2154 if (((o_ptr->ident & ID_EMPTY) || ((o_ptr->ident & ID_KNOWN) && o_ptr->pval == 0))
2155 && fallback)
2156 return (p_ptr->fail_no_melee);
2157 do_cmd_use_staff(Ind, item);
2158 return TRUE;
2159 case TV_ROD:
2160 if (o_ptr->pval != 0 && fallback)
2161 return (p_ptr->fail_no_melee);
2162 do_cmd_zap_rod(Ind, item, 5);
2163 return TRUE;
2164 case TV_WAND:
2165 if (((o_ptr->ident & ID_EMPTY) || ((o_ptr->ident & ID_KNOWN) && o_ptr->pval == 0))
2166 && fallback)
2167 return (p_ptr->fail_no_melee);
2168 do_cmd_aim_wand(Ind, item, 5);
2169 return TRUE;
2170 }
2171 #endif
2172
2173 /* Accept reasonable targets:
2174 * This prevents a player from getting stuck when facing a
2175 * monster inside a wall.
2176 * NOTE: The above statement becomes obsolete nowadays if
2177 * PY_PROJ_ and similar are defined.
2178 */
2179 if (!target_able(Ind, p_ptr->target_who)) return FALSE;
2180
2181 /* Spell to cast */
2182 if (inscription != NULL) {
2183 choice = *inscription - 96 - 1;
2184 if (choice < 0 || choice > 9) choice = 0;
2185 }
2186
2187 switch (o_ptr->tval) {
2188 /* weapon -- attack normally! */
2189 case TV_MSTAFF:
2190 case TV_BLUNT:
2191 case TV_POLEARM:
2192 case TV_SWORD:
2193 case TV_AXE:
2194 //redundant?-> if (item == INVEN_WIELD) return FALSE;
2195 return FALSE;
2196 break;
2197
2198 /* directional ones */
2199 case TV_SHOT:
2200 case TV_ARROW:
2201 case TV_BOLT:
2202 case TV_BOW:
2203 // case TV_BOOMERANG:
2204 // case TV_INSTRUMENT:
2205 if (item == INVEN_BOW || item == INVEN_AMMO) {
2206 if (!p_ptr->inventory[INVEN_AMMO].k_idx ||
2207 !p_ptr->inventory[INVEN_AMMO].number)
2208 break;
2209
2210 retaliating_cmd = TRUE;
2211 do_cmd_fire(Ind, 5);
2212 if (p_ptr->ranged_double) do_cmd_fire(Ind, 5);
2213 return TRUE;
2214 }
2215 break;
2216
2217 case TV_BOOMERANG:
2218 if (item == INVEN_BOW)
2219 {
2220 retaliating_cmd = TRUE;
2221 do_cmd_fire(Ind, 5);
2222 return TRUE;
2223 }
2224 break;
2225
2226 /* spellbooks - mikaelh */
2227 case TV_BOOK:
2228 if (o_ptr->sval == SV_SPELLBOOK) {
2229 /* It's a spellbook */
2230
2231 /* There's only one spell in a spellbook */
2232 spell = o_ptr->pval;
2233 } else {
2234 /* It's a tome */
2235
2236 /* Get the spell */
2237 if (MY_VERSION < (4 << 12 | 4 << 8 | 1 << 4 | 8)) {
2238 /* no longer supported! to make s_aux.lua slimmer */
2239 spell = exec_lua(Ind, format("return spell_x(%d, %d, %d)", o_ptr->sval, o_ptr->pval, choice));
2240 } else {
2241 spell = exec_lua(Ind, format("return spell_x2(%d, %d, %d, %d)", item, o_ptr->sval, o_ptr->pval, choice));
2242 }
2243 }
2244
2245 cost = exec_lua(Ind, format("return get_mana(%d, %d)", Ind, spell));
2246 if (cost > p_ptr->csp && fallback) return (p_ptr->fail_no_melee);
2247
2248 /* Check that it's ok... more checks needed here? */
2249 /* Limit amount of mana used? */
2250 if (!p_ptr->blind && !no_lite(Ind) && !p_ptr->confused && cost <= p_ptr->csp &&
2251 exec_lua(Ind, format("return is_ok_spell(%d, %d)", Ind, spell)))
2252 {
2253 cast_school_spell(Ind, item, spell, 5, -1, 0);
2254 return TRUE;
2255 }
2256 break;
2257
2258
2259 case TV_RUNE: { //Format: @O<t?><imperative><form> {!R}
2260
2261 /* Validate Rune */
2262 if (o_ptr->sval < 0 || o_ptr->sval > RCRAFT_MAX_PROJECTIONS) break;
2263 u16b e_flags = r_projections[o_ptr->sval].flags, m_flags = 0;
2264 byte m_index = 0;
2265
2266 /* Validate Imperative */
2267 if (*inscription != '\0') {
2268 m_index = *inscription - 'a';
2269 if (m_index < 0 || m_index > RCRAFT_MAX_IMPERATIVES) m_flags |= I_MINI;
2270 else m_flags |= r_imperatives[m_index].flag;
2271 }
2272 else {
2273 if (cast_rune_spell(Ind, 5, e_flags, I_MINI | T_BOLT, 0, 1) == 2) return (p_ptr->fail_no_melee);
2274 return TRUE;
2275 }
2276
2277 /* Next Letter */
2278 inscription++;
2279
2280 /* Validate Form */
2281 if (*inscription != '\0') {
2282 m_index = *inscription - 'a';
2283 if (m_index < 0 || m_index > RCRAFT_MAX_TYPES || r_types[m_index].flag == T_SIGN || r_types[m_index].flag == T_RUNE || r_types[m_index].flag == T_ENCH) m_flags |= T_BOLT; //Hack -- Disallow 'self' types...
2284 else m_flags |= r_types[m_index].flag;
2285 }
2286 else {
2287 if (cast_rune_spell(Ind, 5, e_flags, I_MINI | T_BOLT, 0, 1) == 2) return (p_ptr->fail_no_melee);
2288 return TRUE;
2289 }
2290
2291 /* Retaliate or Melee */
2292 if (cast_rune_spell(Ind, 5, e_flags, m_flags, 0, 1) == 2) return (p_ptr->fail_no_melee);
2293 return TRUE;
2294
2295 break; }
2296 }
2297
2298 /* If all fails, then melee */
2299 return (p_ptr->fail_no_melee);
2300 }
2301
2302 #ifdef AUTO_RET_CMD
2303 /* Check auto-retaliation set via slash command /autoret or /ar.
2304 This was added for mimics to use their powers without having to inscribe
2305 a random item as a workaround. - C. Blue */
2306 static bool retaliate_cmd(int Ind, bool fallback) {
2307 player_type *p_ptr = Players[Ind];
2308 int ar = p_ptr->autoret;
2309
2310 /* Is it variant @Ot for town-only auto-retaliation? - C. Blue */
2311 if (ar >= 100) {
2312 if (!istownarea(&p_ptr->wpos, MAX_TOWNAREA)) return FALSE;
2313 ar -= 100;
2314 }
2315
2316 /* no autoret set? */
2317 if (!ar) return FALSE;
2318
2319 /* Hack -- use innate power via inscription on any item */
2320 if (get_skill(p_ptr, SKILL_MIMIC)) {
2321 /* Spell to cast */
2322 int choice = ar - 1;
2323
2324 if (choice < 4) /* 3 polymorph powers + immunity preference */
2325 return FALSE;
2326
2327 int power = retaliate_mimic_power(Ind, choice - 1);
2328 bool dir = FALSE;
2329 if (innate_powers[power].smana > p_ptr->csp && fallback) return (p_ptr->fail_no_melee);
2330 switch (power / 32) {
2331 case 0: dir = monster_spells4[power].uses_dir;
2332 break;
2333 case 1: dir = monster_spells5[power - 32].uses_dir;
2334 break;
2335 case 2: dir = monster_spells6[power - 64].uses_dir;
2336 break;
2337 }
2338
2339 /* Accept reasonable targets:
2340 * This prevents a player from getting stuck when facing a
2341 * monster inside a wall.
2342 * NOTE: The above statement becomes obsolete nowadays if
2343 * PY_PROJ_ and similar are defined.
2344 */
2345 if (!target_able(Ind, p_ptr->target_who)) return FALSE;
2346
2347 do_cmd_mimic(Ind, power + 3, dir ? 5 : 0);
2348 return TRUE;
2349 }
2350
2351 /* If all fails, then melee */
2352 return (p_ptr->fail_no_melee);
2353 }
2354 #endif
2355
2356 /*
2357 * Check for nearby players or monsters and attempt to do something useful.
2358 *
2359 * This function should only be called if the player is "lagging" and helpless
2360 * to do anything about the situation. This is not intended to be incredibly
2361 * useful, merely to prevent deaths due to extreme lag.
2362 */
2363 /* This function returns a 0 if no attack has been performed, a 1 if an attack
2364 * has been performed and there are still monsters around, and a 2 if an attack
2365 * has been performed and all of the surrounding monsters are dead.
2366 * (This difference between 1 and 2 isn't used anywhere... but I leave it for
2367 * future use. Jir)
2368 */
2369 /* We now intelligently try to decide which monster to autoattack. Our current
2370 * algorithm is to fight first Q's, then any monster that is 20 levels higher
2371 * than its peers, then the most proportionatly wounded monster, then the highest
2372 * level monster, then the monster with the least hit points.
2373 */
2374 /* Now a player can choose the way of auto-retaliating; - Jir -
2375 * Item marked with inscription {@O} will be used automatically.
2376 * For spellbooks this should be {@Oa} to specify which spell to use.
2377 * You can also choose to 'do nothing' by inscribing it on not-suitable item.
2378 *
2379 * Fighters are allowed to use {@O-}, which is only used if his HP is 1/2 or less.
2380 * ({@O-} feature is commented out)
2381 */
2382 /* handle RF7_NO_TARGET monsters so they won't block auto-retaliation?
2383 This involves checking for retal-item before checking for retal-target.
2384 That is probably much more expensive on CPU than the other way round.
2385 Also see CHEAP_NO_TARGET_TEST. - C. Blue
2386 NOTE: I added code that prevents auto-ret with physical attacks against a
2387 wraithed target, this code is in EXPENSIVE_NO_TARGET_TEST only, so it won't
2388 work if this isn't defined. This was already the case for melee, just not for @O ranged. */
2389 #define EXPENSIVE_NO_TARGET_TEST
2390 static int auto_retaliate(int Ind) {
2391 player_type *p_ptr = Players[Ind], *q_ptr, *p_target_ptr = NULL, *prev_p_target_ptr = NULL;
2392 int d, i, tx, ty, target, prev_target, item = -1;
2393 // char friends = 0;
2394 monster_type *m_ptr, *m_target_ptr = NULL, *prev_m_target_ptr = NULL;
2395 monster_race *r_ptr = NULL, *r_ptr2, *r_ptr0;
2396 object_type *o_ptr;
2397 cptr inscription = NULL, at_O_inscription = NULL;
2398 bool no_melee = FALSE, fallback = FALSE;
2399 bool skip_monsters = (p_ptr->cloaked || p_ptr->shadow_running) && !p_ptr->stormbringer;
2400 cave_type **zcave;
2401 /* are we dealing just physical damage? for wraithform checks (stormbringer ignores everything and just attacks anyway..): */
2402 bool physical = TRUE, wraith = (p_ptr->tim_wraith != 0) && !p_ptr->stormbringer;
2403
2404 if (!(zcave = getcave(&p_ptr->wpos))) return(FALSE);
2405
2406 if (p_ptr->new_level_flag) return 0;
2407
2408 /* disable auto-retaliation if we skip monsters/hostile players and blood-bonded players likewise */
2409 if (skip_monsters && !p_ptr->blood_bond) return 0;
2410
2411 /* Just to kill compiler warnings */
2412 target = prev_target = 0;
2413
2414 #ifdef EXPENSIVE_NO_TARGET_TEST
2415 /* Pick an item with {@O} inscription */
2416 for (i = 0; i < INVEN_TOTAL; i++) {
2417 o_ptr = &p_ptr->inventory[i];
2418 if (!o_ptr->tval) continue;
2419
2420 inscription = quark_str(o_ptr->note);
2421
2422 /* check for a valid inscription */
2423 if (inscription == NULL) continue;
2424
2425 /* scan the inscription for @O */
2426 while (*inscription != '\0') {
2427 if (*inscription == '@') {
2428 inscription++;
2429
2430 /* a valid @O has been located */
2431 /* @O shouldn't work on weapons or ammo in inventory - mikaelh */
2432 if ((*inscription == 'O' || *inscription == 'Q') && !(i < INVEN_WIELD &&
2433 (is_weapon(o_ptr->tval) || is_ammo(o_ptr->tval) ||
2434 is_armour(o_ptr->tval) || o_ptr->tval == TV_MSTAFF ||
2435 o_ptr->tval == TV_BOW || o_ptr->tval == TV_BOOMERANG))) {
2436 if (*inscription == 'Q') fallback = TRUE;
2437 inscription++;
2438
2439 /* Skip this item in case it has @Ox */
2440 if (*inscription == 'x') {
2441 p_ptr->warning_autoret = 99; /* seems he knows what he's doing! */
2442 break;
2443 }
2444
2445 /* Select the first usable item with @O */
2446 item = i;
2447 i = INVEN_TOTAL;
2448
2449 /* Remember the inscription */
2450 at_O_inscription = inscription;
2451
2452 p_ptr->warning_autoret = 99; /* seems he knows what he's doing! */
2453 break;
2454 }
2455 }
2456 inscription++;
2457 }
2458 }
2459
2460 /* check if we're using physical damage attacks */
2461 if (item != -1) physical = is_weapon(o_ptr->tval) || o_ptr->tval == TV_MSTAFF || is_ranged_weapon(o_ptr->tval) || is_ammo(o_ptr->tval);
2462
2463 /* Scan for @Ox to disable auto-retaliation only if no @O was found - mikaelh */
2464 for (i = INVEN_WIELD; i < INVEN_TOTAL; i++) {
2465 o_ptr = &p_ptr->inventory[i];
2466 if (!o_ptr->tval) continue;
2467
2468 inscription = quark_str(o_ptr->note);
2469
2470 /* check for a valid inscription */
2471 if (inscription == NULL) continue;
2472
2473 /* scan the inscription for @O */
2474 while (*inscription != '\0') {
2475 if (inscription[0] == '@' && (inscription[1] == 'O' || inscription[1] == 'Q') && inscription[2] == 'x') {
2476 p_ptr->warning_autoret = 99; /* seems he knows what he's doing! */
2477
2478 if (i == INVEN_WIELD || i == INVEN_ARM) {
2479 /* Prevent melee retaliation - mikaelh */
2480 no_melee = TRUE;
2481 }
2482
2483 if (item == -1) {
2484 /* Select the item with @Ox */
2485 item = i;
2486
2487 /* Make at_O_inscription point to the 'x' */
2488 at_O_inscription = inscription + 2;
2489
2490 i = INVEN_TOTAL; /* exit the outer loop too */
2491 break;
2492 }
2493 }
2494 inscription++;
2495 }
2496 }
2497
2498 /* no specific item inscribed -> use default melee attacks */
2499 if (item == -1) physical = TRUE;
2500 #endif
2501
2502 /* check for monster/player targets */
2503 for (d = 1; d <= 9; d++) {
2504 if (d == 5) continue;
2505
2506 tx = p_ptr->px + ddx[d];
2507 ty = p_ptr->py + ddy[d];
2508
2509 if (!in_bounds(ty, tx)) continue;
2510
2511 if (!(i = zcave[ty][tx].m_idx)) continue;
2512 if (i > 0) {
2513 m_ptr = &m_list[i];
2514 r_ptr0 = race_inf(m_ptr);
2515
2516 /* Paranoia -- Skip dead monsters */
2517 if (!m_ptr->r_idx) continue;
2518
2519 /* Make sure that the player can see this monster */
2520 if (!p_ptr->mon_vis[i]) continue;
2521
2522 /* Stop annoying auto-retaliation against certain 'monsters' */
2523 if (r_ptr0->flags8 & RF8_NO_AUTORET) continue;
2524
2525 #ifdef EXPENSIVE_NO_TARGET_TEST
2526 /* Skip monsters we cannot actually target! (Sparrows) */
2527 if ((r_ptr0->flags7 & RF7_NO_TARGET) &&
2528 is_ranged_item(Ind, &p_ptr->inventory[item]))
2529 continue;
2530
2531 /* New - wraithform checks: Don't attack monsters that we'd deal 0 damage against and just wake up */
2532 if (wraith && physical && !(r_ptr0->flags2 & RF2_PASS_WALL)) continue;
2533 #endif
2534
2535 /* Protect pets/golems */
2536 #if 0 /* Only vs our own pet/golem? */
2537 if (p_ptr->id == m_ptr->owner && !p_ptr->stormbringer) continue;
2538 #else /* vs own+other players' pets/golems? */
2539 if (m_ptr->owner && !p_ptr->stormbringer) continue;
2540 #endif
2541
2542 /* specialty: don't auto-retaliate charmed monsters.
2543 Maybe slightly inconsistent with the fact that we still auto-ret sleeping monsters ;). */
2544 if (m_ptr->charmedignore && !p_ptr->stormbringer) continue;
2545
2546 /* Figure out if this is the best target so far */
2547 if (!m_target_ptr) {
2548 prev_m_target_ptr = m_target_ptr;
2549 m_target_ptr = m_ptr;
2550 r_ptr = race_inf(m_ptr);
2551 prev_target = target;
2552 target = i;
2553 } else {
2554 /* Target dummy should always be the last one to get attacked - mikaelh */
2555 if (m_ptr->r_idx == RI_TARGET_DUMMY1 || m_ptr->r_idx == RI_TARGET_DUMMY2 ||
2556 m_ptr->r_idx == RI_TARGET_DUMMYA1 || m_ptr->r_idx == RI_TARGET_DUMMYA2)
2557 continue;
2558
2559 r_ptr2 = r_ptr;
2560 r_ptr = race_inf(m_ptr);
2561
2562 /* If it is a Q, then make it our new target. */
2563 /* We don't handle the case of choosing between two
2564 * Q's because if the player is standing next to two Q's
2565 * he deserves whatever punishment he gets.
2566 */
2567 if (r_ptr->d_char == 'Q') {
2568 prev_m_target_ptr = m_target_ptr;
2569 m_target_ptr = m_ptr;
2570 prev_target = target;
2571 target = i;
2572 }
2573 /* Otherwise if it is 20 levels higher than everything
2574 * else attack it.
2575 */
2576 else if ((r_ptr->level - 20) >= r_ptr2->level) {
2577 prev_m_target_ptr = m_target_ptr;
2578 m_target_ptr = m_ptr;
2579 prev_target = target;
2580 target = i;
2581 }
2582 /* Otherwise if it is the most proportionatly wounded monster
2583 * attack it.
2584 */
2585 else if (m_ptr->hp * m_target_ptr->maxhp < m_target_ptr->hp * m_ptr->maxhp) {
2586 prev_m_target_ptr = m_target_ptr;
2587 m_target_ptr = m_ptr;
2588 prev_target = target;
2589 target = i;
2590 }
2591 /* If it is a tie attack the higher level monster */
2592 else if (m_ptr->hp * m_target_ptr->maxhp == m_target_ptr->hp * m_ptr->maxhp) {
2593 if (r_ptr->level > r_ptr2->level) {
2594 prev_m_target_ptr = m_target_ptr;
2595 m_target_ptr = m_ptr;
2596 prev_target = target;
2597 target = i;
2598 }
2599 /* If it is a tie attack the monster with less hit points */
2600 else if (r_ptr->level == r_ptr2->level) {
2601 if (m_ptr->hp < m_target_ptr->hp) {
2602 prev_m_target_ptr = m_target_ptr;
2603 m_target_ptr = m_ptr;
2604 prev_target = target;
2605 target = i;
2606 }
2607 }
2608 }
2609 }
2610 } else if (cfg.use_pk_rules != PK_RULES_NEVER) {
2611 i = -i;
2612 if (!(q_ptr = Players[i])) continue;
2613
2614 /* Skip non-connected players */
2615 if (q_ptr->conn == NOT_CONNECTED) continue;
2616
2617 /* Skip players we aren't hostile to */
2618 if (!check_hostile(Ind, i) && !p_ptr->stormbringer) continue;
2619
2620 /* Skip players we cannot see */
2621 if (!p_ptr->play_vis[i]) continue;
2622
2623 /* Figure out if this is the best target so far */
2624 if (p_target_ptr) {
2625 /* If we are 15 levels over the old target, make this
2626 * player our new target.
2627 */
2628 if ((q_ptr->lev - 15) >= p_target_ptr->lev) {
2629 prev_p_target_ptr = p_target_ptr;
2630 p_target_ptr = q_ptr;
2631 prev_target = target;
2632 target = -i;
2633 }
2634 /* Otherwise attack this player if he is more proportionatly
2635 * wounded than our old target.
2636 */
2637 else if (q_ptr->chp * p_target_ptr->mhp < p_target_ptr->chp * q_ptr->mhp) {
2638 prev_p_target_ptr = p_target_ptr;
2639 p_target_ptr = q_ptr;
2640 prev_target = target;
2641 target = -i;
2642 }
2643 /* If it is a tie attack the higher level player */
2644 else if (q_ptr->chp * p_target_ptr->mhp == p_target_ptr->chp * q_ptr->mhp) {
2645 if (q_ptr->lev > p_target_ptr->lev) {
2646 prev_p_target_ptr = p_target_ptr;
2647 p_target_ptr = q_ptr;
2648 prev_target = target;
2649 target = -i;
2650 }
2651 /* If it is a tie attack the player with less hit points */
2652 else if (q_ptr->lev == p_target_ptr->lev) {
2653 if (q_ptr->chp < p_target_ptr->chp) {
2654 prev_p_target_ptr = p_target_ptr;
2655 p_target_ptr = q_ptr;
2656 prev_target = target;
2657 target = -i;
2658 }
2659 }
2660 }
2661 } else {
2662 prev_p_target_ptr = p_target_ptr;
2663 p_target_ptr = q_ptr;
2664 prev_target = target;
2665 target = -i;
2666 }
2667 }
2668 }
2669
2670 /* Nothing to attack */
2671 if (!p_target_ptr && !m_target_ptr) {
2672 /* Hack: If we don't have a 'continuous attack' ie are out of
2673 adjacent targets, which just happened here, stop 'piercing' attacks */
2674 if (p_ptr->piercing && !p_ptr->piercing_charged) p_ptr->piercing = 0;
2675
2676 return 0;
2677 }
2678
2679 #ifndef EXPENSIVE_NO_TARGET_TEST
2680 /* Pick an item with {@O} inscription */
2681 for (i = 0; i < INVEN_TOTAL; i++) {
2682 o_ptr = &p_ptr->inventory[i];
2683 if (!o_ptr->tval) continue;
2684
2685 inscription = quark_str(o_ptr->note);
2686
2687 /* check for a valid inscription */
2688 if (inscription == NULL) continue;
2689
2690 /* scan the inscription for @O */
2691 while (*inscription != '\0') {
2692 if (*inscription == '@') {
2693 inscription++;
2694
2695 /* a valid @O has been located */
2696 /* @O shouldn't work on weapons or ammo in inventory - mikaelh */
2697 if ((*inscription == 'O' || *inscription == 'Q') && !(i < INVEN_WIELD &&
2698 (is_weapon(o_ptr->tval) || is_ammo(o_ptr->tval) ||
2699 is_armour(o_ptr->tval) || o_ptr->tval == TV_MSTAFF ||
2700 o_ptr->tval == TV_BOW || o_ptr->tval == TV_BOOMERANG))) {
2701 if (*inscription == 'Q') fallback = TRUE;
2702 inscription++;
2703
2704 /* Skip this item in case it has @Ox */
2705 if (*inscription == 'x') {
2706 p_ptr->warning_autoret = 99; /* seems he knows what he's doing! */
2707 break;
2708 }
2709
2710 /* Select the first usable item with @O */
2711 item = i;
2712 i = INVEN_TOTAL;
2713
2714 /* Remember the inscription */
2715 at_O_inscription = inscription;
2716
2717 p_ptr->warning_autoret = 99; /* seems he knows what he's doing! */
2718 break;
2719 }
2720 }
2721 inscription++;
2722 }
2723 }
2724
2725 /* Scan for @Ox to disable auto-retaliation only if no @O was found - mikaelh */
2726 for (i = INVEN_WIELD; i < INVEN_TOTAL; i++) {
2727 o_ptr = &p_ptr->inventory[i];
2728 if (!o_ptr->tval) continue;
2729
2730 inscription = quark_str(o_ptr->note);
2731
2732 /* check for a valid inscription */
2733 if (inscription == NULL) continue;
2734
2735 /* scan the inscription for @O */
2736 while (*inscription != '\0') {
2737 if (inscription[0] == '@' && (inscription[1] == 'O' || inscription[1] == 'Q') && inscription[2] == 'x') {
2738 p_ptr->warning_autoret = 99; /* seems he knows what he's doing! */
2739
2740 if (i == INVEN_WIELD || i == INVEN_ARM) {
2741 /* Prevent melee retaliation - mikaelh */
2742 no_melee = TRUE;
2743 }
2744
2745 if (item == -1) {
2746 /* Select the item with @Ox */
2747 item = i;
2748
2749 /* Make at_O_inscription point to the 'x' */
2750 at_O_inscription = inscription + 2;
2751
2752 i = INVEN_TOTAL; /* exit the outer loop too */
2753 break;
2754 }
2755 }
2756 inscription++;
2757 }
2758 }
2759 #endif
2760
2761 /* If we have a player target, attack him. */
2762 if (p_target_ptr) {
2763 /* set the target */
2764 p_ptr->target_who = target;
2765
2766 /* Attack him */
2767 /* Stormbringer bypasses everything!! */
2768 // py_attack(Ind, p_target_ptr->py, p_target_ptr->px);
2769 if (p_ptr->stormbringer || (
2770 #ifdef AUTO_RET_CMD
2771 !retaliate_cmd(Ind, fallback) &&
2772 #endif
2773 !retaliate_item(Ind, item, at_O_inscription, fallback) &&
2774 !p_ptr->afraid && !no_melee)) {
2775 py_attack(Ind, p_target_ptr->py, p_target_ptr->px, FALSE);
2776 }
2777
2778 /* Check if he is still alive or another targets exists */
2779 if ((!p_target_ptr->death) || (prev_p_target_ptr) || (m_target_ptr)) {
2780 /* We attacked something */
2781 return 1;
2782 } else {
2783 /* Otherwise return 2 to indicate we are no longer
2784 * autoattacking anything.
2785 */
2786 return 2;
2787 }
2788 }
2789
2790 /* The dungeon master does not fight his or her offspring */
2791 if (p_ptr->admin_dm) return 0;
2792
2793 /* If we have a target to attack, attack it! */
2794 if (m_target_ptr) {
2795 /* set the target */
2796 p_ptr->target_who = target;
2797 if (m_target_ptr->pet) { //a pet?
2798 return 0;
2799 }
2800
2801 /* Attack it */
2802 // py_attack(Ind, m_target_ptr->fy, m_target_ptr->fx);
2803 if (p_ptr->stormbringer || (
2804 #ifdef AUTO_RET_CMD
2805 !retaliate_cmd(Ind, fallback) &&
2806 #endif
2807 !retaliate_item(Ind, item, at_O_inscription, fallback) &&
2808 !p_ptr->afraid && !no_melee)) {
2809 py_attack(Ind, m_target_ptr->fy, m_target_ptr->fx, FALSE);
2810
2811 /* manage autoretaliation warning for newbies (reset it) */
2812 if (p_ptr->warning_autoret != 99) p_ptr->warning_autoret = 0;
2813 }
2814
2815 /* Check if it is still alive or another targets exists */
2816 if ((m_target_ptr->r_idx) || (prev_m_target_ptr) || (p_target_ptr)) {
2817 /* We attacked something */
2818 return 1;
2819 } else {
2820 /* Otherwise return 2 to indicate we are no longer
2821 * autoattacking anything.
2822 */
2823 return 2;
2824 }
2825 }
2826
2827 /* Nothing was attacked. */
2828 return 0;
2829 }
2830
2831 /*
2832 * Player processing that occurs at the beginning of a new turn
2833 */
2834 static void process_player_begin(int Ind)
2835 {
2836 player_type *p_ptr = Players[Ind];
2837
2838 /* for AT_VALINOR: */
2839 int i, x, y, xstart = 0, ystart = 0, ox, oy;
2840 dungeon_type *d_ptr;
2841 cave_type **zcave;
2842 dun_level *l_ptr;
2843
2844 p_ptr->heal_turn_20 += p_ptr->heal_turn[0] - p_ptr->heal_turn[20];
2845 p_ptr->heal_turn_10 += p_ptr->heal_turn[0] - p_ptr->heal_turn[10];
2846 p_ptr->heal_turn_5 += p_ptr->heal_turn[0] - p_ptr->heal_turn[5];
2847 p_ptr->dam_turn_20 = p_ptr->dam_turn[0] - p_ptr->dam_turn[20];
2848 p_ptr->dam_turn_10 = p_ptr->dam_turn[0] - p_ptr->dam_turn[10];
2849 p_ptr->dam_turn_5 = p_ptr->dam_turn[0] - p_ptr->dam_turn[5];
2850 for (i = 20; i > 0; i--) {
2851 /* move internal heal/turn register for C_BLUE_AI */
2852 p_ptr->heal_turn[i] = p_ptr->heal_turn[i - 1];
2853 /* move internal dam/turn register for C_BLUE_AI */
2854 p_ptr->dam_turn[i] = p_ptr->dam_turn[i - 1];
2855 }
2856 p_ptr->heal_turn[0] = 0; /* prepared to store healing that might happen */
2857 p_ptr->dam_turn[0] = 0; /* prepared to store damage dealing that might happen */
2858
2859 /* Perform pending automatic transportation */
2860 switch (p_ptr->auto_transport) {
2861 case AT_BLINK: teleport_player_force(Ind, 10); p_ptr->auto_transport = 0; break;
2862 case AT_TPORT: teleport_player_force(Ind, 100); p_ptr->auto_transport = 0; break;
2863 case AT_VALINOR: /* allocate Valinor; recall player there */
2864 #if 0
2865 if (players_on_depth(wpos) && !getcave(wpos)) {
2866 /* Allocate space for it */
2867 alloc_dungeon_level(wpos);
2868 /* Generate a dungeon level there */
2869 generate_cave(wpos, p_ptr);
2870 }
2871 zcave = getcave(wpos);
2872 l_ptr = getfloor(wpos);
2873 #endif
2874 #if 1
2875 for (y = 0; y < MAX_WILD_Y; y++) {
2876 for (x = 0; x < MAX_WILD_X; x++) {
2877 if ((d_ptr = wild_info[y][x].tower) && (!strcmp(d_name + d_info[d_ptr->type].name, "The Shores of Valinor"))) {
2878 p_ptr->recall_pos.wx = x;
2879 p_ptr->recall_pos.wy = y;
2880 p_ptr->recall_pos.wz = 1;
2881 p_ptr->new_level_method = LEVEL_OUTSIDE_RAND;
2882 recall_player(Ind, "");
2883 break;
2884 }
2885 if ((d_ptr = wild_info[y][x].dungeon) && (!strcmp(d_name + d_info[d_ptr->type].name, "The Shores of Valinor"))) {
2886 p_ptr->recall_pos.wx = x;
2887 p_ptr->recall_pos.wy = y;
2888 p_ptr->recall_pos.wz = -1;
2889 // let's try LEVEL_OUTSIDE_RAND (5) instead of LEVEL_OUTSIDE (4) - C. Blue :)
2890 p_ptr->new_level_method = LEVEL_OUTSIDE_RAND;
2891 recall_player(Ind, "");
2892 break;
2893 }
2894 }
2895 }
2896 p_ptr->auto_transport = AT_VALINOR2;
2897 break;
2898 #endif
2899 case AT_VALINOR2: /* (re-)generate Valinor from scratch; move player into position; lite it up for the show; place 'monsters' */
2900 zcave = getcave(&p_ptr->wpos);
2901 l_ptr = getfloor(&p_ptr->wpos);
2902 /* Get rid of annoying level flags */
2903 l_ptr->flags1 &= ~(LF1_NO_MAP | LF1_NO_MAGIC_MAP);
2904 for (y = 0; y < MAX_HGT / 3; y++) {
2905 for (x = 0; x < MAX_WID; x++) {
2906 zcave[y][x].feat = FEAT_HIGH_MOUNT_SOLID;
2907 zcave[y + MAX_HGT / 3][x].feat = FEAT_GLIT_WATER;
2908 zcave[y + (MAX_HGT * 2) / 3][x].feat = FEAT_GLIT_WATER;
2909 }
2910 }
2911 /* Wipe any monsters/objects */
2912 wipe_o_list_safely(&p_ptr->wpos);
2913 wipe_m_list(&p_ptr->wpos);
2914 /* Regenerate the level from fixed layout */
2915 process_dungeon_file("t_valinor.txt", &p_ptr->wpos, &ystart, &xstart, 21, 66, TRUE);
2916 for (x = 0; x <= 65; x++) zcave[21][x].feat = FEAT_GLIT_WATER;
2917 zcave[20][0].feat = FEAT_GLIT_WATER;
2918 zcave[20][65].feat = FEAT_GLIT_WATER;
2919 /* Some lil hacks */
2920 msg_format(Ind, "\377%cYou enter the shores of Valinor..", COLOUR_DUNGEON);
2921 wiz_lite(Ind);
2922 /* Move @ to designated starting position (level_rand_x/y()) and redraw */
2923 oy = p_ptr->py;
2924 ox = p_ptr->px;
2925 p_ptr->py = 15;
2926 p_ptr->px = 16;
2927 zcave[oy][ox].m_idx = 0;
2928 zcave[p_ptr->py][p_ptr->px].m_idx = 0 - Ind;
2929 everyone_lite_spot(&p_ptr->wpos, oy, ox);
2930 everyone_lite_spot(&p_ptr->wpos, p_ptr->py, p_ptr->px);
2931 /* Summon 'monsters' */
2932 place_monster_one(&p_ptr->wpos, 7, 10, RI_BRIGHTLANCE, 0, 0, 0, 0, 0);
2933 everyone_lite_spot(&p_ptr->wpos, 7, 10);
2934 place_monster_one(&p_ptr->wpos, 7, 15, RI_BRIGHTLANCE, 0, 0, 0, 0, 0);
2935 everyone_lite_spot(&p_ptr->wpos, 7, 15);
2936 place_monster_one(&p_ptr->wpos, 10, 25, RI_OROME, 0, 0, 0, 0, 0);
2937 everyone_lite_spot(&p_ptr->wpos, 10, 25);
2938 p_ptr->update |= PU_LITE;
2939 p_ptr->update |= (PU_VIEW | PU_LITE | PU_FLOW);
2940 p_ptr->update |= (PU_DISTANCE);
2941 redraw_stuff(Ind);
2942 p_ptr->auto_transport = AT_VALINOR3;
2943 break;
2944 case AT_VALINOR3: /* Orome mumbles */
2945 if (turn % 300) break; /* cool down.. */
2946 msg_print(Ind, "\374 ");
2947 msg_print(Ind, "\374\377oOrome, The Hunter, mumbles something about a spear..");
2948 p_ptr->auto_transport = AT_VALINOR4;
2949 break;
2950 case AT_VALINOR4: /* Orome looks */
2951 if (turn % 500) break; /* cool down.. */
2952 msg_print(Ind, "\374 ");
2953 msg_print(Ind, "\374\377oOrome, The Hunter, notices you and surprise crosses his face!");
2954 p_ptr->auto_transport = AT_VALINOR5;
2955 break;
2956 case AT_VALINOR5: /* Orome laughs */
2957 if (turn % 500) break; /* cool down.. */
2958 msg_print(Ind, "\374 ");
2959 msg_print(Ind, "\374\377oOrome, The Hunter, laughs out loudly!");
2960 set_afraid(Ind, 8);
2961 p_ptr->auto_transport = AT_VALINOR6;
2962 break;
2963 case AT_VALINOR6: /* Orome offers */
2964 if (turn % 500) break; /* cool down.. */
2965 msg_print(Ind, "\374 ");
2966 msg_print(Ind, "\374\377oOrome, The Hunter, offers you to stay here!");
2967 msg_print(Ind, "\374\377y (You may hit the suicide keys in order to retire here,");
2968 msg_print(Ind, "\374\377y or take the staircase back to the mundane world.)");
2969 msg_print(Ind, "\374 ");
2970 p_ptr->auto_transport = 0;
2971 break;
2972 }
2973
2974
2975 /* Give the player some energy */
2976 p_ptr->energy += extract_energy[p_ptr->pspeed];
2977 limit_energy(p_ptr);
2978
2979 /* clear 'quaked' flag for p_ptr->impact limiting */
2980 p_ptr->quaked = FALSE;
2981
2982 /* Check "resting" status */
2983 if (p_ptr->resting) {
2984 /* No energy availiable while resting */
2985 // This prevents us from instantly waking up.
2986 p_ptr->energy = 0;
2987 }
2988
2989 /* Handle paralysis here */
2990 #ifndef ARCADE_SERVER
2991 if (p_ptr->paralyzed || p_ptr->stun > 100)
2992 p_ptr->energy = 0;
2993 #else
2994 if (p_ptr->paralyzed)
2995 p_ptr->energy = 0;
2996 #endif
2997
2998
2999 /* Hack -- semi-constant hallucination */
3000 if (p_ptr->image && (randint(10) < 1)) p_ptr->redraw |= (PR_MAP);
3001
3002 /* Mega-Hack -- Random teleportation XXX XXX XXX */
3003 if ((p_ptr->teleport) && (rand_int(100) < 1)
3004 /* not during highlander tournament */
3005 && (p_ptr->wpos.wx || p_ptr->wpos.wy || !sector00separation))
3006 {
3007 /* Teleport player */
3008 teleport_player(Ind, 40, FALSE);
3009 }
3010
3011 }
3012
3013
3014 /*
3015 * Generate the feature effect
3016 */
3017 static void apply_effect(int Ind)
3018 {
3019 player_type *p_ptr = Players[Ind];
3020 int y = p_ptr->py, x = p_ptr->px;
3021 cave_type *c_ptr;
3022 feature_type *f_ptr;
3023
3024 cave_type **zcave;
3025 if (!(zcave = getcave(&p_ptr->wpos))) return;
3026
3027 c_ptr = &zcave[y][x];
3028 f_ptr = &f_info[c_ptr->feat];
3029
3030 if (f_ptr->d_frequency[0] != 0) {
3031 int i;
3032
3033 for (i = 0; i < 4; i++) {
3034 /* Check the frequency */
3035 if (f_ptr->d_frequency[i] == 0) continue;
3036
3037 /* XXX it's no good to use 'turn' here */
3038 // if (((turn % f_ptr->d_frequency[i]) == 0) &&
3039
3040 if ((!rand_int(f_ptr->d_frequency[i])) &&
3041 ((f_ptr->d_side[i] != 0) || (f_ptr->d_dice[i] != 0)))
3042 {
3043 int l, dam = 0;
3044 int d = f_ptr->d_dice[i], s = f_ptr->d_side[i];
3045
3046 if (d == -1) d = p_ptr->lev;
3047 if (s == -1) s = p_ptr->lev;
3048
3049 /* Roll damage */
3050 for (l = 0; l < d; l++) {
3051 dam += randint(s);
3052 }
3053
3054 /* Apply damage */
3055 project(PROJECTOR_TERRAIN, 0, &p_ptr->wpos, y, x, dam, f_ptr->d_type[i],
3056 PROJECT_NORF | PROJECT_KILL | PROJECT_HIDE | PROJECT_JUMP, "");
3057
3058 /* Hack -- notice death */
3059 // if (!alive || death) return;
3060 if (p_ptr->death) return;
3061 }
3062 }
3063 }
3064 }
3065
3066 #if 0
3067 /* admin can summon a player anywhere he/she wants */
3068 void summon_player(int victim, struct worldpos *wpos, char *message){
3069 struct player_type *p_ptr;
3070 p_ptr = Players[victim];
3071 p_ptr->recall_pos.wx = wpos->wx;
3072 p_ptr->recall_pos.wy = wpos->wy;
3073 p_ptr->recall_pos.wz = wpos->wz;
3074 recall_player(victim, message);
3075 }
3076 #endif
3077
3078 /* actually recall a player with no questions asked */
3079 void recall_player(int Ind, char *message) {
3080 struct player_type *p_ptr;
3081 cave_type **zcave;
3082 struct worldpos old_wpos;
3083 char buf[MAX_CHARS_WIDE];
3084
3085 p_ptr = Players[Ind];
3086
3087 if(!p_ptr) return;
3088 if(!(zcave = getcave(&p_ptr->wpos))) return; // eww
3089
3090 break_cloaking(Ind, 0);
3091 break_shadow_running(Ind);
3092 stop_precision(Ind);
3093 stop_shooting_till_kill(Ind);
3094
3095 #ifdef USE_SOUND_2010
3096 sound(Ind, "teleport", NULL, SFX_TYPE_COMMAND, FALSE);
3097 #endif
3098
3099 /* Remove the player */
3100 zcave[p_ptr->py][p_ptr->px].m_idx = 0;
3101
3102 /* Show everyone that he's left */
3103 everyone_lite_spot(&p_ptr->wpos, p_ptr->py, p_ptr->px);
3104
3105 msg_print(Ind, message);
3106
3107 /* Forget his lite and view */
3108 forget_lite(Ind);
3109 forget_view(Ind);
3110
3111 #if 1 //todo: fix again after it broke: actually this code should instead have been done already in process_player_change_wpos() or related functions >.>
3112 /* sanity check on recall coordinates */
3113 p_ptr->recall_pos.wx %= MAX_WILD_X;
3114 p_ptr->recall_pos.wy %= MAX_WILD_Y;
3115 if (p_ptr->recall_pos.wz < 0) {
3116 if (wild_info[p_ptr->recall_pos.wy][p_ptr->recall_pos.wx].dungeon) {
3117 if (-p_ptr->recall_pos.wz > wild_info[p_ptr->recall_pos.wy][p_ptr->recall_pos.wx].dungeon->maxdepth)
3118 p_ptr->recall_pos.wz = -wild_info[p_ptr->recall_pos.wy][p_ptr->recall_pos.wx].dungeon->maxdepth;
3119 } else p_ptr->recall_pos.wz = 0;
3120 } else if (p_ptr->recall_pos.wz > 0) {
3121 if (wild_info[p_ptr->recall_pos.wy][p_ptr->recall_pos.wx].tower) {
3122 if (p_ptr->recall_pos.wz > wild_info[p_ptr->recall_pos.wy][p_ptr->recall_pos.wx].tower->maxdepth)
3123 p_ptr->recall_pos.wz = wild_info[p_ptr->recall_pos.wy][p_ptr->recall_pos.wx].tower->maxdepth;
3124 } else p_ptr->recall_pos.wz = 0;
3125 }
3126 #endif
3127
3128 /* Change the wpos */
3129 wpcopy(&old_wpos, &p_ptr->wpos);
3130 wpcopy(&p_ptr->wpos, &p_ptr->recall_pos);
3131
3132 /* One less person here */
3133 new_players_on_depth(&old_wpos, -1, TRUE);
3134
3135 /* Log it */
3136 s_printf("Recalled: %s from %d,%d,%d to %d,%d,%d.\n", p_ptr->name,
3137 old_wpos.wx, old_wpos.wy, old_wpos.wz,
3138 p_ptr->recall_pos.wx, p_ptr->recall_pos.wy, p_ptr->recall_pos.wz);
3139
3140 /* One more person here */
3141 new_players_on_depth(&p_ptr->wpos, 1, TRUE);
3142
3143 p_ptr->new_level_flag = TRUE;
3144
3145 /* He'll be safe for some turns */
3146 set_invuln_short(Ind, RECALL_GOI_LENGTH); // It runs out if attacking anyway
3147
3148 /* cancel any user recalls */
3149 p_ptr->word_recall = 0;
3150
3151
3152 /* check for /tpto admin command that allows changing between 2 wz positions that are both != 0: */
3153 if (p_ptr->wpos.wz) return;
3154
3155
3156 /* Update wilderness map! This is for RECALL_MAX_RANGE:
3157 We learn about the intermediate world map sectors we land on. */
3158 if (!p_ptr->ghost)
3159 p_ptr->wild_map[(p_ptr->wpos.wx + p_ptr->wpos.wy * MAX_WILD_X) / 8] |=
3160 (1 << ((p_ptr->wpos.wx + p_ptr->wpos.wy * MAX_WILD_X) % 8));
3161
3162 /* Did we really make it through all floors of the ironman challenge dungeon? */
3163 if (in_irondeepdive(&old_wpos)
3164 && !is_admin(p_ptr)) {
3165 int i, j;
3166 #ifdef IRONDEEPDIVE_FIXED_TOWN_WITHDRAWAL
3167 bool success = TRUE;
3168 if (getlevel(&old_wpos) == 40 || getlevel(&old_wpos) == 80) success = FALSE;
3169 if (success)
3170 #endif
3171 for (i = 0; i < IDDC_HIGHSCORE_SIZE; i++) {
3172 #ifdef IDDC_THROUGH_IS_FIRST /* 0->always replace first entry! */
3173 if (deep_dive_level[i] == -1) {
3174 #ifdef IDDC_RESTRICT_ACC_CLASS /* only allow one entry of same account+class? : discard new entry */
3175 if (!strcmp(deep_dive_account[i], p_ptr->accountname) &&
3176 deep_dive_class[i] == p_ptr->pclass) {
3177 i = IDDC_HIGHSCORE_DISPLAYED;
3178 break;
3179 }
3180 #endif
3181 continue;
3182 }
3183 #endif
3184 #ifdef IDDC_RESTRICT_ACC_CLASS /* only allow one entry of same account+class? : discard previous entry */
3185 for (j = i; j < IDDC_HIGHSCORE_SIZE - 1; j++) {
3186 if (!strcmp(deep_dive_account[j], p_ptr->accountname) &&
3187 deep_dive_class[j] == p_ptr->pclass) {
3188 int k;
3189
3190 /* pull up all succeeding entries by 1 */
3191 for (k = j; k < IDDC_HIGHSCORE_SIZE - 1; k++) {
3192 deep_dive_level[k] = deep_dive_level[k + 1];
3193 strcpy(deep_dive_name[k], deep_dive_name[k + 1]);
3194 strcpy(deep_dive_char[k], deep_dive_char[k + 1]);
3195 strcpy(deep_dive_account[k], deep_dive_account[k + 1]);
3196 deep_dive_class[k] = deep_dive_class[k + 1];
3197 }
3198 break;
3199 }
3200 }
3201 #endif
3202 /* push down all entries by 1, to make room for inserting new entry */
3203 for (j = IDDC_HIGHSCORE_SIZE - 1; j > i; j--) {
3204 deep_dive_level[j] = deep_dive_level[j - 1];
3205 strcpy(deep_dive_name[j], deep_dive_name[j - 1]);
3206 strcpy(deep_dive_char[j], deep_dive_char[j - 1]);
3207 strcpy(deep_dive_account[j], deep_dive_account[j - 1]);
3208 deep_dive_class[j] = deep_dive_class[j - 1];
3209 }
3210 deep_dive_level[i] = -1;
3211 //strcpy(deep_dive_name[i], p_ptr->name);
3212 #ifdef IDDC_HISCORE_SHOWS_ICON
3213 sprintf(deep_dive_name[i], "%s, %s %s (\\{%c%c\\{s/\\{%c%d\\{s),",
3214 p_ptr->name, get_prace(p_ptr), class_info[p_ptr->pclass].title, color_attr_to_char(p_ptr->cp_ptr->color), p_ptr->fruit_bat ? 'b' : '@',
3215 p_ptr->ghost ? 'r' : 's', p_ptr->max_plv);
3216 #else
3217 sprintf(deep_dive_name[i], "%s, %s %s (\\{%c%d\\{s),",
3218 p_ptr->name, get_prace(p_ptr), class_info[p_ptr->pclass].title,
3219 p_ptr->ghost ? 'r' : 's', p_ptr->max_plv);
3220 #endif
3221 strcpy(deep_dive_char[i], p_ptr->name);
3222 strcpy(deep_dive_account[i], p_ptr->accountname);
3223 deep_dive_class[i] = p_ptr->pclass;
3224 break;
3225 }
3226
3227 #ifdef IRONDEEPDIVE_ALLOW_INCOMPAT
3228 /* need to leave party, since we might be teamed up with incompatible char mode players! */
3229 if (p_ptr->party && !p_ptr->admin_dm &&
3230 compat_mode(p_ptr->mode, parties[p_ptr->party].cmode))
3231 party_leave(Ind, FALSE);
3232 #endif
3233
3234 #ifdef IRONDEEPDIVE_FIXED_TOWN_WITHDRAWAL
3235 if (success) {
3236 #endif
3237 p_ptr->iron_winner = TRUE;
3238 msg_print(Ind, "\374\377L***\377aYou made it through the Ironman Deep Dive challenge!\377L***");
3239 sprintf(buf, "\374\377L***\377a%s made it through the Ironman Deep Dive challenge!\377L***", p_ptr->name);
3240 msg_broadcast(Ind, buf);
3241 l_printf("%s \\{U%s (%d) made it through the Ironman Deep Dive challenge\n", showdate(), p_ptr->name, p_ptr->lev);
3242 #ifdef TOMENET_WORLDS
3243 if (cfg.worldd_events) world_msg(buf);
3244 #endif
3245 /* enforce dedicated Ironman Deep Dive Challenge character slot usage */
3246 if (p_ptr->mode & MODE_DED_IDDC) {
3247 msg_print(Ind, "\377aYou return to town and may retire ('Q') when ready.");
3248 msg_print(Ind, "\377aIf you enter a dungeon or tower, \377Rretirement\377a is assumed \377Rautomatically\377a.");
3249
3250 process_player_change_wpos(Ind);
3251 p_ptr->recall_pos.wx = cfg.town_x;
3252 p_ptr->recall_pos.wy = cfg.town_y;
3253
3254 wpcopy(&old_wpos, &p_ptr->wpos);
3255 wpcopy(&p_ptr->wpos, &p_ptr->recall_pos);
3256 new_players_on_depth(&old_wpos, -1, TRUE);
3257 s_printf("Recalled: %s from %d,%d,%d to %d,%d,%d.\n", p_ptr->name,
3258 old_wpos.wx, old_wpos.wy, old_wpos.wz,
3259 p_ptr->recall_pos.wx, p_ptr->recall_pos.wy, p_ptr->recall_pos.wz);
3260 new_players_on_depth(&p_ptr->wpos, 1, TRUE);
3261 p_ptr->new_level_flag = TRUE;
3262 set_invuln_short(Ind, RECALL_GOI_LENGTH); // It runs out if attacking anyway
3263 p_ptr->word_recall = 0;
3264 process_player_change_wpos(Ind);
3265
3266 /* Restrict character to world surface */
3267 p_ptr->iron_winner_ded = TRUE;
3268 }
3269
3270 p_ptr->IDDC_flags = 0x0; //clear IDDC specialties
3271 #ifdef IRONDEEPDIVE_FIXED_TOWN_WITHDRAWAL
3272 } else {
3273 /* enforce dedicated Ironman Deep Dive Challenge character slot usage */
3274 if (p_ptr->mode & MODE_DED_IDDC) {
3275 msg_print(Ind, "\377RYou failed to complete the Ironman Deep Dive Challenge!");
3276 strcpy(p_ptr->died_from, "indetermination");
3277 p_ptr->deathblow = 0;
3278 p_ptr->death = TRUE;
3279 return;
3280 }
3281
3282 sprintf(buf, "\374\377s%s withdrew from the Ironman Deep Dive challenge.", p_ptr->name);
3283 msg_broadcast(0, buf);
3284 #ifdef TOMENET_WORLDS
3285 if (cfg.worldd_events) world_msg(buf);
3286 #endif
3287
3288 /* reduce his accumulated mimicry form knowledge somewhat
3289 (keep some of the benefits of IDDC hunting) */
3290 #ifdef IDDC_MIMICRY_BOOST
3291 if (IDDC_MIMICRY_BOOST <= 2) j = 5;
3292 else if (IDDC_MIMICRY_BOOST == 3) j = 6;
3293 else if (IDDC_MIMICRY_BOOST == 4) j = 7;
3294 else if (IDDC_MIMICRY_BOOST <= 6) j = 10;
3295 else j = 13;
3296 for (i = 1; i < max_r_idx; i++) {
3297 if ((r_info[i].flags1 & RF1_UNIQUE)) continue;
3298 p_ptr->r_killed[i] = (p_ptr->r_killed[i] * 5) / j;
3299 }
3300 /* In case he can no longer use his current form */
3301 do_mimic_change(Ind, 0, TRUE);
3302 #endif
3303
3304 p_ptr->IDDC_flags = 0x0; //clear IDDC specialties
3305
3306 /* Be nice: Actually set all his true artifacts to non-iddc timeouting
3307 (for IDDC_ARTIFACT_FAST_TIMEOUT) */
3308 for (i = 0; i < INVEN_TOTAL; i++) {
3309 if (!p_ptr->inventory[i].k_idx) continue;
3310 if (!p_ptr->inventory[i].name1 || p_ptr->inventory[i].name1 == ART_RANDART) continue;
3311 a_info[p_ptr->inventory[i].name1].iddc = FALSE;
3312 }
3313 }
3314 #endif
3315 }
3316
3317 /* Specialty: Did we make it through the Halls of Mandos?
3318 Those are now ironman, so they're a 'pure', traditional ironman challenge.
3319 However, this dungeon can be entered at any level, so it might be less of a challenge. */
3320 if (in_hallsofmandos(&old_wpos)) {
3321 msg_print(Ind, "\374\377a***\377sYou made it through the Halls of Mandos!\377a***");
3322 sprintf(buf, "\374\377a***\377s%s made it through the Halls of Mandos!\377a***", p_ptr->name);
3323 msg_broadcast(Ind, buf);
3324 l_printf("%s \\{U%s (%d) made it through the Halls of Mandos\n", showdate(), p_ptr->name, p_ptr->lev);
3325 }
3326 }
3327
3328
3329 /* Handles WoR
3330 * XXX dirty -- REWRITEME
3331 */
3332 static void do_recall(int Ind, bool bypass)
3333 {
3334 player_type *p_ptr = Players[Ind];
3335 char *message = NULL;
3336
3337 /* sorta circumlocution? */
3338 worldpos new_pos;
3339 bool recall_ok = TRUE;
3340
3341 /* Disturbing! */
3342 disturb(Ind, 0, 0);
3343
3344 /* special restriction for global events (Highlander Tournament) */
3345 if (sector00separation && !is_admin(p_ptr) && (
3346 (!p_ptr->recall_pos.wx && !p_ptr->recall_pos.wy) ||
3347 (!p_ptr->wpos.wx && !p_ptr->wpos.wy))) {
3348 if (p_ptr->global_event_temp & PEVF_PASS_00) {
3349 p_ptr->global_event_temp &= ~PEVF_PASS_00;
3350 } else {
3351 msg_print(Ind, "A tension leaves the air around you...");
3352 p_ptr->redraw |= (PR_DEPTH);
3353 return;
3354 }
3355 }
3356
3357 if (!p_ptr->wpos.wz && !bypass) {
3358 wilderness_type *w_ptr = &wild_info[p_ptr->recall_pos.wy][p_ptr->recall_pos.wx];
3359 dungeon_type *d_ptr = NULL;
3360 if (p_ptr->recall_pos.wz < 0 && (w_ptr->flags & WILD_F_DOWN))
3361 d_ptr = w_ptr->dungeon;
3362 else if (p_ptr->recall_pos.wz > 0 && (w_ptr->flags & WILD_F_UP))
3363 d_ptr = w_ptr->tower;
3364
3365 #ifdef OBEY_DUNGEON_LEVEL_REQUIREMENTS
3366 if (d_ptr){
3367 if ((d_ptr->type && d_info[d_ptr->type].min_plev > p_ptr->lev) ||
3368 (!d_ptr->type && d_ptr->baselevel <= (p_ptr->lev * 3) / 2 + 7)) {
3369 msg_print(Ind,"\377rAs you attempt to recall, you are gripped by an uncontrollable fear.");
3370 msg_print(Ind, "A tension leaves the air around you...");
3371 p_ptr->redraw |= (PR_DEPTH);
3372 if (!is_admin(p_ptr)) {
3373 set_afraid(Ind, 10);// + (d_ptr->baselevel - p_ptr->max_dlv));
3374 return;
3375 }
3376 }
3377 }
3378 #endif
3379 /* Nether Realm only for Kings/Queens (currently paranoia, since NR is NO_RECALL_INTO) */
3380 if (d_ptr && (d_ptr->type == DI_NETHER_REALM) && !p_ptr->total_winner) {
3381 msg_print(Ind,"\377rAs you attempt to recall, you are gripped by an uncontrollable fear.");
3382 if (!is_admin(p_ptr)) {
3383 set_afraid(Ind, 10);//+(d_ptr->baselevel-p_ptr->max_dlv));
3384 return;
3385 }
3386 }
3387 }
3388
3389 /* Determine the level */
3390 /* recalling to surface */
3391 if (p_ptr->wpos.wz && !bypass) {
3392 struct dungeon_type *d_ptr;
3393 d_ptr = getdungeon(&p_ptr->wpos);
3394
3395 /* Messages */
3396 if (((d_ptr->flags2 & DF2_IRON || d_ptr->flags1 & DF1_FORCE_DOWN) && d_ptr->maxdepth > ABS(p_ptr->wpos.wz)) ||
3397 (d_ptr->flags1 & DF1_NO_RECALL)) {
3398 if (!(getfloor(&p_ptr->wpos)->flags1 & LF1_IRON_RECALL)) {
3399 msg_print(Ind, "You feel yourself being pulled toward the surface!");
3400 if (!is_admin(p_ptr)) {
3401 recall_ok = FALSE;
3402 /* Redraw the depth(colour) */
3403 p_ptr->redraw |= (PR_DEPTH);
3404 }
3405 } else if ((p_ptr->mode & MODE_DED_IDDC) && in_irondeepdive(&p_ptr->wpos)) {
3406 msg_print(Ind, "You have dedicated yourself to the Ironman Deep Dive Challenge!");
3407 if (!is_admin(p_ptr)) {
3408 recall_ok = FALSE;
3409 /* Redraw the depth(colour) */
3410 p_ptr->redraw |= (PR_DEPTH);
3411 }
3412 }
3413 }
3414 if (recall_ok) {
3415 msg_format(Ind, "\377%cYou are transported out of %s..", COLOUR_DUNGEON, get_dun_name(p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz > 0, d_ptr, 0, FALSE));
3416 if (p_ptr->wpos.wz > 0) {
3417 message = "You feel yourself yanked downwards!";
3418 msg_format_near(Ind, "%s is yanked downwards!", p_ptr->name);
3419 } else {
3420 message = "You feel yourself yanked upwards!";
3421 msg_format_near(Ind, "%s is yanked upwards!", p_ptr->name);
3422 }
3423
3424 /* New location */
3425 new_pos.wx = p_ptr->wpos.wx;
3426 new_pos.wy = p_ptr->wpos.wy;
3427 new_pos.wz = 0;
3428 #if 0
3429 p_ptr->new_level_method = ( istown(&new_pos) ? LEVEL_RAND : LEVEL_OUTSIDE_RAND );
3430 #endif
3431 p_ptr->new_level_method = (p_ptr->wpos.wz>0 ? LEVEL_RECALL_DOWN : LEVEL_RECALL_UP);
3432 }
3433 }
3434 /* beware! bugs inside! (jir) (no longer I hope) */
3435 /* world travel */
3436 /* why wz again? (jir) */
3437 else if ((!(p_ptr->recall_pos.wz) || !(wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].flags & (WILD_F_UP|WILD_F_DOWN))) && !bypass) {
3438 int dis;
3439
3440 if (((!(p_ptr->wild_map[(wild_idx(&p_ptr->recall_pos))/8] &
3441 (1 << (wild_idx(&p_ptr->recall_pos))%8))) &&
3442 !is_admin(p_ptr) ) ||
3443 inarea(&p_ptr->wpos, &p_ptr->recall_pos))
3444 {
3445 /* back to the last town (s)he visited.
3446 * (This can fail if gone too far) */
3447 p_ptr->recall_pos.wx = p_ptr->town_x;
3448 p_ptr->recall_pos.wy = p_ptr->town_y;
3449 }
3450
3451 #ifdef RECALL_MAX_RANGE
3452 dis = distance(p_ptr->recall_pos.wy, p_ptr->recall_pos.wx,
3453 p_ptr->wpos.wy, p_ptr->wpos.wx);
3454 if (dis > RECALL_MAX_RANGE && !is_admin(p_ptr)) {
3455 new_pos.wx = p_ptr->wpos.wx + (p_ptr->recall_pos.wx - p_ptr->wpos.wx) * RECALL_MAX_RANGE / dis;
3456 new_pos.wy = p_ptr->wpos.wy + (p_ptr->recall_pos.wy - p_ptr->wpos.wy) * RECALL_MAX_RANGE / dis;
3457 }
3458 else
3459 #endif // RECALL_MAX_RANGE
3460 {
3461 new_pos.wx = p_ptr->recall_pos.wx;
3462 new_pos.wy = p_ptr->recall_pos.wy;
3463 }
3464
3465 new_pos.wz = 0;
3466
3467 /* Messages */
3468 message = "You feel yourself yanked sideways!";
3469 msg_format_near(Ind, "%s is yanked sideways!", p_ptr->name);
3470
3471 /* New location */
3472 p_ptr->new_level_method = LEVEL_OUTSIDE_RAND;
3473 }
3474
3475 /* into dungeon/tower */
3476 /* even at runlevel 2048 players may still recall..for now */
3477 else if (cfg.runlevel > 4 && cfg.runlevel != 2049) {
3478 wilderness_type *w_ptr = &wild_info[p_ptr->recall_pos.wy][p_ptr->recall_pos.wx];
3479 // wilderness_type *w_ptr = &wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx];
3480 /* Messages */
3481 if (p_ptr->recall_pos.wz < 0 && w_ptr->flags & WILD_F_DOWN) {
3482 dungeon_type *d_ptr = wild_info[p_ptr->recall_pos.wy][p_ptr->recall_pos.wx].dungeon;
3483 #ifdef SEPARATE_RECALL_DEPTHS
3484 int d = -get_recall_depth(&p_ptr->recall_pos, p_ptr);
3485 #endif
3486
3487 /* check character/dungeon limits */
3488 if (-p_ptr->recall_pos.wz > w_ptr->dungeon->maxdepth)
3489 p_ptr->recall_pos.wz = 0 - w_ptr->dungeon->maxdepth;
3490 if (p_ptr->inval && -p_ptr->recall_pos.wz > 10)
3491 p_ptr->recall_pos.wz = -10;
3492 #ifdef SEPARATE_RECALL_DEPTHS
3493 if (d > p_ptr->recall_pos.wz) p_ptr->recall_pos.wz = d;
3494 if ( /* ??? */
3495 #else
3496 if (p_ptr->max_dlv < w_ptr->dungeon->baselevel - p_ptr->recall_pos.wz)
3497 p_ptr->recall_pos.wz = w_ptr->dungeon->baselevel - p_ptr->max_dlv - 1;
3498 //if(d_ptr->baselevel-p_ptr->max_dlv>2){
3499 if ((!d_ptr->type && d_ptr->baselevel - p_ptr->max_dlv > 2) || /* ??? */
3500 #endif
3501 #ifdef OBEY_DUNGEON_LEVEL_REQUIREMENTS
3502 (d_ptr->type && d_info[d_ptr->type].min_plev > p_ptr->lev) ||
3503 #endif
3504 (d_ptr->flags1 & (DF1_NO_RECALL | DF1_NO_UP | DF1_FORCE_DOWN)) ||
3505 #ifdef RPG_SERVER /* Prevent recalling into NO_DEATH dungeons */
3506 (d_ptr->flags2 & (DF2_NO_DEATH)) ||
3507 #endif
3508 #if 0
3509 (d_ptr->flags2 & (DF2_IRON | DF2_NO_RECALL_INTO)) ||
3510 #else /* allow recalling into town dungeons every 1000 ft now? Adjusted Moltor's suggestion */
3511 (d_ptr->flags2 & (DF2_NO_RECALL_INTO)) ||
3512 ((d_ptr->flags2 & DF2_IRON) && wild_info[p_ptr->recall_pos.wy][p_ptr->recall_pos.wx].type != WILD_TOWN) ||
3513 ((d_ptr->flags2 & DF2_IRON) && ((p_ptr->recall_pos.wz + 1) % 20)) ||
3514 #endif
3515 (d_ptr->flags2 & DF2_NO_ENTRY_WOR))
3516 {
3517 if (!is_admin(p_ptr))
3518 p_ptr->recall_pos.wz = 0;
3519 else if (p_ptr->recall_pos.wz != 0) /* got zero already from get_max_depth()? then don't give 'nowhere' msg twice */
3520 msg_print(Ind, "You feel yourself yanked toward nowhere...");
3521 }
3522
3523 if (p_ptr->recall_pos.wz >= 0) {
3524 p_ptr->recall_pos.wz = 0;
3525 } else {
3526 message = "You feel yourself yanked downwards!";
3527 msg_format(Ind, "\377%cYou are transported into %s..", COLOUR_DUNGEON, get_dun_name(p_ptr->recall_pos.wx, p_ptr->recall_pos.wy, FALSE, d_ptr, 0, FALSE));
3528 msg_format_near(Ind, "%s is yanked downwards!", p_ptr->name);
3529 }
3530 }
3531 else if (p_ptr->recall_pos.wz > 0 && w_ptr->flags & WILD_F_UP) {
3532 dungeon_type *d_ptr = wild_info[p_ptr->recall_pos.wy][p_ptr->recall_pos.wx].tower;
3533 #ifdef SEPARATE_RECALL_DEPTHS
3534 int d = get_recall_depth(&p_ptr->recall_pos, p_ptr);
3535 #endif
3536
3537 /* check character/tower limits */
3538 if (p_ptr->recall_pos.wz > w_ptr->tower->maxdepth)
3539 p_ptr->recall_pos.wz = w_ptr->tower->maxdepth;
3540 if (p_ptr->inval && p_ptr->recall_pos.wz > 10)
3541 p_ptr->recall_pos.wz = 10;
3542 #ifdef SEPARATE_RECALL_DEPTHS
3543 if (d < p_ptr->recall_pos.wz) p_ptr->recall_pos.wz = d;
3544 if ( /* ??? */
3545 #else
3546 if (p_ptr->max_dlv < w_ptr->tower->baselevel + p_ptr->recall_pos.wz + 1)
3547 p_ptr->recall_pos.wz = 0 - w_ptr->tower->baselevel + p_ptr->max_dlv + 1;
3548 //if(d_ptr->baselevel-p_ptr->max_dlv>2){
3549 if ((!d_ptr->type && d_ptr->baselevel-p_ptr->max_dlv > 2) || /* ??? */
3550 #endif
3551 #ifdef OBEY_DUNGEON_LEVEL_REQUIREMENTS
3552 (d_ptr->type && d_info[d_ptr->type].min_plev > p_ptr->lev) ||
3553 #endif
3554 (d_ptr->flags1 & (DF1_NO_RECALL | DF1_NO_UP | DF1_FORCE_DOWN)) ||
3555 #ifdef RPG_SERVER /* Prevent recalling into NO_DEATH towers */
3556 (d_ptr->flags2 & (DF2_NO_DEATH)) ||
3557 #endif
3558 #if 0
3559 (d_ptr->flags2 & (DF2_IRON | DF2_NO_RECALL_INTO)) ||
3560 #else /* allow recalling into town dungeons every 1000 ft now? Adjusted Moltor's suggestion */
3561 (d_ptr->flags2 & (DF2_NO_RECALL_INTO)) ||
3562 ((d_ptr->flags2 & DF2_IRON) && wild_info[p_ptr->recall_pos.wy][p_ptr->recall_pos.wx].type != WILD_TOWN) ||
3563 ((d_ptr->flags2 & DF2_IRON) && ((p_ptr->recall_pos.wz - 1) % 20)) ||
3564 #endif
3565 (d_ptr->flags2 & DF2_NO_ENTRY_WOR))
3566 {
3567 if (!is_admin(p_ptr))
3568 p_ptr->recall_pos.wz = 0;
3569 else if (p_ptr->recall_pos.wz != 0) /* got zero already from get_max_depth()? then don't give 'nowhere' msg twice */
3570 msg_print(Ind, "You feel yourself yanked toward nowhere...");
3571 }
3572
3573 if (p_ptr->recall_pos.wz <= 0) {
3574 p_ptr->recall_pos.wz = 0;
3575 } else {
3576 message = "You feel yourself yanked upwards!";
3577 msg_format(Ind, "\377%cYou are transported into %s..", COLOUR_DUNGEON, get_dun_name(p_ptr->recall_pos.wx, p_ptr->recall_pos.wy, TRUE, d_ptr, 0, FALSE));
3578 msg_format_near(Ind, "%s is yanked upwards!", p_ptr->name);
3579 }
3580 } else {
3581 p_ptr->recall_pos.wz = 0;
3582 }
3583
3584 /* prevent 'cross-recalling' except for admins (ie change of x,y and z at once) */
3585 if (p_ptr->recall_pos.wz && !is_admin(p_ptr) &&
3586 (p_ptr->wpos.wx != p_ptr->recall_pos.wx || p_ptr->wpos.wy != p_ptr->recall_pos.wy)) {
3587 p_ptr->recall_pos.wx = p_ptr->wpos.wx;
3588 p_ptr->recall_pos.wy = p_ptr->wpos.wy;
3589 p_ptr->recall_pos.wz = 0;
3590 }
3591
3592 new_pos.wx = p_ptr->recall_pos.wx;
3593 new_pos.wy = p_ptr->recall_pos.wy;
3594 new_pos.wz = p_ptr->recall_pos.wz;
3595 if (p_ptr->recall_pos.wz == 0) {
3596 message = "You feel yourself yanked toward nowhere...";
3597 p_ptr->new_level_method = LEVEL_OUTSIDE_RAND;
3598 }
3599 else p_ptr->new_level_method = LEVEL_RAND;
3600 } else {
3601 /* new_pos isn't set so recalling shouldn't be allowed - mikaelh */
3602 recall_ok = FALSE;
3603 p_ptr->redraw |= (PR_DEPTH);
3604 }
3605
3606 if (recall_ok) {
3607 /* back into here */
3608 wpcopy(&p_ptr->recall_pos, &new_pos);
3609 recall_player(Ind, message);
3610 }
3611 }
3612
3613 /* Does player have ball? */
3614 int has_ball (player_type *p_ptr) {
3615 int i;
3616 for (i = 0; i < INVEN_WIELD; i++) {
3617 if (p_ptr->inventory[i].tval == TV_GAME && p_ptr->inventory[i].sval == SV_GAME_BALL)
3618 break;
3619 }
3620 if (i == INVEN_WIELD) i = -1;
3621 return(i);
3622 }
3623
3624 /*
3625 * Handle misc. 'timed' things on the player.
3626 * returns FALSE if player no longer exists.
3627 *
3628 * TODO: find a better way for timed spells(set_*).
3629 */
3630 static bool process_player_end_aux(int Ind) {
3631 player_type *p_ptr = Players[Ind];
3632 cave_type *c_ptr;
3633 object_type *o_ptr;
3634 int i, j;
3635 int regen_amount; //, NumPlayers_old = NumPlayers;
3636 dun_level *l_ptr = getfloor(&p_ptr->wpos);
3637 dungeon_type *d_ptr = getdungeon(&p_ptr->wpos);
3638
3639 /* Unbelievers "resist" magic */
3640 // int minus = (p_ptr->anti_magic)?3:1;
3641 int minus = 1;
3642 int minus_magic = 1 + get_skill_scale_fine(p_ptr, SKILL_ANTIMAGIC, 2); /* was 3 before, trying slightly less harsh 2 now */
3643 int minus_health = get_skill_scale_fine(p_ptr, SKILL_HEALTH, 2); /* was 3, but then HEALTH didn't give HP.. */
3644 int minus_combat = get_skill_scale_fine(p_ptr, SKILL_COMBAT, 3);
3645
3646 cave_type **zcave;
3647 if (!(zcave = getcave(&p_ptr->wpos))) return(FALSE);
3648
3649 c_ptr = &zcave[p_ptr->py][p_ptr->px];
3650
3651 /* Anything done here cannot be reduced by GoI/Manashield etc */
3652 bypass_invuln = TRUE;
3653
3654 /*** Damage over Time ***/
3655
3656 /* Take damage from poison */
3657 if (p_ptr->poisoned) {
3658 if (p_ptr->slow_poison == 1) {
3659 p_ptr->slow_poison = 2;
3660 /* Take damage */
3661 take_hit(Ind, 1, "poison", p_ptr->poisoned_attacker);
3662 } else if (p_ptr->slow_poison == 2) {
3663 p_ptr->slow_poison = 1;
3664 } else {
3665 /* Take damage */
3666 take_hit(Ind, 1, "poison", p_ptr->poisoned_attacker);
3667 }
3668 }
3669
3670 /* Misc. terrain effects */
3671 if (!p_ptr->ghost) {
3672 /* Generic terrain effects */
3673 apply_effect(Ind);
3674
3675 /* Drowning, but not ghosts */
3676 if (c_ptr->feat == FEAT_DEEP_WATER) {
3677 bool carry_wood = FALSE;
3678
3679 for (i = 0; i < INVEN_PACK; i++) {
3680 o_ptr = &p_ptr->inventory[i];
3681 if (!o_ptr->k_idx) break;
3682 if (o_ptr->tval == TV_GOLEM && o_ptr->sval == SV_GOLEM_WOOD) {
3683 carry_wood = TRUE;
3684 break;
3685 }
3686 }
3687
3688 /* note: TODO (bug): items should get damaged even if player can_swim,
3689 but this might devalue swimming too much compared to levitation. Dunno. */
3690 if ((!p_ptr->tim_wraith) && (!p_ptr->levitate) && (!p_ptr->can_swim)
3691 && !carry_wood
3692 ) {
3693 /* Take damage */
3694 if (!(p_ptr->body_monster) || (
3695 !(r_info[p_ptr->body_monster].flags7 &
3696 (RF7_AQUATIC | RF7_CAN_SWIM)) ))
3697 {
3698 int hit = p_ptr->mhp >> 6;
3699 int swim = get_skill_scale(p_ptr, SKILL_SWIM, 4500);
3700 hit += randint(p_ptr->mhp >> 5);
3701 if (!hit) hit = 1;
3702
3703 /* Take CON into consideration(max 30%) */
3704 //note: if hit was 1, this can each result in 0 aka no hit!
3705 hit = (hit * (80 - adj_str_wgt[p_ptr->stat_ind[A_CON]])) / 75;
3706 if (p_ptr->suscep_life) hit >>= 1;
3707
3708 /* temporary abs weight calc */
3709 if (p_ptr->wt + p_ptr->total_weight/10 > 170 + swim * 2) { // 190
3710 long factor = (p_ptr->wt + p_ptr->total_weight / 10) - 150 - swim * 2; // 170
3711 /* too heavy, always drown? */
3712 if (factor < 300 && randint(factor) < 20) hit = 0;
3713
3714 /* Hack: Take STR and DEX into consideration (max 28%) */
3715 if (magik(adj_str_wgt[p_ptr->stat_ind[A_STR]] / 2) ||
3716 magik(adj_str_wgt[p_ptr->stat_ind[A_DEX]]) / 2)
3717 hit = 0;
3718
3719 if (magik(swim)) hit = 0;
3720
3721 if (hit) msg_print(Ind,"\377rYou're drowning!");
3722
3723 /* harm equipments (even hit == 0) */
3724 if (TOOL_EQUIPPED(p_ptr) != SV_TOOL_TARPAULIN &&
3725 magik(WATER_ITEM_DAMAGE_CHANCE) && !p_ptr->levitate &&
3726 !p_ptr->immune_water) {
3727 if (!p_ptr->resist_water || magik(50)) {
3728 if (!magik(get_skill_scale(p_ptr, SKILL_SWIM, 4900)))
3729 inven_damage(Ind, set_water_destroy, 1);
3730 equip_damage(Ind, GF_WATER);
3731 }
3732 }
3733
3734 if (randint(1000 - factor) < 10) {
3735 //if (p_ptr->prace != RACE_HALF_TROLL) {
3736 if (!p_ptr->sustain_str) {
3737 msg_print(Ind,"\377oYou are weakened by the exertion of swimming!");
3738 //do_dec_stat(Ind, A_STR, STAT_DEC_TEMPORARY);
3739 dec_stat(Ind, A_STR, 10, STAT_DEC_TEMPORARY);
3740 }
3741 }
3742 take_hit(Ind, hit, "drowning", 0);
3743 }
3744 }
3745 }
3746 }
3747 /* Aquatic anoxia */
3748 else if ((p_ptr->body_monster) &&
3749 ((r_info[p_ptr->body_monster].flags7 & RF7_AQUATIC) &&
3750 !(r_info[p_ptr->body_monster].flags3 & RF3_UNDEAD))
3751 && ((c_ptr->feat != FEAT_SHAL_WATER) ||
3752 r_info[p_ptr->body_monster].weight > 700)
3753 /* new: don't get stunned from crossing door/stair grids every time - C. Blue */
3754 && !is_always_passable(c_ptr->feat)
3755 && !p_ptr->tim_wraith)
3756 {
3757 long hit = p_ptr->mhp>>6; /* Take damage */
3758 hit += randint(p_ptr->chp>>5);
3759 /* Take CON into consideration(max 30%) */
3760 hit = (hit * (80 - adj_str_wgt[p_ptr->stat_ind[A_CON]])) / 75;
3761 if (!hit) hit = 1;
3762
3763 if (hit) {
3764 if (c_ptr->feat != FEAT_SHAL_WATER)
3765 msg_print(Ind,"\377rYou cannot breathe air!");
3766 else
3767 msg_print(Ind,"\377rThere's not enough water to breathe!");
3768 }
3769
3770 if (randint(1000) < 10) {
3771 msg_print(Ind,"\377rYou find it hard to stir!");
3772 // do_dec_stat(Ind, A_DEX, STAT_DEC_TEMPORARY);
3773 dec_stat(Ind, A_DEX, 10, STAT_DEC_TEMPORARY);
3774 }
3775
3776 /* very important to actually enforce it, otherwise
3777 it won't matter at all, because during a fight
3778 you quaff healing potions anyway.
3779 if you change the amount, compare it with continuous
3780 stun reduction so it won't get neutralized by high combat skill. */
3781 if (p_ptr->stun < 20) set_stun(Ind, p_ptr->stun + 5);
3782
3783 take_hit(Ind, hit, "anoxia", 0);
3784 }
3785
3786 /* Spectres -- take damage when moving through walls */
3787
3788 /*
3789 * Added: ANYBODY takes damage if inside through walls
3790 * without wraith form -- NOTE: Spectres will never be
3791 * reduced below 0 hp by being inside a stone wall; others
3792 * WILL BE!
3793 */
3794 /* Seemingly the comment above is wrong, dunno */
3795 if (!cave_floor_bold(zcave, p_ptr->py, p_ptr->px)
3796 && !cave_passable(zcave, p_ptr->py, p_ptr->px)) {
3797 /* Player can walk through trees */
3798 //if ((PRACE_FLAG(PR1_PASS_TREE) || (get_skill(SKILL_DRUID) > 15)) && (cave[py][px].feat == FEAT_TREE))
3799 #if 0
3800 if ((p_ptr->pass_trees || p_ptr->levitate) &&
3801 (c_ptr->feat == FEAT_TREE))
3802 #endif
3803 if (player_can_enter(Ind, c_ptr->feat, FALSE)) {
3804 /* Do nothing */
3805 }
3806 else if (c_ptr->feat == FEAT_HOME){/* rien */}
3807 //else if (PRACE_FLAG(PR1_SEMI_WRAITH) && (!p_ptr->wraith_form) && (f_info[cave[py][px].feat].flags1 & FF1_CAN_PASS))
3808 else if (!p_ptr->tim_wraith &&
3809 !p_ptr->master_move_hook) /* Hack -- builder is safe */
3810 {
3811 // int amt = 1 + ((p_ptr->lev)/5) + p_ptr->mhp / 100;
3812 /* Currently it only serves to reduce 'stuck' players' HP,
3813 so we might lower it a bit - C. Blue */
3814 int amt = 1 + ((p_ptr->lev)/10) + p_ptr->mhp / 100;
3815 int amt2 = p_ptr->msp / 35;
3816
3817 /* hack: disruption shield suffers a lot if it's got to withstand the walls oO */
3818 if (p_ptr->tim_manashield) {
3819 amt += amt2;
3820
3821 /* Be nice and don't let the disruption shield dissipate */
3822 if (p_ptr->pclass == CLASS_MAGE) {
3823 if (amt > p_ptr->csp - 1) amt = p_ptr->csp - 1;
3824 } else {
3825 /* Other classes take double damage */
3826 if (2 * amt > p_ptr->csp - 1) amt = (p_ptr->csp - 1) / 2;
3827 }
3828
3829 /* Disruption shield protects from this type of damage */
3830 bypass_invuln = FALSE;
3831 take_hit(Ind, amt, " walls ...", 0);
3832 bypass_invuln = TRUE;
3833 } else {
3834 if (amt > p_ptr->chp - 1) amt = p_ptr->chp - 1;
3835 take_hit(Ind, amt, " walls ...", 0);
3836 }
3837 }
3838 }
3839
3840 /* specialty for Cloud Planes: continuous icy winds */
3841 if (d_ptr && d_ptr->type == DI_CLOUD_PLANES) {
3842 #if 0 /* questionable - same as floor terrain effects? (kills potions) */
3843 project(PROJECTOR_TERRAIN, 0, &p_ptr->wpos, p_ptr->py, p_ptr->px, randint(20), GF_COLD,
3844 PROJECT_NORF | PROJECT_KILL | PROJECT_HIDE | PROJECT_JUMP, "freezing winds");
3845 #else /* seems better/cleaner */
3846 if (!p_ptr->immune_cold) {
3847 int dam;
3848 bool destroy = FALSE; /* note: inven damage should be same probability/extent, with or without <res xor opp>! */
3849
3850 if (p_ptr->resist_cold && p_ptr->oppose_cold) dam = randint(10);
3851 else if (p_ptr->resist_cold || p_ptr->oppose_cold) {
3852 dam = randint(20);
3853 if (!rand_int(3)) destroy = TRUE;
3854 } else {
3855 dam = randint(40);
3856 if (!rand_int(3)) destroy = TRUE;
3857 }
3858 msg_format(Ind, "You are hit by freezing winds for \377o%d\377w damage.", dam);
3859 bypass_invuln = FALSE; /* Disruption shield protects from this type of damage */
3860 take_hit(Ind, dam, "freezing winds", 0);
3861 bypass_invuln = TRUE;
3862 if (destroy) inven_damage(Ind, set_cold_destroy, 1);
3863 }
3864 #endif
3865 }
3866 }
3867
3868
3869 /* Take damage from cuts */
3870 if (p_ptr->cut) {
3871 /* Mortal wound or Deep Gash */
3872 if (p_ptr->cut > 200) i = 3;
3873 /* Severe cut */
3874 else if (p_ptr->cut > 100) i = 2;
3875 /* Other cuts */
3876 else i = 1;
3877
3878 /* Take damage */
3879 take_hit(Ind, i, "a fatal wound", p_ptr->cut_attacker);
3880 }
3881
3882 /*** Check the Food, and Regenerate ***/
3883 /* Ent's natural food while in 'Resting Mode' - C. Blue
3884 Water helps much, natural floor helps some. */
3885 if (!p_ptr->ghost && p_ptr->prace == RACE_ENT && p_ptr->resting) {
3886 if (c_ptr->feat == FEAT_SHAL_WATER || c_ptr->feat == FEAT_DEEP_WATER || c_ptr->feat == FEAT_MUD) {
3887 i = 500; //Delicious!
3888 } else if (c_ptr->feat == FEAT_GRASS || c_ptr->feat == FEAT_DIRT) {
3889 i = 100;
3890 } else if (c_ptr->feat == FEAT_BUSH || c_ptr->feat == FEAT_TREE) {
3891 i = 70;
3892 } else {
3893 i = 0;
3894 }
3895 if (i > 0 && set_food(Ind, p_ptr->food + i)) {
3896 msg_print(Ind, "You gain some nourishment from around you.");
3897 switch(i) {
3898 case 70:
3899 msg_format_near(Ind, "\374\377wYou hear strange sounds coming from the direction of %s.", p_ptr->name);
3900 break;
3901 case 100:
3902 msg_format_near(Ind, "\374\377w%s digs %s roots deep into the ground.", p_ptr->name, (p_ptr->male?"his":"her"));
3903 break;
3904 case 500:
3905 msg_format_near(Ind, "\374\377w%s absorbs all the water around %s.", p_ptr->name, (p_ptr->male?"him":"her"));
3906 }
3907 }
3908 }
3909 /* Ghosts don't need food */
3910 /* Allow AFK-hivernation if not hungry */
3911 else if (!p_ptr->ghost && !(p_ptr->afk && p_ptr->food >= PY_FOOD_ALERT) && !p_ptr->admin_dm &&
3912 /* Don't starve in town (but recover from being gorged) - C. Blue */
3913 // (!istown(&p_ptr->wpos) || p_ptr->food >= PY_FOOD_MAX))
3914 (!(istownarea(&p_ptr->wpos, MAX_TOWNAREA) || isdungeontown(&p_ptr->wpos))
3915 || p_ptr->food >= PY_FOOD_FULL)) /* allow to digest some to not get gorged in upcoming fights quickly - C. Blue */
3916 {
3917 /* Digest normally */
3918 if (p_ptr->food < PY_FOOD_MAX) {
3919 /* Every 50/6 level turns */
3920 // if (!(turn % ((level_speed((&p_ptr->wpos)) * 10) / 12)))
3921 if (!(turn % ((level_speed((&p_ptr->wpos)) / 120) * 10))) {
3922 /* Basic digestion rate based on speed */
3923 // i = (extract_energy[p_ptr->pspeed] / 10) * 2; // 1.3 (let them starve)
3924 i = (10 + (extract_energy[p_ptr->pspeed] / 10) * 3) / 2;
3925
3926 /* Adrenaline takes more food */
3927 if (p_ptr->adrenaline) i *= 5;
3928
3929 /* Biofeedback takes more food */
3930 if (p_ptr->biofeedback) i *= 2;
3931
3932 /* Regeneration takes more food */
3933 if (p_ptr->regenerate) i += 30;
3934
3935 /* Regeneration takes more food */
3936 if (p_ptr->tim_regen) i += p_ptr->tim_regen_pow / 10;
3937
3938 j = 0;
3939
3940 /* Mimics need more food if sustaining heavy forms */
3941 if (p_ptr->body_monster && r_info[p_ptr->body_monster].weight > 180)
3942 j = 15 - 7500 / (r_info[p_ptr->body_monster].weight + 320);//180:0, 260:2, 500:~5, 1000:~9, 5000:14, 7270:15
3943
3944 /* Draconian and Half-Troll take more food */
3945 if (p_ptr->prace == RACE_DRACONIAN
3946 || p_ptr->prace == RACE_HALF_TROLL) j = 15;
3947
3948 /* Use either mimic form induced food consumption increase,
3949 or intrinsic one, depending on which is higher. */
3950 i += j;
3951
3952 /* Vampires consume food very quickly,
3953 but old vampires don't need food frequently */
3954 if (p_ptr->prace == RACE_VAMPIRE) {
3955 if (p_ptr->lev >= 40) i += 60 / (p_ptr->lev - 37);
3956 else i += 20;
3957 }
3958
3959 /* Invisibility consume a lot of food */
3960 i += p_ptr->invis / 2;
3961
3962 /* Invulnerability consume a lot of food */
3963 if (p_ptr->invuln) i += 40;
3964
3965 /* Wraith Form consume a lot of food */
3966 if (p_ptr->tim_wraith) i += 30;
3967
3968 /* Hitpoints multiplier consume a lot of food */
3969 if (p_ptr->to_l) i += p_ptr->to_l * 5;
3970
3971 /* Slow digestion takes less food */
3972 // if (p_ptr->slow_digest) i -= 10;
3973 if (p_ptr->slow_digest) i -= (i > 40) ? i / 4 : 10;
3974
3975 /* Never negative */
3976 if (i < 1) i = 1;
3977
3978 /* Cut vampires some slack for Nether Realm:
3979 Ancient vampire lords almost don't need any food at all */
3980 if (p_ptr->prace == RACE_VAMPIRE && p_ptr->total_winner) i = 1;
3981
3982 /* Digest some food */
3983 (void)set_food(Ind, p_ptr->food - i);
3984 }
3985 }
3986
3987 /* Digest quickly when gorged */
3988 else {
3989 /* Digest a lot of food */
3990 (void)set_food(Ind, p_ptr->food - 100);
3991 }
3992
3993 /* Starve to death (slowly) */
3994 if (p_ptr->food < PY_FOOD_STARVE) {
3995 /* Calculate damage */
3996 i = (PY_FOOD_STARVE - p_ptr->food) / 10;
3997
3998 /* Take damage */
3999 take_hit(Ind, i, "starvation", 0);
4000 }
4001 }
4002
4003 /* Default regeneration */
4004 regen_amount = PY_REGEN_NORMAL;
4005
4006 /* Amulet of immortality relieves from eating */
4007 if (p_ptr->admin_invuln) p_ptr->food = PY_FOOD_MAX - 1;
4008
4009 /* Getting Weak */
4010 if (p_ptr->food < PY_FOOD_WEAK) {
4011 /* Lower regeneration */
4012 if (p_ptr->food < PY_FOOD_STARVE)
4013 regen_amount = 0;
4014 else if (p_ptr->food < PY_FOOD_FAINT)
4015 regen_amount = PY_REGEN_FAINT;
4016 else
4017 regen_amount = PY_REGEN_WEAK;
4018
4019 /* Getting Faint */
4020 if (!p_ptr->ghost && p_ptr->food < PY_FOOD_FAINT) {
4021 /* Faint occasionally */
4022 if (!p_ptr->paralyzed && (rand_int(100) < 10)) {
4023 /* Message */
4024 msg_print(Ind, "You faint from the lack of food.");
4025 disturb(Ind, 1, 0);
4026
4027 /* Hack -- faint (bypass free action) */
4028 (void)set_paralyzed(Ind, p_ptr->paralyzed + 1 + rand_int(5));
4029 }
4030 }
4031 }
4032
4033 /* Resting */
4034 if (p_ptr->resting && !p_ptr->searching)
4035 regen_amount = regen_amount * RESTING_RATE;
4036
4037 /* Regenerate the mana */
4038 /* Hack -- regenerate mana 5/3 times faster */
4039 #ifdef ARCADE_SERVER
4040 p_ptr->regen_mana = TRUE;
4041 #endif
4042 if (p_ptr->csp < p_ptr->msp) {
4043 if (p_ptr->wpos.wx == WPOS_PVPARENA_X &&
4044 p_ptr->wpos.wy == WPOS_PVPARENA_Y &&
4045 p_ptr->wpos.wz == WPOS_PVPARENA_Z)
4046 regenmana(Ind, ((regen_amount * 5 * PVP_MANA_REGEN_BOOST) * (p_ptr->regen_mana ? 2 : 1)) / 3);
4047 else
4048 regenmana(Ind, ((regen_amount * 5) * (p_ptr->regen_mana ? 2 : 1)) / 3);
4049 }
4050
4051 /* Regeneration ability */
4052 if (p_ptr->regenerate)
4053 regen_amount = regen_amount * 2;
4054
4055 /* Health skill improves regen_amount */
4056 if (minus_health)
4057 regen_amount = regen_amount * 3 / 2;
4058
4059 /* Holy curing gives improved regeneration ability */
4060 if (get_skill(p_ptr, SKILL_HCURING) >= 30) regen_amount = (regen_amount * (get_skill(p_ptr, SKILL_HCURING) - 10)) / 20;
4061
4062 /* Increase regen by tim regen */
4063 if (p_ptr->tim_regen) regen_amount += p_ptr->tim_regen_pow;
4064
4065 /* Poisoned or cut yields no healing */
4066 if (p_ptr->poisoned || p_ptr->cut || p_ptr->sun_burn)
4067 regen_amount = 0;
4068
4069 /* But Biofeedback always helps */
4070 if (p_ptr->biofeedback) regen_amount += randint(0x400) + regen_amount;
4071
4072 /* Regenerate Hit Points if needed */
4073 if (p_ptr->chp < p_ptr->mhp && regen_amount)
4074 regenhp(Ind, regen_amount);
4075
4076 /* Undiminish healing penalty in PVP mode */
4077 if (p_ptr->heal_effect) {
4078 // p_ptr->heal_effect -= (p_ptr->mhp + p_ptr->lev * 6) / 30;
4079 p_ptr->heal_effect -= p_ptr->lev / 10;
4080 if (p_ptr->heal_effect < 0) p_ptr->heal_effect = 0;
4081 }
4082
4083 /* Countdown no-teleport rule in PVP mode */
4084 if (p_ptr->pvp_prevent_tele) {
4085 p_ptr->pvp_prevent_tele--;
4086 if (!p_ptr->pvp_prevent_tele) p_ptr->redraw |= PR_DEPTH;
4087 }
4088
4089 /* Regenerate depleted Stamina */
4090 if ((p_ptr->cst < p_ptr->mst) && !p_ptr->shadow_running) {
4091 // int s = 2 * (76 + (adj_con_fix[p_ptr->stat_ind[A_CON]] + minus_health) * 3);
4092 int s = regen_boost_stamina * (54 + (adj_con_fix[p_ptr->stat_ind[A_CON]] + minus_health) * 3);
4093 if (p_ptr->resting && !p_ptr->searching) s *= 2;
4094 p_ptr->cst_frac += s;
4095 if (p_ptr->cst_frac >= 10000) {
4096 p_ptr->cst_frac -= 10000;
4097 p_ptr->cst++;
4098 if (p_ptr->cst == p_ptr->mst) p_ptr->cst_frac = 0;
4099 p_ptr->redraw |= (PR_STAMINA);
4100 }
4101 }
4102
4103 /* Disturb if we are done resting */
4104 if ((p_ptr->resting) && (p_ptr->chp == p_ptr->mhp) && (p_ptr->csp == p_ptr->msp) && (p_ptr->cst == p_ptr->mst)
4105 && !(p_ptr->prace == RACE_ENT && p_ptr->food < PY_FOOD_FULL))
4106 disturb(Ind, 0, 0);
4107
4108 /* Finally, at the end of our turn, update certain counters. */
4109 /*** Timeout Various Things ***/
4110
4111 /* Handle temporary stat drains */
4112 for (i = 0; i < 6; i++) {
4113 if (p_ptr->stat_cnt[i] > 0) {
4114 p_ptr->stat_cnt[i] -= (1 + minus_health);
4115 if (p_ptr->stat_cnt[i] <= 0) {
4116 do_res_stat_temp(Ind, i);
4117 }
4118 }
4119 }
4120
4121 /* Adrenaline */
4122 if (p_ptr->adrenaline)
4123 (void)set_adrenaline(Ind, p_ptr->adrenaline - 1);
4124
4125 /* Biofeedback */
4126 if (p_ptr->biofeedback)
4127 (void)set_biofeedback(Ind, p_ptr->biofeedback - 1);
4128
4129 /* Hack -- Bow Branding */
4130 if (p_ptr->bow_brand)
4131 (void)set_bow_brand(Ind, p_ptr->bow_brand - minus_magic, p_ptr->bow_brand_t, p_ptr->bow_brand_d);
4132
4133 /* weapon brand time */
4134 if (p_ptr->brand) {
4135 (void)set_brand(Ind, p_ptr->brand - minus_magic, p_ptr->brand_t, p_ptr->brand_d);
4136 }
4137
4138 /* Hack -- Timed ESP */
4139 if (p_ptr->tim_esp)
4140 (void)set_tim_esp(Ind, p_ptr->tim_esp - minus_magic);
4141
4142 /* Hack -- Space/Time Anchor */
4143 if (p_ptr->st_anchor)
4144 (void)set_st_anchor(Ind, p_ptr->st_anchor - minus_magic);
4145
4146 /* Hack -- Prob travel */
4147 if (p_ptr->prob_travel)
4148 (void)set_prob_travel(Ind, p_ptr->prob_travel - minus_magic);
4149
4150 /* Hack -- Avoid traps */
4151 if (p_ptr->tim_traps)
4152 (void)set_tim_traps(Ind, p_ptr->tim_traps - minus_magic);
4153
4154 /* Temporary Mimicry from a Ring of Polymorphing */
4155 if (p_ptr->tim_mimic && p_ptr->body_monster == p_ptr->tim_mimic_what) {
4156 /* hack - on hold while in town */
4157 if (!istownarea(&p_ptr->wpos, MAX_TOWNAREA) && !isdungeontown(&p_ptr->wpos)) {
4158 /* decrease time left of being polymorphed */
4159 (void)set_mimic(Ind, p_ptr->tim_mimic - 1, p_ptr->tim_mimic_what);
4160 }
4161 }
4162
4163 /* Hack -- Timed manashield */
4164 if (p_ptr->tim_manashield)
4165 set_tim_manashield(Ind, p_ptr->tim_manashield - minus_magic);
4166 #ifndef KURZEL_PK
4167 if (cfg.use_pk_rules == PK_RULES_DECLARE) {
4168 if (p_ptr->tim_pkill) {
4169 p_ptr->tim_pkill--;
4170 if (!p_ptr->tim_pkill) {
4171 if (p_ptr->pkill & PKILL_SET) {
4172 msg_print(Ind, "You may now kill other players");
4173 p_ptr->pkill |= PKILL_KILLER;
4174 } else {
4175 msg_print(Ind, "You are now protected from other players");
4176 p_ptr->pkill &= ~PKILL_KILLABLE;
4177 }
4178 }
4179 }
4180 }
4181 #endif
4182 if (p_ptr->tim_jail && !p_ptr->wpos.wz) {
4183 p_ptr->tim_jail--;
4184 if (!p_ptr->tim_jail) {
4185 #ifdef JAILER_KILLS_WOR
4186 /* eat his WoR scrolls as suggested? */
4187 bool found = FALSE, one = TRUE;
4188 for (j = 0; j < INVEN_WIELD; j++) {
4189 if (!p_ptr->inventory[j].k_idx) continue;
4190 o_ptr = &p_ptr->inventory[j];
4191 if ((o_ptr->tval == TV_ROD) && (o_ptr->sval == SV_ROD_RECALL)) {
4192 if (found) one = FALSE;
4193 if (o_ptr->number > 1) one = FALSE;
4194 o_ptr->pval = 300;
4195 found = TRUE;
4196 }
4197 }
4198 if (found) {
4199 msg_format(Ind, "The jailer discharges your rod%s of recall.", one ? "" : "s");
4200 p_ptr->window |= PW_INVEN;
4201 }
4202 #endif
4203
4204 /* only teleport him if he didn't take the ironman exit.
4205 (could add p_ptr->in_jail to handle it 100% safely
4206 or just set p_ptr->tim_jail to 0 on wpos change) */
4207 if (p_ptr->wpos.wz == 0 &&
4208 (zcave[p_ptr->py][p_ptr->px].info & CAVE_STCK)) {
4209 msg_print(Ind, "\377GYou are free to go!");
4210 teleport_player_force(Ind, 1);
4211 }
4212 }
4213 }
4214
4215 /* Hack -- Tunnel */
4216 #if 0 // not used
4217 if (p_ptr->auto_tunnel)
4218 p_ptr->auto_tunnel--;
4219 #endif // 0
4220 /* Hack -- Meditation */
4221 if (p_ptr->tim_meditation)
4222 (void)set_tim_meditation(Ind, p_ptr->tim_meditation - minus);
4223
4224 /* Hack -- Wraithform */
4225 if (p_ptr->tim_wraith)
4226 (void)set_tim_wraith(Ind, p_ptr->tim_wraith - minus_magic);
4227
4228 /* Hack -- Hallucinating */
4229 if (p_ptr->image) {
4230 int adjust = 1 + minus_health;
4231 if (get_skill(p_ptr, SKILL_HCURING) >= 50) adjust++;
4232 (void)set_image(Ind, p_ptr->image - adjust);
4233 }
4234
4235 /* Blindness */
4236 if (p_ptr->blind) {
4237 int adjust = 1 + minus_health;
4238 if (get_skill(p_ptr, SKILL_HCURING) >= 30) adjust++;
4239 (void)set_blind(Ind, p_ptr->blind - adjust);
4240 }
4241
4242 /* Times see-invisible */
4243 if (p_ptr->tim_invis)
4244 (void)set_tim_invis(Ind, p_ptr->tim_invis - minus_magic);
4245
4246 /* Times invisibility */
4247 if (p_ptr->tim_invisibility) {
4248 if (p_ptr->aggravate) {
4249 msg_print(Ind, "Your invisibility shield is broken by your aggravation.");
4250 (void)set_invis(Ind, 0, 0);
4251 } else {
4252 (void)set_invis(Ind, p_ptr->tim_invisibility - minus_magic, p_ptr->tim_invis_power2);
4253 }
4254 }
4255
4256 /* Timed infra-vision */
4257 if (p_ptr->tim_infra)
4258 (void)set_tim_infra(Ind, p_ptr->tim_infra - minus_magic);
4259
4260 /* Paralysis */
4261 if (p_ptr->paralyzed)
4262 (void)set_paralyzed(Ind, p_ptr->paralyzed - 1 - minus_health);
4263
4264 /* Confusion */
4265 if (p_ptr->confused)
4266 (void)set_confused(Ind, p_ptr->confused - minus - minus_combat - minus_health);
4267
4268 /* Afraid */
4269 if (p_ptr->afraid)
4270 (void)set_afraid(Ind, p_ptr->afraid - minus - minus_combat);
4271
4272 /* Fast */
4273 if (p_ptr->fast)
4274 (void)set_fast(Ind, p_ptr->fast - minus_magic, p_ptr->fast_mod);
4275
4276 /* Slow */
4277 if (p_ptr->slow)
4278 (void)set_slow(Ind, p_ptr->slow - minus_magic); // - minus_health
4279
4280 #ifdef ENABLE_MAIA
4281 if (p_ptr->divine_crit)
4282 (void)do_divine_crit(Ind, p_ptr->divine_crit - minus_magic, p_ptr->divine_crit_mod);
4283
4284 if (p_ptr->divine_hp)
4285 (void)do_divine_hp(Ind, p_ptr->divine_hp - minus_magic, p_ptr->divine_hp_mod);
4286
4287 if (p_ptr->divine_xtra_res_time)
4288 (void)do_divine_xtra_res_time(Ind, p_ptr->divine_xtra_res_time - minus_magic);
4289 #endif
4290 /* xtra shot? - the_sandman */
4291 if (p_ptr->focus_time)
4292 (void)do_focus_shot(Ind, p_ptr->focus_time - minus_magic, p_ptr->focus_val);
4293
4294 /* xtra stats? - the_sandman */
4295 if (p_ptr->xtrastat)
4296 (void)do_xtra_stats(Ind, p_ptr->xtrastat - minus_magic, p_ptr->statval);
4297
4298 /* Protection from evil */
4299 if (p_ptr->protevil)
4300 (void)set_protevil(Ind, p_ptr->protevil - minus_magic);
4301
4302 /* Holy Zeal - EA bonus */
4303 if (p_ptr->zeal)
4304 (void)set_zeal(Ind, p_ptr->zeal_power, p_ptr->zeal - 1);
4305
4306 /* Heart is still boldened */
4307 if (p_ptr->res_fear_temp)
4308 (void)set_res_fear(Ind, p_ptr->res_fear_temp - 1);
4309
4310 /* Holy Martyr */
4311 if (p_ptr->martyr)
4312 (void)set_martyr(Ind, p_ptr->martyr - 1);
4313 if (p_ptr->martyr_timeout) {
4314 p_ptr->martyr_timeout--;
4315 if (!p_ptr->martyr_timeout) msg_print(Ind, "The heavens are ready to accept your martyrium.");
4316 }
4317
4318 /* Mindcrafters' Willpower */
4319 if (p_ptr->mindboost)
4320 (void)set_mindboost(Ind, p_ptr->mindboost_power, p_ptr->mindboost - 1);
4321
4322 /* Mindcrafters' repulsion shield */
4323 if (p_ptr->kinetic_shield) (void)set_kinetic_shield(Ind, p_ptr->kinetic_shield - 1);
4324
4325 if (p_ptr->cloak_neutralized) p_ptr->cloak_neutralized--;
4326 if (p_ptr->cloaked > 1) {
4327 if (--p_ptr->cloaked == 1) {
4328 msg_print(Ind, "\377DYou cloaked your appearance!");
4329 msg_format_near(Ind, "\377w%s disappears before your eyes!", p_ptr->name);
4330 p_ptr->update |= (PU_BONUS | PU_MONSTERS);
4331 p_ptr->redraw |= (PR_STATE | PR_SPEED);
4332 handle_stuff(Ind);
4333 /* log a hint that newbies got it */
4334 if (p_ptr->lev == 15) s_printf("CLOAKING-15: %s.\n", p_ptr->name);
4335 p_ptr->warning_cloak = 1;
4336 }
4337 }
4338
4339 /* Invulnerability */
4340 /* Hack -- make -1 permanent invulnerability */
4341 if (p_ptr->invuln) {
4342 if (p_ptr->invuln > 0) {
4343 /* Hack: Don't diminish Stair-GoI by Antimagic: */
4344 if (p_ptr->invuln_dur >= 5) (void)set_invuln(Ind, p_ptr->invuln - minus_magic);
4345 else (void)set_invuln(Ind, p_ptr->invuln - 1);
4346 }
4347 //if (p_ptr->invuln == 5) msg_print(Ind, "\377vThe invulnerability shield starts to fade...");
4348 }
4349
4350 /* Heroism */
4351 if (p_ptr->hero)
4352 (void)set_hero(Ind, p_ptr->hero - 1);
4353
4354 /* Super Heroism */
4355 if (p_ptr->shero)
4356 (void)set_shero(Ind, p_ptr->shero - 1);
4357
4358 /* Furry */
4359 if (p_ptr->fury)
4360 (void)set_fury(Ind, p_ptr->fury - 1);
4361
4362 /* Berserk #2 */
4363 if (p_ptr->berserk)
4364 (void)set_berserk(Ind, p_ptr->berserk - 1);
4365
4366 /* Sprint? melee technique */
4367 if (p_ptr->melee_sprint)
4368 (void)set_melee_sprint(Ind, p_ptr->melee_sprint - 1);
4369
4370 /* Blessed */
4371 if (p_ptr->blessed)
4372 (void)set_blessed(Ind, p_ptr->blessed - 1);
4373
4374 /* Shield */
4375 if (p_ptr->shield)
4376 (void)set_shield(Ind, p_ptr->shield - minus_magic, p_ptr->shield_power, p_ptr->shield_opt, p_ptr->shield_power_opt, p_ptr->shield_power_opt2);
4377
4378 /* Timed deflection */
4379 if (p_ptr->tim_deflect)
4380 (void)set_tim_deflect(Ind, p_ptr->tim_deflect - minus_magic);
4381
4382 /* Timed Feather Falling */
4383 if (p_ptr->tim_ffall)
4384 (void)set_tim_ffall(Ind, p_ptr->tim_ffall - 1);
4385 if (p_ptr->tim_lev)
4386 (void)set_tim_lev(Ind, p_ptr->tim_lev - 1);
4387
4388 /* Timed regen */
4389 if (p_ptr->tim_regen)
4390 (void)set_tim_regen(Ind, p_ptr->tim_regen - 1, p_ptr->tim_regen_pow);
4391
4392 /* Thunderstorm */
4393 if (p_ptr->tim_thunder) {
4394 int dam = damroll(p_ptr->tim_thunder_p1, p_ptr->tim_thunder_p2);
4395 int i, tries = 600;
4396 monster_type *m_ptr = NULL;
4397
4398 while (tries) {
4399 /* Access the monster */
4400 m_ptr = &m_list[i = rand_range(1, m_max - 1)];
4401
4402 tries--;
4403
4404 /* Ignore "dead" monsters */
4405 if (!m_ptr->r_idx) continue;
4406
4407 /* pfft. not even our level */
4408
4409 if (!inarea(&p_ptr->wpos, &m_ptr->wpos)) continue;
4410 /* Cant see ? cant hit */
4411 if (!los(&p_ptr->wpos, p_ptr->py, p_ptr->px, m_ptr->fy, m_ptr->fx)) continue;
4412 if (distance(p_ptr->py, p_ptr->px, m_ptr->fy, m_ptr->fx) > 15) continue;
4413
4414 /* Do not hurt friends! */
4415 /* if (is_friend(m_ptr) >= 0) continue; */
4416 break;
4417 }
4418
4419 if (tries) {
4420 char m_name[MNAME_LEN];
4421
4422 monster_desc(Ind, m_name, i, 0);
4423 msg_format(Ind, "Lightning strikes %s.", m_name, i, dam);
4424 project(-Ind, 0, &p_ptr->wpos, m_ptr->fy, m_ptr->fx, dam, GF_THUNDER,
4425 PROJECT_KILL | PROJECT_ITEM | PROJECT_GRID, "");
4426 //project(-Ind, 0, &p_ptr->wpos, m_ptr->fy, m_ptr->fx, dam / 3, GF_ELEC,
4427 // PROJECT_KILL | PROJECT_ITEM, "");
4428 //project(-Ind, 0, &p_ptr->wpos, m_ptr->fy, m_ptr->fx, dam / 3, GF_LITE,
4429 // PROJECT_KILL | PROJECT_ITEM, "");
4430 //project(-Ind, 0, &p_ptr->wpos, m_ptr->fy, m_ptr->fx, dam / 3, GF_SOUND,
4431 // PROJECT_KILL | PROJECT_ITEM, "");
4432 }
4433
4434 (void)set_tim_thunder(Ind, p_ptr->tim_thunder - minus_magic, p_ptr->tim_thunder_p1, p_ptr->tim_thunder_p2);
4435 }
4436
4437 /* Oppose Acid */
4438 if (p_ptr->oppose_acid)
4439 (void)set_oppose_acid(Ind, p_ptr->oppose_acid - minus_magic);
4440
4441 /* Oppose Electricity */
4442 if (p_ptr->oppose_elec)
4443 (void)set_oppose_elec(Ind, p_ptr->oppose_elec - minus_magic);
4444
4445 /* Oppose Fire */
4446 if (p_ptr->oppose_fire)
4447 (void)set_oppose_fire(Ind, p_ptr->oppose_fire - minus_magic);
4448
4449 /* Oppose Cold */
4450 if (p_ptr->oppose_cold)
4451 (void)set_oppose_cold(Ind, p_ptr->oppose_cold - minus_magic);
4452
4453 /* Oppose Poison */
4454 if (p_ptr->oppose_pois)
4455 (void)set_oppose_pois(Ind, p_ptr->oppose_pois - minus_magic);
4456
4457 /*** Poison and Stun and Cut ***/
4458
4459 /* Poison */
4460 if (p_ptr->poisoned) {
4461 int adjust = (adj_con_fix[p_ptr->stat_ind[A_CON]] + minus);
4462 /* Apply some healing */
4463 if (get_skill(p_ptr, SKILL_HCURING) >= 30) adjust *= 2;
4464
4465 //(void)set_poisoned(Ind, p_ptr->poisoned - adjust - minus_health * 2, p_ptr->poisoned_attacker);
4466 (void)set_poisoned(Ind, p_ptr->poisoned - (adjust + minus_health) * (minus_health + 1), p_ptr->poisoned_attacker);
4467
4468 if (!p_ptr->poisoned) p_ptr->slow_poison = 0;
4469 }
4470
4471 /* Stun */
4472 if (p_ptr->stun) {
4473 #if 0
4474 int adjust = (adj_con_fix[p_ptr->stat_ind[A_CON]] + minus);
4475 /* Apply some healing */
4476 //(void)set_stun(Ind, p_ptr->stun - adjust - minus_health * 2);
4477 (void)set_stun(Ind, p_ptr->stun - (adjust + minus_health) * (minus_health + 1));
4478 #endif
4479 int adjust = minus + get_skill_scale_fine(p_ptr, SKILL_COMBAT, 2);
4480 // if (get_skill(p_ptr, SKILL_HCURING) >= 40) adjust = (adjust * 5) / 3;
4481 if (get_skill(p_ptr, SKILL_HCURING) >= 40) adjust++;
4482
4483 (void)set_stun(Ind, p_ptr->stun - adjust);
4484 }
4485
4486 /* Cut */
4487 if (p_ptr->cut) {
4488 int adjust = minus;// = (adj_con_fix[p_ptr->stat_ind[A_CON]] + minus);
4489
4490 /* Biofeedback always helps */
4491 if (p_ptr->biofeedback) adjust += 5;
4492
4493 /* Hack -- Truly "mortal" wound */
4494 if (p_ptr->cut > 1000) adjust = 0;
4495
4496 if (get_skill(p_ptr, SKILL_HCURING) >= 40) adjust *= 2;
4497
4498
4499 /* Apply some healing */
4500 //(void)set_cut(Ind, p_ptr->cut - adjust - minus_health * 2, p_ptr->cut_attacker);
4501 // (void)set_cut(Ind, p_ptr->cut - (adjust + minus_health) * (minus_health + 1), p_ptr->cut_attacker);
4502 (void)set_cut(Ind, p_ptr->cut - adjust * (minus_health + 1), p_ptr->cut_attacker);
4503 }
4504
4505 /* Temporary blessing of luck */
4506 if (p_ptr->bless_temp_luck) (void)bless_temp_luck(Ind, p_ptr->bless_temp_luck_power, p_ptr->bless_temp_luck - 1);
4507
4508 /* Temporary auras */
4509 if (p_ptr->sh_fire_tim) (void)set_sh_fire_tim(Ind, p_ptr->sh_fire_tim - minus_magic);
4510 if (p_ptr->sh_cold_tim) (void)set_sh_cold_tim(Ind, p_ptr->sh_cold_tim - minus_magic);
4511 if (p_ptr->sh_elec_tim) (void)set_sh_elec_tim(Ind, p_ptr->sh_elec_tim - minus_magic);
4512
4513 /* Still possible effects from another player's support spell on this player? */
4514 if (p_ptr->support_timer) {
4515 p_ptr->support_timer--;
4516 if (!p_ptr->support_timer) p_ptr->supp = p_ptr->supp_top = 0;
4517 }
4518
4519 #if POLY_RING_METHOD == 0
4520 /* Check polymorph rings with timeouts */
4521 for (i = INVEN_LEFT; i <= INVEN_RIGHT; i++) {
4522 o_ptr = &p_ptr->inventory[i];
4523 if ((o_ptr->tval == TV_RING) && (o_ptr->sval == SV_RING_POLYMORPH) && (o_ptr->timeout > 0) &&
4524 (p_ptr->body_monster == o_ptr->pval))
4525 {
4526 /* Decrease life-span */
4527 o_ptr->timeout--;
4528
4529 /* Hack -- notice interesting energy steps */
4530 if ((o_ptr->timeout < 100) || (!(o_ptr->timeout % 100))) {
4531 /* Window stuff */
4532 p_ptr->window |= (PW_INVEN | PW_EQUIP);
4533 }
4534
4535 /* Hack -- notice interesting fuel steps */
4536 if ((o_ptr->timeout > 0) && (o_ptr->timeout < 100) && !(o_ptr->timeout % 10))
4537 {
4538 if (p_ptr->disturb_minor) disturb(Ind, 0, 0);
4539 msg_print(Ind, "\376\377LYour ring flickers and fades, flashes of light run over its surface.");
4540 /* Window stuff */
4541 p_ptr->window |= (PW_INVEN | PW_EQUIP);
4542 } else if (o_ptr->timeout == 0) {
4543 disturb(Ind, 0, 0);
4544 msg_print(Ind, "\376\377LYour ring disintegrates!");
4545
4546 if ((p_ptr->body_monster == o_ptr->pval) &&
4547 ((p_ptr->r_killed[p_ptr->body_monster] < r_info[p_ptr->body_monster].level) ||
4548 (get_skill_scale(p_ptr, SKILL_MIMIC, 100) < r_info[p_ptr->body_monster].level)))
4549 {
4550 /* If player hasn't got high enough kill count anymore now, poly back to player form! */
4551 msg_print(Ind, "You polymorph back to your normal form.");
4552 do_mimic_change(Ind, 0, TRUE);
4553 }
4554
4555 /* Decrease the item, optimize. */
4556 inven_item_increase(Ind, i, -1);
4557 inven_item_optimize(Ind, i);
4558 }
4559 }
4560 }
4561 #endif
4562
4563 /* Don't accidentally float after dying */
4564 if (p_ptr->safe_float_turns) p_ptr->safe_float_turns--;
4565
4566 #ifdef USE_SOUND_2010
4567 /* Start delayed music for players who were greeted at start via audio */
4568 if (p_ptr->music_start) {
4569 p_ptr->music_start--;
4570 if (p_ptr->music_start == 0) handle_music(Ind);
4571 }
4572 #endif
4573
4574
4575 /*** Process Light ***/
4576
4577 /* Check for light being wielded */
4578 o_ptr = &p_ptr->inventory[INVEN_LITE];
4579
4580 /* Burn some fuel in the current lite */
4581 if (o_ptr->tval == TV_LITE) {
4582 u32b f1 = 0 , f2 = 0 , f3 = 0, f4 = 0, f5 = 0, f6 = 0, esp = 0;
4583
4584 /* Hack -- Use some fuel (sometimes) */
4585 #if 0
4586 if (!artifact_p(o_ptr) && !(o_ptr->sval == SV_LITE_DWARVEN)
4587 && !(o_ptr->sval == SV_LITE_FEANOR) && (o_ptr->pval > 0) && (!o_ptr->name1))
4588 #endif // 0
4589
4590 /* Extract the item flags */
4591 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
4592
4593 /* Hack -- Use some fuel */
4594 if ((f4 & TR4_FUEL_LITE) && (o_ptr->timeout > 0)) {
4595 /* Decrease life-span */
4596 o_ptr->timeout--;
4597
4598 /* Hack -- notice interesting fuel steps */
4599 if ((o_ptr->timeout < 100) || (!(o_ptr->timeout % 100))) {
4600 /* Window stuff */
4601 p_ptr->window |= (PW_INVEN | PW_EQUIP);
4602 }
4603
4604 /* Hack -- Special treatment when blind */
4605 if (p_ptr->blind) {
4606 /* Hack -- save some light for later */
4607 if (o_ptr->timeout == 0) o_ptr->timeout++;
4608 }
4609
4610 /* The light is now out */
4611 else if (o_ptr->timeout == 0) {
4612 bool refilled = FALSE;
4613
4614 disturb(Ind, 0, 0);
4615
4616 /* If flint is ready, refill at once */
4617 if (TOOL_EQUIPPED(p_ptr) == SV_TOOL_FLINT &&
4618 !p_ptr->paralyzed)
4619 {
4620 msg_print(Ind, "You prepare a flint...");
4621 refilled = do_auto_refill(Ind);
4622 if (!refilled)
4623 msg_print(Ind, "Oops, you're out of fuel!");
4624 }
4625
4626 if (!refilled) {
4627 msg_print(Ind, "Your light has gone out!");
4628 /* Calculate torch radius */
4629 p_ptr->update |= (PU_TORCH | PU_BONUS);
4630
4631 if (!p_ptr->warning_lite_refill) {
4632 p_ptr->warning_lite_refill = 1;
4633 msg_print(Ind, "\374\377yHINT: Press \377oSHIFT+f\377y to refill your light source. You will need a flask of");
4634 msg_print(Ind, "\374\377y oil for lanterns, or another torch to combine with an extinct torch.");
4635 // s_printf("warning_lite_refill: %s\n", p_ptr->name);
4636 }
4637 }
4638 #if 0 /* torch of presentiment goes poof to unlight trap, taken out for now - C. Blue */
4639 /* Torch disappears */
4640 if (o_ptr->sval == SV_LITE_TORCH && !o_ptr->timeout) {
4641 /* Decrease the item, optimize. */
4642 inven_item_increase(Ind, INVEN_LITE, -1);
4643 // inven_item_describe(Ind, INVEN_LITE);
4644 inven_item_optimize(Ind, INVEN_LITE);
4645 }
4646 #endif
4647 }
4648
4649 /* The light is getting dim */
4650 else if ((o_ptr->timeout < 100) && (!(o_ptr->timeout % 10))) {
4651 if (p_ptr->disturb_minor) disturb(Ind, 0, 0);
4652 msg_print(Ind, "Your light is growing faint.");
4653 }
4654 }
4655 }
4656
4657 /* Calculate torch radius */
4658 // p_ptr->update |= (PU_TORCH|PU_BONUS);
4659
4660 /* Silyl fun stuff >:) - C. Blue */
4661 if (p_ptr->corner_turn) {
4662 p_ptr->corner_turn -= (p_ptr->corner_turn > 2 ? 2 : p_ptr->corner_turn);
4663 if (p_ptr->corner_turn > 25) {
4664 p_ptr->corner_turn = 0;
4665 disturb(Ind, 0, 0);
4666 msg_print(Ind, "\377oYour head feels dizzy!");
4667 msg_format_near(Ind, "%s looks dizzy!", p_ptr->name);
4668 set_confused(Ind, 10 + rand_int(5));
4669 if (magik(50)) {
4670 msg_print(Ind, "\377oYou vomit!");
4671 msg_format_near(Ind, "%s vomits!", p_ptr->name);
4672 take_hit(Ind, 1, "circulation collapse", 0);
4673 if (!p_ptr->suscep_life) {
4674 if (p_ptr->chp < p_ptr->mhp) /* *invincibility* fix */
4675 if (p_ptr->food > PY_FOOD_FAINT - 1)
4676 (void)set_food(Ind, PY_FOOD_FAINT - 1);
4677 (void)set_poisoned(Ind, 0, 0);
4678 if (!p_ptr->free_act && !p_ptr->slow_digest)
4679 (void)set_paralyzed(Ind, p_ptr->paralyzed + rand_int(10) + 10);
4680 }
4681 }
4682 }
4683 }
4684
4685
4686 /*** Process Inventory ***/
4687
4688 /* Handle experience draining */
4689 // if (p_ptr->drain_exp && (p_ptr->wpos.wz != 0) && magik(30 - (60 / (p_ptr->drain_exp + 2))))
4690 /* experimental: maybe no expdrain or just less expdrain while player is on world surface.
4691 idea: allow classes who lack a *remove curse* spell to make more use of the rings. */
4692 // if (p_ptr->drain_exp && (p_ptr->wpos.wz != 0) && magik(30 - (60 / (p_ptr->drain_exp + 2))))
4693 // if (p_ptr->drain_exp && magik(p_ptr->wpos.wz != 0 ? 50 : 0) && magik(30 - (60 / (p_ptr->drain_exp + 2))))
4694 // if (p_ptr->drain_exp && magik(p_ptr->wpos.wz != 0 ? 50 : (istown(&p_ptr->wpos) ? 0 : 25)) && magik(30 - (60 / (p_ptr->drain_exp + 2))))
4695 /* changing above line to use istownarea() so you can sort your houses without drain */
4696 if (p_ptr->drain_exp && magik(
4697 p_ptr->wpos.wz != 0 ? (isdungeontown(&p_ptr->wpos) ? 0 : 50) :
4698 (istownarea(&p_ptr->wpos, MAX_TOWNAREA) ? 0 : 25)
4699 ) && magik(30 - (60 / (p_ptr->drain_exp + 2))))
4700 // take_xp_hit(Ind, 1 + p_ptr->lev / 5 + p_ptr->max_exp / 50000L, "Draining", TRUE, FALSE, FALSE);
4701 /* Moltor is right, exp drain was too weak for up to quite high levels. Need to make a new formula.. */
4702 {
4703 long exploss = 1 + p_ptr->lev + p_ptr->max_exp / 2000L;
4704
4705 /* Reduce exploss the more difficult it is for a race/class combination
4706 to aquire exp, ie depending on the character's exp% penalty.
4707 Otherwise wearing rings of power on Draconian or Maiar becomes quite harsh,
4708 and might require special strategies to counter such as taking ood U pits. */
4709 exploss = (exploss * 120L) / (50 + p_ptr->expfact / 2);
4710
4711 /* Cap it against level thresholds */
4712 #ifdef ALT_EXPRATIO
4713 if ((p_ptr->lev >= 2) && (player_exp[p_ptr->lev - 2] > p_ptr->exp - exploss))
4714 exploss = p_ptr->exp - player_exp[p_ptr->lev - 2];
4715 #else
4716 if ((p_ptr->lev >= 2) && ((((s64b)player_exp[p_ptr->lev - 2]) * ((s64b)p_ptr->expfact)) / 100L > p_ptr->exp - exploss))
4717 exploss = p_ptr->exp - player_exp[p_ptr->lev - 2];
4718 #endif
4719
4720 /* Drain it! */
4721 if (exploss > 0) take_xp_hit(Ind, exploss, "Draining", TRUE, FALSE, FALSE);
4722 }
4723
4724 #if 0
4725 {
4726 if ((rand_int(100) < 10) && (p_ptr->exp > 0)) {
4727 p_ptr->exp--;
4728 p_ptr->max_exp--;
4729 check_experience(Ind);
4730 }
4731 }
4732 #endif // 0
4733
4734 /* Now implemented here too ;) - C. Blue */
4735 /* let's say TY_CURSE lowers stats (occurs often) */
4736 if (p_ptr->ty_curse &&
4737 (rand_int(p_ptr->wpos.wz != 0 ? 100 : (istown(&p_ptr->wpos) || isdungeontown(&p_ptr->wpos) ? 0 : 300)) == 1) &&
4738 (get_skill(p_ptr, SKILL_HSUPPORT) < 50) && magik(100 - p_ptr->antimagic)) {
4739 msg_print(Ind, "An ancient foul curse shakes your body!");
4740 #if 0
4741 if (rand_int(2))
4742 (void)do_dec_stat(Ind, rand_int(6), STAT_DEC_NORMAL);
4743 else if (p_ptr->lev != 99) lose_exp(Ind, (p_ptr->exp / 100) * MON_DRAIN_LIFE);
4744 /* take_xp_hit(Ind, 1 + p_ptr->lev / 5 + p_ptr->max_exp / 50000L, "an ancient foul curse", TRUE, TRUE, TRUE); */
4745 #else
4746 (void)do_dec_stat(Ind, rand_int(6), STAT_DEC_NORMAL);
4747 #endif
4748 }
4749 /* and DG_CURSE randomly summons a monster (non-unique) */
4750 if (p_ptr->dg_curse && (rand_int(200) == 0) && !istown(&p_ptr->wpos) && !isdungeontown(&p_ptr->wpos) &&
4751 (get_skill(p_ptr, SKILL_HSUPPORT) < 50) && magik(100 - p_ptr->antimagic)) {
4752 msg_print(Ind, "An ancient morgothian curse calls out!");
4753 summon_specific(&p_ptr->wpos, p_ptr->py, p_ptr->px, p_ptr->lev + 20, 100, SUMMON_MONSTER, 0, 0);
4754 }
4755
4756 /* Handle experience draining. In Oangband, the effect
4757 * is worse, especially for high-level characters.
4758 * As per Tolkien, hobbits are resistant.
4759 */
4760 if ((p_ptr->black_breath || p_ptr->black_breath_tmp) &&
4761 rand_int((get_skill(p_ptr, SKILL_HCURING) >= 50) ? 250 : 150) < (p_ptr->prace == RACE_HOBBIT || p_ptr->suscep_life ? 2 : 5))
4762 {
4763 (void)do_dec_stat_time(Ind, rand_int(6), STAT_DEC_NORMAL, 25, 0, TRUE);
4764 take_xp_hit(Ind, 1 + p_ptr->lev * 3 + p_ptr->max_exp / 5000L,
4765 "Black Breath", TRUE, TRUE, TRUE);
4766 }
4767
4768 /* Drain Mana */
4769 if (p_ptr->drain_mana && p_ptr->csp) {
4770 p_ptr->csp -= p_ptr->drain_mana;
4771 if (magik(30)) p_ptr->csp -= p_ptr->drain_mana;
4772
4773 if (p_ptr->csp < 0) p_ptr->csp = 0;
4774
4775 /* Redraw */
4776 p_ptr->redraw |= (PR_MANA);
4777
4778 /* Window stuff */
4779 p_ptr->window |= (PW_PLAYER);
4780 }
4781
4782 /* Drain Hitpoints */
4783 if (p_ptr->drain_life) {
4784 int drain = (p_ptr->drain_life) * (rand_int(p_ptr->mhp / 100) + 1);
4785
4786 p_ptr->no_alert = TRUE;
4787 take_hit(Ind, drain < p_ptr->chp ? drain : p_ptr->chp, "life draining", 0);
4788 p_ptr->no_alert = FALSE;
4789 }
4790
4791 /* Note changes */
4792 j = 0;
4793
4794 /* Process inventory (blood potions going bad) */
4795 for (i = 0; i < INVEN_PACK; i++) {
4796 /* Get the object */
4797 o_ptr = &p_ptr->inventory[i];
4798
4799 /* Skip non-objects */
4800 if (!o_ptr->k_idx) continue;
4801
4802 if (!(o_ptr->tval == TV_POTION || o_ptr->tval == TV_FOOD) || !o_ptr->timeout) continue;
4803
4804 o_ptr->timeout--;
4805 /* Notice changes */
4806 if (!(o_ptr->timeout)) {
4807 inven_item_increase(Ind, i, -o_ptr->number);
4808 inven_item_describe(Ind, i);
4809 inven_item_optimize(Ind, i);
4810 j++;
4811 }
4812 }
4813
4814 /* Process equipment */
4815 for (i = INVEN_WIELD; i < INVEN_TOTAL; i++) {
4816 /* Get the object */
4817 o_ptr = &p_ptr->inventory[i];
4818
4819 /* Skip non-objects */
4820 if (!o_ptr->k_idx) continue;
4821
4822 /* Recharge activatable objects */
4823 /* (well, light-src should be handled here too? -Jir- */
4824 if ((o_ptr->timeout > 0) && ((o_ptr->tval != TV_LITE) || o_ptr->name1) &&
4825 !((o_ptr->tval == TV_RING) && (o_ptr->sval == SV_RING_POLYMORPH)))
4826 {
4827 /* Recharge */
4828 o_ptr->timeout--;
4829
4830 /* Notice changes */
4831 if (!(o_ptr->timeout)) j++;
4832 }
4833 }
4834
4835 /* Recharge rods */
4836 /* this should be moved to 'timeout'? */
4837 for (i = 0; i < INVEN_PACK; i++) {
4838 o_ptr = &p_ptr->inventory[i];
4839
4840 /* Examine all charging rods */
4841 if ((o_ptr->tval == TV_ROD) && (o_ptr->pval)) {
4842 /* Charge it */
4843 o_ptr->pval--;
4844
4845 /* Charge it further */
4846 if (o_ptr->pval && magik(p_ptr->skill_dev))
4847 o_ptr->pval--;
4848
4849 /* Notice changes */
4850 if (!(o_ptr->pval)) j++;
4851 }
4852 }
4853
4854 /* Notice changes */
4855 if (j) {
4856 /* Combine pack */
4857 p_ptr->notice |= (PN_COMBINE);
4858
4859 /* Window stuff */
4860 p_ptr->window |= (PW_INVEN | PW_EQUIP);
4861 }
4862
4863 /* Feel the inventory */
4864 if (!p_ptr->admin_dm) sense_inventory(Ind);
4865
4866 /*** Involuntary Movement ***/
4867
4868
4869 /* Delayed mind link */
4870 if (p_ptr->esp_link_end) {
4871 //msg_format(Ind, "ele: %d", p_ptr->esp_link_end);
4872 p_ptr->esp_link_end--;
4873
4874 /* Activate the break */
4875 if (!p_ptr->esp_link_end) {
4876 player_type *p_ptr2 = NULL;
4877 int Ind2;
4878 if ((Ind2 = get_esp_link(Ind, 0x0, &p_ptr2))) {
4879 if (!(p_ptr->esp_link_flags & LINKF_HIDDEN)) {
4880 msg_format(Ind, "\377RYou break the mind link with %s.", p_ptr2->name);
4881 msg_format(Ind2, "\377R%s breaks the mind link with you.", p_ptr->name);
4882 }
4883 if (p_ptr->esp_link_flags & LINKF_VIEW_DEDICATED) p_ptr->update |= PU_MUSIC;
4884 if (p_ptr2->esp_link_flags & LINKF_VIEW_DEDICATED) p_ptr2->update |= PU_MUSIC;
4885 p_ptr->esp_link = 0;
4886 p_ptr->esp_link_type = 0;
4887 p_ptr->esp_link_flags = 0;
4888 p_ptr->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
4889 p_ptr->update |= (PU_BONUS | PU_VIEW | PU_MANA | PU_HP);
4890 p_ptr->redraw |= (PR_BASIC | PR_EXTRA | PR_MAP);
4891 p_ptr2->esp_link = 0;
4892 p_ptr2->esp_link_type = 0;
4893 p_ptr2->esp_link_flags = 0;
4894 p_ptr2->window |= (PW_INVEN | PW_EQUIP | PW_PLAYER);
4895 p_ptr2->update |= (PU_BONUS | PU_VIEW | PU_MANA | PU_HP);
4896 p_ptr2->redraw |= (PR_BASIC | PR_EXTRA | PR_MAP);
4897 }
4898 }
4899 }
4900
4901 /* Don't do AFK in a store */
4902 if (p_ptr->tim_store) {
4903 if (p_ptr->store_num == -1) p_ptr->tim_store = 0;
4904 #ifdef ENABLE_GO_GAME
4905 else if (go_game_up && go_engine_player_id == p_ptr->id) p_ptr->tim_store = 0;
4906 #endif
4907 else if (!admin_p(Ind)) {
4908 /* Count down towards turnout */
4909 p_ptr->tim_store--;
4910
4911 /* Check if that town is 'crowded' */
4912 if (p_ptr->tim_store <= 0) {
4913 player_type *q_ptr;
4914 bool bye = FALSE;
4915
4916 for (j = 1; j < NumPlayers + 1; j++) {
4917 if (Ind == j) continue;
4918 if (admin_p(j)) continue;
4919 q_ptr = Players[j];
4920 if (!inarea(&p_ptr->wpos, &q_ptr->wpos)) continue;
4921 if (q_ptr->afk) continue;
4922
4923 /* new: other players must wait in line, or at least closely nearby, to kick you out */
4924 if (ABS(q_ptr->py - p_ptr->py) >= 4 || ABS(q_ptr->px - p_ptr->px) >= 4) continue;
4925
4926 bye = TRUE;
4927 break;
4928 }
4929
4930 if (bye) store_kick(Ind, TRUE);
4931 else p_ptr->tim_store = STORE_TURNOUT;
4932 }
4933 }
4934 }
4935
4936 if (p_ptr->tim_blacklist && !p_ptr->afk) {
4937 /* Count down towards turnout */
4938 p_ptr->tim_blacklist--;
4939 }
4940
4941 #if 1 /* use turns instead of day/night cycles */
4942 if (p_ptr->tim_watchlist) {
4943 /* Count down towards turnout */
4944 p_ptr->tim_watchlist--;
4945 }
4946 #endif
4947
4948 if (p_ptr->pstealing) {
4949 /* Count down towards turnout */
4950 p_ptr->pstealing--;
4951 // if (!p_ptr->pstealing) msg_print(Ind, "You're calm enough to steal from another player.");
4952 if (!p_ptr->pstealing) msg_print(Ind, "You're calm enough to attempt to steal something.");
4953 }
4954
4955 /* Delayed Word-of-Recall */
4956 if (p_ptr->word_recall) {
4957 /* Count down towards recall */
4958 p_ptr->word_recall--;
4959
4960 /* MEGA HACK: no recall if icky, or in a shop */
4961 if (!p_ptr->word_recall) {
4962 if (((p_ptr->anti_tele ||
4963 (check_st_anchor(&p_ptr->wpos, p_ptr->py, p_ptr->px) && !p_ptr->admin_dm))
4964 && !(l_ptr && (l_ptr->flags2 & LF2_NO_TELE))) ||
4965 p_ptr->store_num != -1 ||
4966 zcave[p_ptr->py][p_ptr->px].info & CAVE_STCK)
4967 p_ptr->word_recall = 1;
4968 else
4969 /* Activate the recall */
4970 do_recall(Ind, 0);
4971 }
4972 }
4973
4974 bypass_invuln = FALSE;
4975
4976 /* Evileye, please tell me if it's right */
4977 if (p_ptr->tim_wraith) {
4978 if(zcave[p_ptr->py][p_ptr->px].info & CAVE_STCK) {
4979 p_ptr->tim_wraith = 0;
4980 msg_print(Ind, "You lose your wraith powers.");
4981 msg_format_near(Ind, "%s loses %s wraith powers.", p_ptr->name, p_ptr->male ? "his":"her");
4982 }
4983 }
4984
4985 /* No wraithform on NO_MAGIC levels - C. Blue */
4986 if (p_ptr->tim_wraith) {
4987 if (p_ptr->wpos.wz && l_ptr && (l_ptr->flags1 & LF1_NO_MAGIC)) {
4988 p_ptr->tim_wraith = 0;
4989 msg_print(Ind, "You lose your wraith powers.");
4990 msg_format_near(Ind, "%s loses %s wraith powers.", p_ptr->name, p_ptr->male ? "his":"her");
4991 }
4992 }
4993
4994 return (TRUE);
4995 }
4996
4997 /* process any team games */
4998 static void process_games(int Ind) {
4999 player_type *p_ptr = Players[Ind];
5000 cave_type **zcave;
5001 cave_type *c_ptr;
5002 char sstr[80];
5003 int score = 0;
5004 if (!(zcave = getcave(&p_ptr->wpos))) return;
5005 c_ptr = &zcave[p_ptr->py][p_ptr->px];
5006
5007 if (c_ptr->feat == FEAT_AGOAL || c_ptr->feat == FEAT_BGOAL) {
5008 int ball;
5009 switch(gametype){
5010 /* rugby type game */
5011 case EEGAME_RUGBY:
5012 if ((ball = has_ball(p_ptr)) == -1) break;
5013
5014 if (p_ptr->team == 1 && c_ptr->feat == FEAT_BGOAL) {
5015 teamscore[0]++;
5016 msg_format_near(Ind, "\377R%s scored a goal!!!", p_ptr->name);
5017 msg_print(Ind, "\377rYou scored a goal!!!");
5018 score = 1;
5019 }
5020 if (p_ptr->team == 2 && c_ptr->feat == FEAT_AGOAL) {
5021 teamscore[1]++;
5022 msg_format_near(Ind, "\377B%s scored a goal!!!", p_ptr->name);
5023 msg_print(Ind, "\377gYou scored a goal!!!");
5024 score = 1;
5025 }
5026 if (score) {
5027 object_type tmp_obj;
5028 s16b ox, oy;
5029 int try;
5030 p_ptr->energy = 0;
5031 snprintf(sstr, 80, "Score: \377RReds: %d \377BBlues: %d", teamscore[0], teamscore[1]);
5032 msg_broadcast(0, sstr);
5033
5034 for (try = 0; try < 1000; try++) {
5035 ox = p_ptr->px + 5 - rand_int(10);
5036 oy = p_ptr->py + 5 - rand_int(10);
5037 if (!in_bounds(oy, ox)) continue;
5038 if (!cave_floor_bold(zcave, oy, ox)) continue;
5039 tmp_obj = p_ptr->inventory[ball];
5040 tmp_obj.marked2 = ITEM_REMOVAL_NEVER;
5041 drop_near(&tmp_obj, -1, &p_ptr->wpos, oy, ox);
5042 printf("dropping at %d %d (%d)\n", ox, oy, try);
5043 inven_item_increase(Ind, ball, -999);
5044 inven_item_optimize(Ind, ball);
5045 break;
5046 }
5047 /* Move the player from the goal area */
5048 teleport_player_force(Ind, 20);
5049 }
5050 break;
5051 /* capture the flag */
5052 case EEGAME_CTF:
5053 break;
5054 default:
5055 break; /* gcc 3.4 actually wants this - mikaelh */
5056 }
5057 }
5058 }
5059
5060 /*
5061 * Player processing that occurs at the end of a turn
5062 */
5063 static void process_player_end(int Ind) {
5064 player_type *p_ptr = Players[Ind];
5065
5066 // int x, y, i, j, new_depth, new_world_x, new_world_y;
5067 // int regen_amount, NumPlayers_old = NumPlayers;
5068 char attackstatus;
5069
5070 // byte *w_ptr;
5071
5072 /* slower 'running' movement over certain terrain */
5073 int real_speed = cfg.running_speed;
5074 cave_type *c_ptr, **zcave;
5075 if(!(zcave = getcave(&p_ptr->wpos))) return;
5076 c_ptr = &zcave[p_ptr->py][p_ptr->px];
5077
5078 if (Players[Ind]->conn == NOT_CONNECTED) return;
5079
5080 /* count turns online, afk, and idle */
5081 p_ptr->turns_online++;
5082 if (p_ptr->afk) p_ptr->turns_afk++;
5083 if (p_ptr->idle) p_ptr->turns_idle++;
5084 else if (!p_ptr->afk) p_ptr->turns_active++;
5085
5086 /* count how long they stay on a level (for EXTRA_LEVEL_FEELINGS) */
5087 p_ptr->turns_on_floor++;
5088 /* hack to indicate it to the player */
5089 if (p_ptr->turns_on_floor == TURNS_FOR_EXTRA_FEELING) Send_depth(Ind, &p_ptr->wpos);
5090
5091 /* calculate effective running speed */
5092 eff_running_speed(&real_speed, p_ptr, c_ptr);
5093
5094 /* Try to execute any commands on the command queue. */
5095 process_pending_commands(p_ptr->conn);
5096
5097 /* Mind Fusion/Control disable the char */
5098 if (p_ptr->esp_link && p_ptr->esp_link_type && (p_ptr->esp_link_flags & LINKF_OBJ)) return;
5099
5100
5101 /* Check for fire-till-kill and auto-retaliation */
5102 if (!p_ptr->requires_energy && /* <- new, required for allowing actions here (fire-till-kill)
5103 at <= 100% energy to prevent character lock-up. - C. Blue */
5104 !p_ptr->confused && !p_ptr->resting &&
5105 (!p_ptr->autooff_retaliator || /* <- these conditions seem buggy/wrong/useless? */
5106 !p_ptr->invuln))//&& !p_ptr->tim_manashield)))
5107 {
5108 /* Prepare auto-ret/fire-till-kill mode energy requirements.
5109 (Note: auto-ret is currently nothing special but always 1 x level_speed() as usual,
5110 so for auto-ret nothing changed basically. Therefore firing with auto-ret will also
5111 still have that small delay in the beginning, if player could fire multiple shots/round.
5112 This cannot be changed easily because here we don't know yet with which methid the
5113 player might auto-ret. - C. Blue) */
5114 int energy = level_speed(&p_ptr->wpos);
5115
5116 #if 0 /* don't modify energy! the correct amount of energy is deducted in the actual combat routines, and we want to have an extra amount of energy left, to break out quickly */
5117 /* test ftk type and use according energy requirements */
5118 if (p_ptr->shooting_till_kill) {
5119 if (target_okay(Ind)) {
5120 /* spells always require 1 turn: */
5121 if (p_ptr->shoot_till_kill_spell || p_ptr->shoot_till_kill_mimic);
5122 /* runespells excepted (for 'brief' modifier)*/
5123 else if (p_ptr->shoot_till_kill_rcraft) energy = p_ptr->FTK_energy;
5124 /* shooting with ranged weapon: */
5125 else energy = energy / p_ptr->num_fire;
5126 } else {
5127 p_ptr->shooting_till_kill = FALSE;
5128 /* normal auto-retaliation */
5129 //MIGHT NOT BE A MELEE ATTACK, SO COMMENTED OUT! else energy = energy / p_ptr->num_blow;
5130 }
5131 }
5132 /* normal auto-retaliation */
5133 //MIGHT NOT BE A MELEE ATTACK, SO COMMENTED OUT! else energy = energy / p_ptr->num_blow;
5134 #else
5135 /* is this line even required at all..? */
5136 if (p_ptr->shooting_till_kill && !target_okay(Ind)) p_ptr->shooting_till_kill = FALSE;
5137 #endif
5138
5139 /* Check for auto-retaliate */
5140 /* The 'old way' is actually the best way, because the initial delay of the 'new way',
5141 when it happens, can be very irritating. The best way to fix perceived responsiveness
5142 (of the old way) would be to not add full floor speed energy all at once, but in multiple
5143 parts, to (ideally) immediately cover the energy loss for a single attack performed. */
5144 #if 1 /* old way - get the usual 'double initial attack' in. \
5145 Drawback: Have to wait for nearly a full turn (1-(1/attacksperround)) \
5146 for FTK/meleeret to break out for performing a different action. -- this should be fixed now. May break out in 1/attacksperround now.) */
5147 if (p_ptr->energy >= energy) {
5148 #else /* new way - allows to instantly break out and perform another action (quaff/read) \
5149 but doesn't give the 'double initial attack' anymore, just a normal, single attack. \
5150 Main drawback: Walking into a mob will not smoothly transgress into auto-ret the next turn, \
5151 but wait for an extra turn before it begins, ie taking 2 turns until first attack got in. */
5152 if (p_ptr->energy >= energy * 2 - 1) {
5153 #endif
5154 /* assume nothing will happen here */
5155 p_ptr->auto_retaliating = FALSE;
5156
5157 if (p_ptr->shooting_till_kill) {
5158 /* stop shooting till kill if target is no longer available,
5159 instead of casting a final time into thin air! */
5160 if (target_okay(Ind)) {
5161 p_ptr->auto_retaliating = TRUE;
5162
5163 if (p_ptr->shoot_till_kill_spell) {
5164 cast_school_spell(Ind, p_ptr->shoot_till_kill_book, p_ptr->shoot_till_kill_spell - 1, 5, -1, 0);
5165 if (!p_ptr->shooting_till_kill) p_ptr->shoot_till_kill_spell = 0;
5166 } else if (p_ptr->shoot_till_kill_rcraft) {
5167 (void)cast_rune_spell(Ind, 5, p_ptr->FTK_e_flags, p_ptr->FTK_m_flags, 0, 1);
5168 } else if (p_ptr->shoot_till_kill_mimic) {
5169 do_cmd_mimic(Ind, p_ptr->shoot_till_kill_mimic - 1 + 3, 5);
5170 } else {
5171 do_cmd_fire(Ind, 5);
5172 #if 1 //what was the point of this hack again?..
5173 p_ptr->auto_retaliating = !p_ptr->auto_retaliating; /* hack, it's unset in do_cmd_fire IF it WAS successfull, ie reverse */
5174 #endif
5175 }
5176
5177 //not required really if (p_ptr->ranged_double && p_ptr->shooting_till_kill) do_cmd_fire(Ind, 5);
5178 p_ptr->shooty_till_kill = FALSE; /* if we didn't succeed shooting till kill, then we don't intend it anymore */
5179 } else {
5180 p_ptr->shooting_till_kill = FALSE;
5181 }
5182 }
5183
5184 /* Parania: Don't break fire-till-kill by starting to auto-retaliate when monster enters melee range!
5185 (note: that behaviour was reported, but haven't reproduced it in local testing so far) */
5186 if (!p_ptr->shooting_till_kill) {
5187 /* Check for nearby monsters and try to kill them */
5188 /* If auto_retaliate returns nonzero than we attacked
5189 * something and so should use energy.
5190 */
5191 p_ptr->auto_retaliaty = TRUE; /* hack: prevent going un-AFK from auto-retaliating */
5192 if ((!p_ptr->auto_retaliating) /* aren't we doing fire_till_kill already? */
5193 && (attackstatus = auto_retaliate(Ind))) /* attackstatus seems to be unused! */
5194 {
5195 p_ptr->auto_retaliating = TRUE;
5196 /* Use energy */
5197 //p_ptr->energy -= level_speed(p_ptr->dun_depth);
5198 }
5199 p_ptr->auto_retaliaty = FALSE;
5200 }
5201 } else {
5202 p_ptr->auto_retaliating = FALSE; /* if no energy left, this is required to turn off the no-run-while-retaliate-hack */
5203 }
5204
5205 /* Reset attack sfx counter in case player enabled half_sfx_attack or cut_sfx_attack. */
5206 if (!p_ptr->shooting_till_kill && !p_ptr->auto_retaliating) {
5207 p_ptr->count_cut_sfx_attack = 500;
5208 p_ptr->half_sfx_attack_state = FALSE;
5209 }
5210 }
5211
5212
5213 /* ('Handle running' from above was originally at this place) */
5214 /* Handle running -- 5 times the speed of walking */
5215 while (p_ptr->running && p_ptr->energy >= (level_speed(&p_ptr->wpos) * (real_speed + 1)) / real_speed) {
5216 char consume_full_energy;
5217 run_step(Ind, 0, &consume_full_energy);
5218 if (consume_full_energy) {
5219 /* Consume a full turn of energy in case we have e.g. attacked a monster */
5220 p_ptr->energy -= level_speed(&p_ptr->wpos);
5221 } else {
5222 p_ptr->energy -= level_speed(&p_ptr->wpos) / real_speed;
5223 }
5224 }
5225
5226
5227 /* Notice stuff */
5228 if (p_ptr->notice) notice_stuff(Ind);
5229
5230 /* XXX XXX XXX Pack Overflow */
5231 pack_overflow(Ind);
5232
5233 process_games(Ind);
5234
5235 /* Process things such as regeneration. */
5236 /* This used to be processed every 10 turns, but I am changing it to be
5237 * processed once every 5/6 of a "dungeon turn". This will make healing
5238 * and poison faster with respect to real time < 1750 feet and slower >
5239 * 1750 feet. - C. Blue
5240 */
5241 if (!(turn % (level_speed(&p_ptr->wpos) / 120))) {
5242 if (!process_player_end_aux(Ind)) return;
5243 }
5244
5245
5246 /* HACK -- redraw stuff a lot, this should reduce perceived latency. */
5247 /* This might not do anything, I may have been silly when I added this. -APD */
5248 /* Notice stuff (if needed) */
5249 if (p_ptr->notice) notice_stuff(Ind);
5250
5251 /* Update stuff (if needed) */
5252 if (p_ptr->update) update_stuff(Ind);
5253
5254 // if(zcave[p_ptr->py][p_ptr->px].info & CAVE_STCK) p_ptr->tim_wraith = 0;
5255
5256 /* Redraw stuff (if needed) */
5257 if (p_ptr->redraw) redraw_stuff(Ind);
5258
5259 /* Redraw stuff (if needed) */
5260 if (p_ptr->window) window_stuff(Ind);
5261 }
5262
5263
5264 bool stale_level(struct worldpos *wpos, int grace) {
5265 time_t now;
5266
5267 /* Hack -- towns are static for good? too spammy */
5268 // if (istown(wpos)) return FALSE;
5269 /* Hack -- make dungeon towns static though? too cheezy */
5270 // if (isdungeontown(wpos)) return FALSE;
5271
5272 /* Hack: In IDDC, all floors are stale for 2 minutes to allow logging back in if
5273 someone's connection dropped without the floor going stale right away,
5274 and towns to allow for easy item transfers.
5275 Small drawback: If someone logs back on after having taken a break from IDDC
5276 and he finds himself in a non-accessible area, he'll have to wait for
5277 2 minutes instead of the usual 10 seconds till the floor regens. */
5278 if (in_irondeepdive(wpos) && grace < 120) grace = 120;
5279
5280 now = time(&now);
5281 if (wpos->wz) {
5282 struct dungeon_type *d_ptr;
5283 struct dun_level *l_ptr;
5284 d_ptr = getdungeon(wpos);
5285 if (!d_ptr) return FALSE;
5286 l_ptr = &d_ptr->level[ABS(wpos->wz) - 1];
5287 #if DEBUG_LEVEL > 1
5288 s_printf("%s now:%d last:%d diff:%d grace:%d players:%d\n", wpos_format(0, wpos), now, l_ptr->lastused, now-l_ptr->lastused,grace, players_on_depth(wpos));
5289 #endif
5290 if (now - l_ptr->lastused > grace) return TRUE;
5291 } else if (now - wild_info[wpos->wy][wpos->wx].lastused > grace) {
5292 #if 0
5293 /* Never allow dealloc where there are houses */
5294 /* For now at least */
5295 int i;
5296
5297 for (i = 0; i < num_houses; i++) {
5298 if (inarea(wpos, &houses[i].wpos)) {
5299 if (!(houses[i].flags & HF_DELETED)) return FALSE;
5300 }
5301 }
5302 #endif
5303 return TRUE;
5304 }
5305 return FALSE;
5306 }
5307
5308 static void do_unstat(struct worldpos *wpos, bool fast_unstat) {
5309 int j;
5310
5311 /* Highlander Tournament sector00 is static while players are in dungeon! */
5312 if (wpos->wx == WPOS_SECTOR00_X && wpos->wy == WPOS_SECTOR00_Y && wpos->wz == WPOS_SECTOR00_Z && sector00separation) return;
5313
5314 /* Arena Monster Challenge */
5315 if (ge_special_sector && wpos->wx == WPOS_ARENA_X && wpos->wy == WPOS_ARENA_Y && wpos->wz == WPOS_ARENA_Z) return;
5316
5317 // Anyone on this depth?
5318 for (j = 1; j <= NumPlayers; j++)
5319 if (inarea(&Players[j]->wpos, wpos)) return;
5320
5321 // If this level is static and no one is actually on it
5322 // if (stale_level(wpos)) {
5323 /* limit static time in Ironman Deep Dive Challenge a lot */
5324 if (in_irondeepdive(wpos)) {
5325 if (isdungeontown(wpos)) {
5326 if (stale_level(wpos, 300)) new_players_on_depth(wpos, 0, FALSE);
5327 } else if ((getlevel(wpos) < cfg.min_unstatic_level) && (0 < cfg.min_unstatic_level)) {
5328 /* still 2 minutes static for very shallow levels */
5329 if (stale_level(wpos, 120)) new_players_on_depth(wpos, 0, FALSE);
5330 } else if (stale_level(wpos, 600)) new_players_on_depth(wpos, 0, FALSE);
5331 } else {
5332 #ifdef SAURON_FLOOR_FAST_UNSTAT
5333 if (fast_unstat) j = 60 * 60; //1h
5334 else
5335 #endif
5336 j = cfg.level_unstatic_chance * getlevel(wpos) * 60;
5337
5338 /* makes levels between 50ft and min_unstatic_level unstatic on player saving/quiting game/leaving level DEG */
5339 if (((getlevel(wpos) < cfg.min_unstatic_level) && (0 < cfg.min_unstatic_level)) ||
5340 stale_level(wpos, j))
5341 new_players_on_depth(wpos, 0, FALSE);
5342 }
5343 // }
5344 }
5345
5346 /*
5347 * 24 hourly scan of houses - should the odd house be owned by
5348 * a non player. Hopefully never, but best to save admin work.
5349 */
5350 static void scan_houses()
5351 {
5352 int i;
5353 //int lval;
5354 s_printf("Doing house maintenance\n");
5355 for(i = 0; i < num_houses; i++) {
5356 if(!houses[i].dna->owner) continue;
5357 switch(houses[i].dna->owner_type) {
5358 case OT_PLAYER:
5359 if(!lookup_player_name(houses[i].dna->owner)) {
5360 s_printf("Found old player houses. ID: %d\n", houses[i].dna->owner);
5361 kill_houses(houses[i].dna->owner, OT_PLAYER);
5362 }
5363 break;
5364 case OT_PARTY:
5365 if(!strlen(parties[houses[i].dna->owner].name)) {
5366 s_printf("Found old party houses. ID: %d\n", houses[i].dna->owner);
5367 kill_houses(houses[i].dna->owner, OT_PARTY);
5368 }
5369 break;
5370 case OT_GUILD:
5371 if(!strlen(guilds[houses[i].dna->owner].name)) {
5372 s_printf("Found old guild houses. ID: %d\n", houses[i].dna->owner);
5373 kill_houses(houses[i].dna->owner, OT_GUILD);
5374 }
5375 break;
5376 }
5377 }
5378 s_printf("Finished house maintenance\n");
5379 }
5380
5381 /* If the level unstaticer is not disabled, try to.
5382 * Now it's done every 60*fps, so better raise the
5383 * rate as such. - Jir -
5384 */
5385 /*
5386 * Deallocate all non static levels. (evileye)
5387 */
5388 static void purge_old()
5389 {
5390 int x, y, i;
5391
5392 // if (cfg.level_unstatic_chance > 0)
5393 {
5394 struct worldpos twpos;
5395 twpos.wz = 0;
5396 for(y = 0; y < MAX_WILD_Y; y++) {
5397 twpos.wy = y;
5398 for(x = 0; x < MAX_WILD_X; x++) {
5399 struct wilderness_type *w_ptr;
5400 struct dungeon_type *d_ptr;
5401
5402 twpos.wx = x;
5403 w_ptr = &wild_info[twpos.wy][twpos.wx];
5404
5405 if (cfg.level_unstatic_chance > 0 &&
5406 players_on_depth(&twpos))
5407 do_unstat(&twpos, FALSE);
5408
5409 if (!players_on_depth(&twpos) && !istown(&twpos) &&
5410 getcave(&twpos) && stale_level(&twpos, cfg.anti_scum))
5411 dealloc_dungeon_level(&twpos);
5412
5413 if (w_ptr->flags & WILD_F_UP) {
5414 d_ptr = w_ptr->tower;
5415 for (i = 1; i <= d_ptr->maxdepth; i++) {
5416 twpos.wz = i;
5417 if (cfg.level_unstatic_chance > 0 &&
5418 players_on_depth(&twpos))
5419 do_unstat(&twpos, d_ptr->type == DI_MT_DOOM && i == d_ptr->maxdepth);
5420
5421 if (!players_on_depth(&twpos) && getcave(&twpos) &&
5422 stale_level(&twpos, cfg.anti_scum))
5423 dealloc_dungeon_level(&twpos);
5424 }
5425 }
5426 if (w_ptr->flags & WILD_F_DOWN) {
5427 d_ptr = w_ptr->dungeon;
5428 for (i = 1; i <= d_ptr->maxdepth; i++) {
5429 twpos.wz = -i;
5430 if (cfg.level_unstatic_chance > 0 &&
5431 players_on_depth(&twpos))
5432 do_unstat(&twpos, d_ptr->type == DI_MT_DOOM && i == d_ptr->maxdepth);
5433
5434 if (!players_on_depth(&twpos) && getcave(&twpos) &&
5435 stale_level(&twpos, cfg.anti_scum))
5436 dealloc_dungeon_level(&twpos);
5437 }
5438 }
5439 twpos.wz = 0;
5440 }
5441 }
5442 }
5443 }
5444
5445 /*
5446 * TODO: Check for OT_GUILD (or guild will be mere den of cheeze)
5447 */
5448 void cheeze(object_type *o_ptr){
5449 #if CHEEZELOG_LEVEL > 3
5450 int j;
5451 /* check for inside a house */
5452 for(j = 0; j < num_houses; j++){
5453 if(inarea(&houses[j].wpos, &o_ptr->wpos)){
5454 if(fill_house(&houses[j], FILL_OBJECT, o_ptr)){
5455 if(houses[j].dna->owner_type == OT_PLAYER){
5456 if(o_ptr->owner != houses[j].dna->owner){
5457 if(o_ptr->level > lookup_player_level(houses[j].dna->owner))
5458 s_printf("Suspicious item: (%d,%d) Owned by %s, in %s's house. (%d,%d)\n", o_ptr->wpos.wx, o_ptr->wpos.wy, lookup_player_name(o_ptr->owner), lookup_player_name(houses[j].dna->owner), o_ptr->level, lookup_player_level(houses[j].dna->owner));
5459 }
5460 }
5461 else if(houses[j].dna->owner_type == OT_PARTY){
5462 int owner;
5463 if((owner = lookup_player_id(parties[houses[j].dna->owner].owner))){
5464 if(o_ptr->owner != owner){
5465 if(o_ptr->level > lookup_player_level(owner))
5466 s_printf("Suspicious item: (%d,%d) Owned by %s, in %s party house. (%d,%d)\n", o_ptr->wpos.wx, o_ptr->wpos.wy, lookup_player_name(o_ptr->owner), parties[houses[j].dna->owner].name, o_ptr->level, lookup_player_level(owner));
5467 }
5468 }
5469 }
5470 else if(houses[j].dna->owner_type == OT_GUILD){
5471 int owner;
5472 if((owner = guilds[houses[j].dna->owner].master)){
5473 if(o_ptr->owner != owner){
5474 if(o_ptr->level > lookup_player_level(owner))
5475 s_printf("Suspicious item: (%d,%d) Owned by %s, in %s party house. (%d,%d)\n", o_ptr->wpos.wx, o_ptr->wpos.wy, lookup_player_name(o_ptr->owner), guilds[houses[j].dna->owner].name, o_ptr->level, lookup_player_level(owner));
5476 }
5477 }
5478 }
5479 break;
5480 }
5481 }
5482 }
5483 #endif // CHEEZELOG_LEVEL > 3
5484 }
5485
5486
5487 /* Traditional (Vanilla) houses version of cheeze() - Jir - */
5488 #ifndef USE_MANG_HOUSE_ONLY
5489 void cheeze_trad_house()
5490 {
5491 #if CHEEZELOG_LEVEL > 3
5492 int i, j;
5493 house_type *h_ptr;
5494 object_type *o_ptr;
5495
5496 /* check for inside a house */
5497 for(j = 0;j < num_houses; j++) {
5498 h_ptr = &houses[j];
5499 if(h_ptr->dna->owner_type == OT_PLAYER) {
5500 for (i = 0; i < h_ptr->stock_num; i++) {
5501 o_ptr = &h_ptr->stock[i];
5502 if(o_ptr->owner != h_ptr->dna->owner) {
5503 if(o_ptr->level > lookup_player_level(h_ptr->dna->owner))
5504 s_printf("Suspicious item: (%d,%d) Owned by %s, in %s's trad house(%d). (%d,%d)\n",
5505 o_ptr->wpos.wx, o_ptr->wpos.wy,
5506 lookup_player_name(o_ptr->owner),
5507 lookup_player_name(h_ptr->dna->owner),
5508 j, o_ptr->level,
5509 lookup_player_level(h_ptr->dna->owner));
5510 }
5511 }
5512 }
5513 else if(h_ptr->dna->owner_type == OT_PARTY) {
5514 int owner;
5515 if((owner = lookup_player_id(parties[h_ptr->dna->owner].owner))) {
5516 for (i = 0; i < h_ptr->stock_num; i++) {
5517 o_ptr = &h_ptr->stock[i];
5518 if(o_ptr->owner != owner) {
5519 if(o_ptr->level > lookup_player_level(owner))
5520 s_printf("Suspicious item: (%d,%d) Owned by %s, in %s party trad house(%d). (%d,%d)\n",
5521 o_ptr->wpos.wx, o_ptr->wpos.wy,
5522 lookup_player_name(o_ptr->owner),
5523 parties[h_ptr->dna->owner].name,
5524 j, o_ptr->level, lookup_player_level(owner));
5525 }
5526 }
5527 }
5528 }
5529 else if(h_ptr->dna->owner_type == OT_GUILD) {
5530 int owner;
5531 if((owner = guilds[h_ptr->dna->owner].master)) {
5532 for (i = 0; i < h_ptr->stock_num; i++) {
5533 o_ptr = &h_ptr->stock[i];
5534 if(o_ptr->owner != owner) {
5535 if(o_ptr->level > lookup_player_level(owner))
5536 s_printf("Suspicious item: (%d,%d) Owned by %s, in %s guild trad house(%d). (%d,%d)\n",
5537 o_ptr->wpos.wx, o_ptr->wpos.wy,
5538 lookup_player_name(o_ptr->owner),
5539 guilds[h_ptr->dna->owner].name,
5540 j, o_ptr->level, lookup_player_level(owner));
5541 }
5542 }
5543 }
5544 }
5545 }
5546 #endif // CHEEZELOG_LEVEL > 3
5547 }
5548 #endif // USE_MANG_HOUSE_ONLY
5549
5550
5551 /* Change item mode of all items inside a house to the according house owner mode */
5552 void house_contents_chmod(object_type *o_ptr){
5553 #if CHEEZELOG_LEVEL > 3
5554 int j;
5555 /* check for inside a house */
5556 for(j = 0; j < num_houses; j++){
5557 if(inarea(&houses[j].wpos, &o_ptr->wpos)){
5558 if(fill_house(&houses[j], FILL_OBJECT, o_ptr)){
5559 if(houses[j].dna->owner_type == OT_PLAYER){
5560 o_ptr->mode = lookup_player_mode(houses[j].dna->owner));
5561 }
5562 else if(houses[j].dna->owner_type == OT_PARTY){
5563 int owner;
5564 if((owner = lookup_player_id(parties[houses[j].dna->owner].owner))){
5565 o_ptr->mode = lookup_player_mode(owner));
5566 }
5567 }
5568 break;
5569 }
5570 }
5571 }
5572 #endif // CHEEZELOG_LEVEL > 3
5573 }
5574
5575
5576 /* Traditional (Vanilla) houses version */
5577 #ifndef USE_MANG_HOUSE_ONLY
5578 void tradhouse_contents_chmod()
5579 {
5580 #if CHEEZELOG_LEVEL > 3
5581 int i, j;
5582 house_type *h_ptr;
5583 object_type *o_ptr;
5584
5585 /* check for inside a house */
5586 for(j = 0; j < num_houses; j++)
5587 {
5588 h_ptr = &houses[j];
5589 if(h_ptr->dna->owner_type == OT_PLAYER)
5590 {
5591 for (i = 0; i < h_ptr->stock_num; i++)
5592 {
5593 o_ptr = &h_ptr->stock[i];
5594 o_ptr->mode = lookup_player_mode(houses[j].dna->owner));
5595 }
5596 }
5597 else if(h_ptr->dna->owner_type == OT_PARTY)
5598 {
5599 int owner;
5600 if((owner = lookup_player_id(parties[h_ptr->dna->owner].owner)))
5601 {
5602 for (i = 0; i < h_ptr->stock_num; i++)
5603 {
5604 o_ptr = &h_ptr->stock[i];
5605 o_ptr->mode = lookup_player_mode(owner));
5606 }
5607 }
5608 }
5609 }
5610 #endif // CHEEZELOG_LEVEL > 3
5611 }
5612 #endif // USE_MANG_HOUSE_ONLY
5613
5614
5615
5616 /*
5617 * The purpose of this function is to scan through all the
5618 * game objects on the surface of the world. Objects which
5619 * are not owned will be ignored. Owned items will be checked.
5620 * If they are in a house, they will be compared against the
5621 * house owner. If this fails, the level difference will be
5622 * used to calculate some chance for the object's deletion.
5623 *
5624 * In the case for non house objects, essentially a TTL is
5625 * set. This protects them from instant loss, should a player
5626 * drop something just at the wrong time, but it should get
5627 * rid of some town junk. Artifacts should probably resist
5628 * this clearing.
5629 */
5630 /*
5631 * TODO:
5632 * - this function should handle items in 'traditional' houses too
5633 * - maybe rename this function (scan_objects and scan_objs...)
5634 */
5635 static void scan_objs() {
5636 int i, cnt = 0, dcnt = 0;
5637 bool sj;
5638 object_type *o_ptr;
5639 cave_type **zcave;
5640
5641 /* objects time-outing disabled? */
5642 if (!cfg.surface_item_removal && !cfg.dungeon_item_removal) return;
5643
5644 for (i = 0; i < o_max; i++) {
5645 o_ptr = &o_list[i];
5646 if (!o_ptr->k_idx) continue;
5647
5648 sj = FALSE;
5649 /* not dropped on player death or generated on the floor? (or special stuff) */
5650 if (o_ptr->marked2 == ITEM_REMOVAL_NEVER ||
5651 o_ptr->marked2 == ITEM_REMOVAL_HOUSE)
5652 continue;
5653
5654 /* hack for monster trap items */
5655 /* XXX noisy warning, eh? */ /* This is unsatisfactory. */
5656 if (!in_bounds_array(o_ptr->iy, o_ptr->ix) &&
5657 /* There was an old woman who swallowed a fly... */
5658 in_bounds_array(255 - o_ptr->iy, o_ptr->ix)) {
5659 sj = TRUE;
5660 o_ptr->iy = 255 - o_ptr->iy;
5661 }
5662
5663 /* Make town Inns a safe place to store (read: cheeze) items,
5664 at least as long as the town level is allocated. - C. Blue */
5665 if ((zcave = getcave(&o_ptr->wpos))
5666 && in_bounds_array(o_ptr->iy, o_ptr->ix) //paranoia or monster trap? or tradhouse?
5667 && (f_info[zcave[o_ptr->iy][o_ptr->ix].feat].flags1 & FF1_PROTECTED))
5668 continue;
5669
5670 /* check items on the world's surface */
5671 if (!o_ptr->wpos.wz && cfg.surface_item_removal) {
5672 if (in_bounds_array(o_ptr->iy, o_ptr->ix)) { //paranoia or monster trap? or tradhouse?
5673 /* Artifacts and objects that were inscribed and dropped by
5674 the dungeon master or by unique monsters on their death
5675 stay n times as long as cfg.surface_item_removal specifies */
5676 if (o_ptr->marked2 == ITEM_REMOVAL_QUICK) {
5677 if (++o_ptr->marked >= 10) {
5678 /* handle monster trap, if this item was part of one */
5679 if (sj) {
5680 erase_mon_trap(&o_ptr->wpos, o_ptr->iy, o_ptr->ix);
5681 sj = FALSE;
5682 } else
5683
5684 /* normal object */
5685 delete_object_idx(i, TRUE);
5686
5687 dcnt++;
5688 }
5689 } else if (o_ptr->marked2 == ITEM_REMOVAL_MONTRAP) {
5690 if (++o_ptr->marked >= 120) {
5691 /* handle monster trap, if this item was part of one */
5692 if (sj) {
5693 erase_mon_trap(&o_ptr->wpos, o_ptr->iy, o_ptr->ix);
5694 sj = FALSE;
5695 } else
5696
5697 /* normal object */
5698 delete_object_idx(i, TRUE);
5699
5700 dcnt++;
5701 }
5702 } else if (++o_ptr->marked >= ((like_artifact_p(o_ptr) || /* stormy too */
5703 (o_ptr->note && !o_ptr->owner))?
5704 cfg.surface_item_removal * 3 : cfg.surface_item_removal)
5705 + (o_ptr->marked2 == ITEM_REMOVAL_DEATH_WILD ? cfg.death_wild_item_removal : 0)
5706 + (o_ptr->marked2 == ITEM_REMOVAL_LONG_WILD ? cfg.long_wild_item_removal : 0)
5707 ) {
5708 /* handle monster trap, if this item was part of one */
5709 if (sj) {
5710 erase_mon_trap(&o_ptr->wpos, o_ptr->iy, o_ptr->ix);
5711 sj = FALSE;
5712 } else
5713
5714 /* normal object */
5715 delete_object_idx(i, TRUE);
5716
5717 dcnt++;
5718 }
5719 }
5720
5721 /* Also perform a 'cheeze check' */
5722 #if CHEEZELOG_LEVEL > 1
5723 else
5724 #if CHEEZELOG_LEVEL < 4
5725 /* ..only once an hour. (logs would fill the hd otherwise ;( */
5726 if (!(turn % (cfg.fps * 3600)))
5727 #endif /* CHEEZELOG_LEVEL (4) */
5728 cheeze(o_ptr);
5729 #endif /* CHEEZELOG_LEVEL (1) */
5730
5731 /* count amount of items that were checked */
5732 cnt++;
5733 }
5734
5735 /* check items on dungeon/tower floors */
5736 else if (o_ptr->wpos.wz && cfg.dungeon_item_removal) {
5737 if (in_bounds_array(o_ptr->iy, o_ptr->ix)) { //paranoia or monster trap? or tradhouse?
5738 /* Artifacts and objects that were inscribed and dropped by
5739 the dungeon master or by unique monsters on their death
5740 stay n times as long as cfg.surface_item_removal specifies */
5741 if (++o_ptr->marked >= ((artifact_p(o_ptr) ||
5742 (o_ptr->note && !o_ptr->owner)) ?
5743 cfg.dungeon_item_removal * 3 : cfg.dungeon_item_removal)) {
5744 /* handle monster trap, if this item was part of one */
5745 if (sj) {
5746 erase_mon_trap(&o_ptr->wpos, o_ptr->iy, o_ptr->ix);
5747 sj = FALSE;
5748 } else
5749
5750 /* normal object */
5751 delete_object_idx(i, TRUE);
5752
5753 dcnt++;
5754 }
5755 }
5756
5757 /* Also perform a 'cheeze check' */
5758 #if CHEEZELOG_LEVEL > 1
5759 else
5760 #if CHEEZELOG_LEVEL < 4
5761 /* ..only once an hour. (logs would fill the hd otherwise ;( */
5762 if (!(turn % (cfg.fps * 3600)))
5763 #endif /* CHEEZELOG_LEVEL (4) */
5764 cheeze(o_ptr);
5765 #endif /* CHEEZELOG_LEVEL (1) */
5766
5767 /* count amount of items that were checked */
5768 cnt++;
5769 }
5770
5771 /* restore monster trap hack */
5772 if (sj) o_ptr->iy = 255 - o_ptr->iy; /* mega-hack: never inbounds */
5773 }
5774
5775 /* log result */
5776 if (dcnt) s_printf("Scanned %d objects. Removed %d.\n", cnt, dcnt);
5777
5778 #ifndef USE_MANG_HOUSE_ONLY
5779 /* Additional cheeze check for all those items inside of mangband-style houses */
5780 #if CHEEZELOG_LEVEL > 1
5781 #if CHEEZELOG_LEVEL < 4
5782 if (!(turn % (cfg.fps * 3600)))
5783 #endif /* CHEEZELOG_LEVEL (4) */
5784 cheeze_trad_house();
5785 #endif /* CHEEZELOG_LEVEL (1) */
5786 #endif /* USE_MANG_HOUSE_ONLY */
5787
5788 }
5789
5790
5791 /* NOTE: this can cause short freeze if many stores exist,
5792 * so it isn't called from process_various any more.
5793 * the store changes their stocks when a player enters a store.
5794 *
5795 * (However, this function can be called by admin characters)
5796 */
5797 void store_turnover()
5798 {
5799 int i, n;
5800
5801 for(i = 0; i < numtowns; i++) {
5802 /* Maintain each shop (except home and auction house) */
5803 // for (n = 0; n < MAX_BASE_STORES - 2; n++)
5804 for (n = 0; n < max_st_idx; n++) {
5805 /* Maintain */
5806 store_maint(&town[i].townstore[n]);
5807 }
5808
5809 /* Sometimes, shuffle the shopkeepers */
5810 if (rand_int(STORE_SHUFFLE) == 0) {
5811 /* Shuffle a random shop (except home and auction house) */
5812 // store_shuffle(&town[i].townstore[rand_int(MAX_BASE_STORES - 2)]);
5813 store_shuffle(&town[i].townstore[rand_int(max_st_idx)]);
5814 }
5815 }
5816 }
5817
5818 /*
5819 * This function handles "global" things such as the stores,
5820 * day/night in the town, etc.
5821 */
5822 /* Added the japanese unique respawn patch -APD-
5823 It appears that each moment of time is equal to 10 minutes?
5824 */
5825 /* called only every 10 turns
5826 */
5827 /* WARNING: Every if-check in here that tests for turns % cfg.fps
5828 should instead check for turns % cfg.fps*10, because this function
5829 is only called every 10 turns as stated above, otherwise
5830 depending on cfg.fps it might be skipped sometimes, which may or
5831 may not be critical depending on what it does! - C. Blue */
5832 static void process_various(void)
5833 {
5834 int i, j;
5835 int h = 0, m = 0, s = 0, dwd = 0, dd = 0, dm = 0, dy = 0;
5836 #ifndef ARCADE_SERVER
5837 time_t now;
5838 struct tm *tmp;
5839 #endif
5840 //cave_type *c_ptr;
5841 player_type *p_ptr;
5842
5843 //char buf[1024];
5844
5845 /* this TomeCron stuff could be merged at some point
5846 to improve efficiency. ;) */
5847
5848 if (!(turn % 2)) {
5849 do_xfers(); /* handle filetransfers per second
5850 * FOR NOW!!! DO NOT TOUCH/CHANGE!!!
5851 */
5852 }
5853
5854 /* Save the server state occasionally */
5855 if (!(turn % ((NumPlayers ? 10L : 1000L) * SERVER_SAVE))) {
5856 save_server_info();
5857
5858 /* Save each player */
5859 for (i = 1; i <= NumPlayers; i++) {
5860 /* Save this player */
5861 save_player(i);
5862 }
5863 }
5864
5865 #if 0 /* might skip an hour if transition is unprecise, ie 1:59 -> 3:00 */
5866 /* Extra LUA function in custom.lua */
5867 time(&now);
5868 tmp = localtime(&now);
5869 h = tmp->tm_hour;
5870 m = tmp->tm_min;
5871 s = tmp->tm_sec;
5872
5873 if (!(turn % (cfg.fps * 3600)))
5874 exec_lua(0, format("cron_1h(\"%s\", %d, %d, %d)", showtime(), h, m, s));
5875 #else
5876 #ifndef ARCADE_SERVER
5877 if (!(turn % (cfg.fps * 10))) { /* call every 10 seconds instead of every 10 turns, to save some CPU time (yeah well...)*/
5878 /* Extra LUA function in custom.lua */
5879 time(&now);
5880 tmp = localtime(&now);
5881 h = tmp->tm_hour;
5882 m = tmp->tm_min;
5883 s = tmp->tm_sec;
5884 if (h != cron_1h_last_hour) {
5885 exec_lua(0, format("cron_1h(\"%s\", %d, %d, %d)", showtime(), h, m, s));
5886 cron_1h_last_hour = h;
5887 }
5888 }
5889 #endif
5890 #endif
5891
5892 /* daily maintenance */
5893 if (!(turn % (cfg.fps * 86400))) {
5894 s_printf("24 hours maintenance cycle\n");
5895 scan_players();
5896 scan_accounts();
5897 scan_houses();
5898 #ifdef IRONDEEPDIVE_MIXED_TYPES
5899 (void)scan_iddc();
5900 #endif
5901 if (cfg.auto_purge) {
5902 s_printf("previous server status: m_max(%d) o_max(%d)\n",
5903 m_max, o_max);
5904 compact_monsters(0, TRUE);
5905 compact_objects(0, TRUE);
5906 // compact_traps(0, TRUE);
5907 s_printf("current server status: m_max(%d) o_max(%d)\n",
5908 m_max, o_max);
5909 }
5910 #if DEBUG_LEVEL > 1
5911 else s_printf("Current server status: m_max(%d) o_max(%d)\n",
5912 m_max, o_max);
5913 #endif
5914 s_printf("Finished maintenance\n");
5915 get_date(&dwd, &dd, &dm, &dy);
5916 exec_lua(0, format("cron_24h(\"%s\", %d, %d, %d, %d, %d, %d, %d)", showtime(), h, m, s, dwd, dd, dm, dy));
5917
5918 /* bbs_add_line("--- new day line ---"); */
5919 }
5920
5921 /* every 10 seconds */
5922 if (!(turn % (cfg.fps * 10))) purge_old();
5923
5924 #if 0 /* disable for now - mikaelh */
5925 if (!(turn % (cfg.fps * 50))) {
5926 /* Tell the scripts that we're alive */
5927 update_check_file();
5928 }
5929 #endif
5930
5931
5932 /* Things handled once per hour */
5933 if (!(turn % (cfg.fps * 3600))) {
5934 /* Purge leaderless guilds after a while */
5935 for (i = 0; i < MAX_GUILDS; i++) {
5936 if (!guilds[i].members) continue;
5937 if (!lookup_player_name(guilds[i].master) &&
5938 guilds[i].timeout++ >= 24 * 7)
5939 guild_timeout(i);
5940 }
5941 }
5942
5943
5944 /* Handle certain things once a minute */
5945 if (!(turn % (cfg.fps * 60))) {
5946 monster_race *r_ptr;
5947
5948 check_xorders(); /* check for expiry of extermination orders */
5949 check_banlist(); /* unban some players */
5950 scan_objs(); /* scan objects and houses */
5951
5952 if (dungeon_store_timer) dungeon_store_timer--; /* Timeout */
5953 if (dungeon_store2_timer) dungeon_store2_timer--; /* Timeout */
5954
5955 if (great_pumpkin_timer > 0) great_pumpkin_timer--; /* HALLOWEEN */
5956 if (great_pumpkin_duration > 0) {
5957 great_pumpkin_duration--;
5958 if (!great_pumpkin_duration) {
5959 monster_type *m_ptr;
5960 int k, m_idx;
5961
5962 for (k = m_top - 1; k >= 0; k--) {
5963 /* Access the index */
5964 m_idx = m_fast[k];
5965 /* Access the monster */
5966 m_ptr = &m_list[m_idx];
5967 /* Excise "dead" monsters */
5968 if (!m_ptr->r_idx) {
5969 /* Excise the monster */
5970 m_fast[k] = m_fast[--m_top];
5971 /* Skip */
5972 continue;
5973 }
5974 /* Players of too high level cannot participate in killing attemps (anti-cheeze) */
5975 /* search for Great Pumpkins */
5976 if (m_ptr->r_idx == RI_PUMPKIN1 || m_ptr->r_idx == RI_PUMPKIN2 || m_ptr->r_idx == RI_PUMPKIN3) {
5977 msg_print_near_monster(m_idx, "\377oThe Great Pumpkin wails and suddenly vanishes into thin air!");
5978 s_printf("HALLOWEEN: The Great Pumpkin despawned.\n");
5979 delete_monster_idx(k, TRUE);
5980 //note_spot_depth(&p_ptr->wpos, y, x);
5981 great_pumpkin_timer = rand_int(2); /* fast respawn if not killed! */
5982 }
5983 }
5984 }
5985 else if (great_pumpkin_duration <= 5) {
5986 monster_type *m_ptr;
5987 int k, m_idx;
5988
5989 for (k = m_top - 1; k >= 0; k--) {
5990 /* Access the index */
5991 m_idx = m_fast[k];
5992 /* Access the monster */
5993 m_ptr = &m_list[m_idx];
5994 /* Excise "dead" monsters */
5995 if (!m_ptr->r_idx) {
5996 /* Excise the monster */
5997 m_fast[k] = m_fast[--m_top];
5998 /* Skip */
5999 continue;
6000 }
6001 /* Players of too high level cannot participate in killing attemps (anti-cheeze) */
6002 /* search for Great Pumpkins */
6003 if (m_ptr->r_idx == RI_PUMPKIN1 || m_ptr->r_idx == RI_PUMPKIN2 || m_ptr->r_idx == RI_PUMPKIN3) {
6004 msg_print_near_monster(m_idx, "\377oThe Great Pumpkin wails and seems to fade..");
6005 break;
6006 }
6007 }
6008 }
6009 }
6010
6011 if (season_xmas) { /* XMAS */
6012 if (santa_claus_timer > 0) santa_claus_timer--;
6013 if (santa_claus_timer == 0) {
6014 struct worldpos wpos = {cfg.town_x, cfg.town_y, 0};
6015 cave_type **zcave = getcave(&wpos);
6016 if (zcave) { /* anyone in town? */
6017 int x, y, tries = 50;
6018
6019 /* Try nine locations */
6020 while (--tries) {
6021 /* Pick location nearby hard-coded town centre */
6022 scatter(&wpos, &y, &x, 34, 96, 10, 0);
6023
6024 /* Require "empty" floor grids */
6025 if (!cave_empty_bold(zcave, y, x)) continue;
6026
6027 if (place_monster_aux(&wpos, y, x, RI_SANTA2, FALSE, FALSE, 0, 0) == 0) {
6028 s_printf("%s XMAS: Generated Santa Claus.\n", showtime());
6029 santa_claus_timer = -1; /* put generation on hold */
6030 break;
6031 }
6032 }
6033 if (!tries) santa_claus_timer = 1; /* fast respawn, probably paranoia */
6034 }
6035 }
6036 }
6037
6038 for (i = 1; i <= NumPlayers; i++) {
6039 p_ptr = Players[i];
6040
6041 /* Update the player retirement timers */
6042 // If our retirement timer is set
6043 if (p_ptr->retire_timer > 0) {
6044 int k = p_ptr->retire_timer;
6045
6046 // Decrement our retire timer
6047 j = k - 1;
6048
6049 // Alert him
6050 if (j <= 60) {
6051 msg_format(i, "\377rYou have %d minute%s of tenure left.", j, j > 1 ? "s" : "");
6052 }
6053 else if (j <= 1440 && !(k % 60)) {
6054 msg_format(i, "\377yYou have %d hours of tenure left.", j / 60);
6055 }
6056 else if (!(k % 1440)) {
6057 msg_format(i, "\377GYou have %d days of tenure left.", j / 1440);
6058 }
6059
6060
6061 // If the timer runs out, forcibly retire
6062 // this character.
6063 if (!j) do_cmd_suicide(i);
6064 }
6065
6066 /* reduce warning_rest cooldown */
6067 if (p_ptr->warning_rest_cooldown) p_ptr->warning_rest_cooldown--;
6068 }
6069
6070 /* Reswpan for kings' joy -Jir- */
6071 /* Update the unique respawn timers */
6072 /* I moved this out of the loop above so this may need some
6073 * tuning now - mikaelh */
6074 for (j = 1; j <= NumPlayers; j++) {
6075 p_ptr = Players[j];
6076 if (!p_ptr->total_winner) continue;
6077 if (istownarea(&p_ptr->wpos, MAX_TOWNAREA)) continue; /* allow kings idling instead of having to switch chars */
6078
6079 /* Hack -- never Maggot and his dogs :) */
6080 i = rand_range(60, MAX_R_IDX - 2);
6081 r_ptr = &r_info[i];
6082
6083 /* Make sure we are looking at a dead unique */
6084 if (!(r_ptr->flags1 & RF1_UNIQUE)) {
6085 j--;
6086 continue;
6087 }
6088
6089 if (p_ptr->r_killed[i] != 1) continue;
6090
6091 /* Hack -- Sauron and Morgoth are exceptions (and all > Morgy-uniques)
6092 --- QUESTOR is currently NOT used!! - C. Blue */
6093 if (r_ptr->flags1 & RF1_QUESTOR) continue;
6094 /* ..hardcoding them instead: */
6095 if (r_ptr->level >= 98) continue; /* Not Michael either */
6096
6097 if (r_ptr->flags7 & RF7_NAZGUL) continue; /* No nazguls */
6098
6099 /* Dungeon bosses probably shouldn't respawn */
6100 if (r_ptr->flags0 & RF0_FINAL_GUARDIAN) continue;
6101
6102 /* Special-dropping uniques too! */
6103 /* if (r_ptr->flags1 & RF1_DROP_CHOSEN) continue; */
6104
6105 // if (r_ptr->max_num > 0) continue;
6106 if (rand_int(cfg.unique_respawn_time * (r_ptr->level + 1)) > 9)
6107 continue;
6108
6109 /* "Ressurect" the unique */
6110 p_ptr->r_killed[i] = 0;
6111 Send_unique_monster(j, i);
6112
6113 /* Tell the player */
6114 /* the_sandman: added colour */
6115 msg_format(j,"\377v%s rises from the dead!",(r_name + r_ptr->name));
6116 }
6117
6118 /* discard reserved character names that exceed their timeout */
6119 for (i = 0; i < MAX_RESERVED_NAMES; i++) {
6120 if (!reserved_name_character[i][0]) break;
6121 if (reserved_name_timeout[i]) {
6122 reserved_name_timeout[i]--;
6123 continue;
6124 }
6125 for (j = i + 1; j < MAX_RESERVED_NAMES; j++) {
6126 if (!reserved_name_character[j][0]) {
6127 reserved_name_character[j - 1][0] = '\0';
6128 break;
6129 }
6130 strcpy(reserved_name_character[j - 1], reserved_name_character[j]);
6131 strcpy(reserved_name_account[j - 1], reserved_name_account[j]);
6132 reserved_name_timeout[j - 1] = reserved_name_timeout[j];
6133 }
6134 break;
6135 }
6136 }
6137
6138 #if 0
6139 /* Grow trees very occasionally */
6140 if (!(turn % (10L * GROW_TREE))) {
6141 /* Find a suitable location */
6142 for (i = 1; i < 1000; i++) {
6143 cave_type *c_ptr;
6144
6145 /* Pick a location */
6146 y = rand_range(1, MAX_HGT - 1);
6147 x = rand_range(1, MAX_WID - 1);
6148
6149 /* Acquire pointer */
6150 #ifdef NEW_DUNGEON
6151 c_ptr = &zcave[0][y][x];
6152 #else
6153 c_ptr = &cave[0][y][x];
6154 #endif
6155
6156 /* Only allow "dirt" */
6157 if (c_ptr->feat != FEAT_DIRT) continue;
6158
6159 /* Never grow on top of objects or monsters */
6160 if (c_ptr->m_idx) continue;
6161 if (c_ptr->o_idx) continue;
6162
6163 /* Grow a tree here */
6164 c_ptr->feat = get_seasonal_tree();
6165
6166 /* Show it */
6167 everyone_lite_spot(0, y, x);
6168
6169 /* Done */
6170 break;
6171 }
6172 }
6173 #endif /* if 0 */
6174 }
6175
6176 int find_player(s32b id)
6177 {
6178 int i;
6179
6180 for (i = 1; i < NumPlayers + 1; i++) {
6181 player_type *p_ptr = Players[i];
6182 if (Players[i]->conn == NOT_CONNECTED) return 0;
6183 if (p_ptr->id == id) return i;
6184 }
6185
6186 /* assume none */
6187 return 0;
6188 }
6189
6190 int find_player_name(char *name)
6191 {
6192 int i;
6193
6194 for (i = 1; i < NumPlayers + 1; i++) {
6195 player_type *p_ptr = Players[i];
6196
6197 if (!strcmp(p_ptr->name, name)) return i;
6198 }
6199
6200 /* assume none */
6201 return 0;
6202 }
6203
6204 void process_player_change_wpos(int Ind) {
6205 player_type *p_ptr = Players[Ind];
6206 worldpos *wpos = &p_ptr->wpos;
6207 cave_type **zcave;
6208 //worldpos twpos;
6209 dun_level *l_ptr;
6210 int d, j, x, y, startx = 0, starty = 0, m_idx, my, mx, tries, emergency_x, emergency_y, dlv = getlevel(wpos);
6211 char o_name_short[ONAME_LEN];
6212 bool smooth_ambient = FALSE, travel_ambient = FALSE;
6213
6214 /* IDDC specialties */
6215 if (in_irondeepdive(&p_ptr->wpos_old)) {
6216 /* for obtaining statistical IDDC information: */
6217 if (!is_admin(p_ptr)) {
6218 s_printf("CVRG-IDDC: '%s' leaves floor %d:\n", p_ptr->name, p_ptr->wpos_old.wz);
6219 log_floor_coverage(getfloor(&p_ptr->wpos_old), &p_ptr->wpos_old);
6220 }
6221
6222 #ifdef IDDC_EASY_SPEED_RINGS
6223 #if IDDC_EASY_SPEED_RINGS > 0
6224 /* IDDC_EASY_SPEED_RINGS - allow easy speed-ring finding for the first 1-2 rings,
6225 from floor 60+ and optionally another one from floor 80+? */
6226 if (wpos->wz == 60
6227 #if IDDC_EASY_SPEED_RINGS > 1
6228 || wpos->wz == 80
6229 #endif
6230 ) p_ptr->IDDC_flags++;//hack: abuse 2 flag bits as a counter
6231 #endif
6232 #endif
6233 }
6234
6235 /* Decide whether we stayed long enough on the previous
6236 floor to get distinct floor feelings here, and also
6237 start counting turns we spend on this floor. */
6238 //there's no scumming in RPG_SERVER!
6239 #ifdef RPG_SERVER
6240 p_ptr->distinct_floor_feeling = TRUE;
6241 #else
6242 if (p_ptr->turns_on_floor >= TURNS_FOR_EXTRA_FEELING)
6243 p_ptr->distinct_floor_feeling = TRUE;
6244 else
6245 p_ptr->distinct_floor_feeling = FALSE;
6246 #endif
6247 if (p_ptr->new_level_method != LEVEL_OUTSIDE &&
6248 p_ptr->new_level_method != LEVEL_OUTSIDE_RAND &&
6249 p_ptr->new_level_method != LEVEL_HOUSE)
6250 p_ptr->turns_on_floor = 0;
6251
6252 #ifdef ENABLE_MAIA
6253 /* reset void gate coordinates */
6254 if (p_ptr->voidx) {
6255 if (getcave(&p_ptr->wpos_old))
6256 cave_set_feat(&p_ptr->wpos_old, p_ptr->voidy, p_ptr->voidx, twall_erosion(&p_ptr->wpos_old, p_ptr->voidy, p_ptr->voidx));
6257 p_ptr->voidx = 0;
6258 p_ptr->voidy = 0;
6259 }
6260 #endif
6261
6262 /* being on different floors destabilizes mind fusion */
6263 if (p_ptr->esp_link_type && p_ptr->esp_link)
6264 change_mind(Ind, FALSE);
6265
6266 /* Check "maximum depth" to make sure it's still correct */
6267 if (wpos->wz != 0 && (!p_ptr->ghost || p_ptr->admin_dm)) {
6268 if (dlv > p_ptr->max_dlv) p_ptr->max_dlv = dlv;
6269
6270 #ifdef SEPARATE_RECALL_DEPTHS
6271 j = recall_depth_idx(wpos, p_ptr);
6272 if (ABS(wpos->wz) > p_ptr->max_depth[j]) p_ptr->max_depth[j] = ABS(wpos->wz);
6273 #endif
6274 }
6275
6276 /* Make sure the server doesn't think the player is in a store */
6277 if (p_ptr->store_num != -1) {
6278 handle_store_leave(Ind);
6279 Send_store_kick(Ind);
6280 }
6281
6282 /* Hack -- artifacts leave the queen/king */
6283 /* also checks the artifact list */
6284 if ((cfg.fallenkings_etiquette || cfg.kings_etiquette) && !is_admin(p_ptr) && cfg.strict_etiquette) {
6285 object_type *o_ptr;
6286 char o_name[ONAME_LEN];
6287 bool no_etiquette =
6288 (!(cfg.fallenkings_etiquette && p_ptr->once_winner && !p_ptr->total_winner) &&
6289 !(cfg.kings_etiquette && p_ptr->total_winner));
6290
6291
6292 for (j = 0; j < INVEN_TOTAL; j++) {
6293 o_ptr = &p_ptr->inventory[j];
6294 if (!o_ptr->k_idx || !true_artifact_p(o_ptr)) continue;
6295
6296 /* fix the list */
6297 handle_art_inumpara(o_ptr->name1);
6298 if (!a_info[o_ptr->name1].known && (o_ptr->ident & ID_KNOWN))
6299 a_info[o_ptr->name1].known = TRUE;
6300
6301 if (no_etiquette ||
6302 winner_artifact_p(o_ptr) || admin_artifact_p(o_ptr)) continue;
6303
6304 /* Describe the object */
6305 object_desc(Ind, o_name, o_ptr, TRUE, 0);
6306 object_desc(0, o_name_short, o_ptr, TRUE, 256);
6307
6308 /* Message */
6309 msg_format(Ind, "\377y%s bids farewell to you...", o_name);
6310 handle_art_d(o_ptr->name1);
6311
6312 /* Eliminate the item */
6313 inven_item_increase(Ind, j, -99);
6314 inven_item_describe(Ind, j);
6315 inven_item_optimize(Ind, j);
6316
6317 /* Tell everyone */
6318 msg_broadcast_format(Ind, "\374\377M* \377U%s has been lost once more. \377M*", o_name_short);
6319
6320 j--;
6321 }
6322 }
6323
6324 /* Reset bot hunting variables */
6325 p_ptr->silly_door_exp = 0;
6326
6327 /* For Ironman Deep Dive Challenge */
6328 p_ptr->IDDC_logscum = 0; /* we changed floor, all fine and dandy.. */
6329
6330 /* Somebody has entered an ungenerated level */
6331 if (players_on_depth(wpos) && !getcave(wpos)) {
6332 /* Allocate space for it */
6333 alloc_dungeon_level(wpos);
6334
6335 /* Generate a dungeon level there */
6336 generate_cave(wpos, p_ptr);
6337
6338 #if 0 /* arena monster challenge - paranoia (should be generated in xtra1.c, and permanently static really) */
6339 //copy/pasted code, non-functional as is, just put it here for later maybe
6340 new_players_on_depth(&wpos, 1, TRUE); /* make it static */
6341 s_printf("EVENT_LAYOUT: Generating arena_tt at %d,%d,%d\n", wpos.wx, wpos.wy, wpos.wz);
6342 process_dungeon_file("t_arena_tt.txt", &wpos, &ystart, &xstart, MAX_HGT, MAX_WID, TRUE);
6343 #endif
6344
6345 /* allow non-normal (interval-timed) ambient sfx, but depend on our own fast-travel-induced rythm */
6346 travel_ambient = TRUE;
6347 } else if (players_on_depth(wpos) == 1) travel_ambient = TRUE; /* exception - if we're the only one here we won't mess up someone else's ambient sfx rythm, so it's ok */
6348
6349 #ifdef USE_SOUND_2010
6350 if (travel_ambient) {
6351 /* hack for single ambient sfx while speed-travelling the wild.
6352 (Random info: Travelling a sector horizontally at +4 spd takes ~20s if no obstacles.) */
6353 if (!wpos->wz && !p_ptr->wpos_old.wz) {
6354 wilderness_type *w_ptr = &wild_info[wpos->wy][wpos->wx];
6355 #if 0 /* require to travel lots of the same type of terrain to play hacked-rythem ambient sfx? */
6356 if (w_ptr->type != w_ptr->type)
6357 p_ptr->ambient_sfx_timer = 0;
6358 else
6359 #endif
6360 if (p_ptr->ambient_sfx_timer >= w_ptr->ambient_sfx_timer && !w_ptr->ambient_sfx_dummy) {
6361 p_ptr->ambient_sfx_timer = 0;
6362 w_ptr->ambient_sfx_timer = 0;
6363 }
6364 } else p_ptr->ambient_sfx_timer = 0;
6365 }
6366 #endif
6367
6368 zcave = getcave(wpos);
6369 l_ptr = getfloor(wpos);
6370
6371 /* Clear the "marked" and "lit" flags for each cave grid */
6372 for (y = 0; y < MAX_HGT; y++) {
6373 for (x = 0; x < MAX_WID; x++) {
6374 p_ptr->cave_flag[y][x] = 0;
6375 }
6376 }
6377 /* Player now starts mapping this dungeon (as far as its flags allow) */
6378 if (l_ptr) p_ptr->dlev_id = l_ptr->id;
6379 else p_ptr->dlev_id = 0;
6380
6381 /* Memorize the town and all wilderness levels close to town */
6382 if (istownarea(wpos, MAX_TOWNAREA)) {
6383 p_ptr->max_panel_rows = MAX_PANEL_ROWS;
6384 p_ptr->max_panel_cols = MAX_PANEL_COLS;
6385
6386 p_ptr->max_tradpanel_rows = MAX_TRADPANEL_ROWS;
6387 p_ptr->max_tradpanel_cols = MAX_TRADPANEL_COLS;
6388
6389 p_ptr->cur_hgt = MAX_HGT;
6390 p_ptr->cur_wid = MAX_WID;
6391
6392 if (istown(wpos)) {
6393 p_ptr->town_x = wpos->wx;
6394 p_ptr->town_y = wpos->wy;
6395
6396 /* for PVP-mode, reset diminishing healing */
6397 p_ptr->heal_effect = 0;
6398 /* and anti-fleeing teleport prevention */
6399 p_ptr->pvp_prevent_tele = 0;
6400 p_ptr->redraw |= PR_DEPTH;
6401 }
6402 } else if (wpos->wz) {
6403 /* Hack -- tricky formula, but needed */
6404 p_ptr->max_panel_rows = MAX_PANEL_ROWS_L;
6405 p_ptr->max_panel_cols = MAX_PANEL_COLS_L;
6406
6407 p_ptr->max_tradpanel_rows = MAX_TRADPANEL_ROWS_L;
6408 p_ptr->max_tradpanel_cols = MAX_TRADPANEL_COLS_L;
6409
6410 p_ptr->cur_hgt = l_ptr->hgt;
6411 p_ptr->cur_wid = l_ptr->wid;
6412
6413 /* only show 'dungeon explore feelings' when entering a dungeon, for now */
6414 #ifdef DUNGEON_VISIT_BONUS
6415 show_floor_feeling(Ind, (p_ptr->wpos_old.wz == 0));
6416 #else
6417 show_floor_feeling(Ind, FALSE);
6418 #endif
6419 } else {
6420 p_ptr->max_panel_rows = MAX_PANEL_ROWS;
6421 p_ptr->max_panel_cols = MAX_PANEL_COLS;
6422
6423 p_ptr->max_tradpanel_rows = MAX_TRADPANEL_ROWS;
6424 p_ptr->max_tradpanel_cols = MAX_TRADPANEL_COLS;
6425
6426 p_ptr->cur_hgt = MAX_HGT;
6427 p_ptr->cur_wid = MAX_WID;
6428 }
6429
6430 #ifdef BIG_MAP
6431 if (p_ptr->max_panel_rows < 0) p_ptr->max_panel_rows = 0;
6432 if (p_ptr->max_panel_cols < 0) p_ptr->max_panel_cols = 0;
6433 #endif
6434
6435 #ifdef ALLOW_NR_CROSS_PARTIES
6436 if (p_ptr->party && at_netherrealm(&p_ptr->wpos_old) && !at_netherrealm(&p_ptr->wpos)
6437 && compat_mode(p_ptr->mode, parties[p_ptr->party].cmode)
6438 /* actually preserve his nether realm cross party for this,
6439 so he can tell everyone involved about Valinor in party chat: */
6440 && p_ptr->auto_transport != AT_VALINOR
6441 && !p_ptr->admin_dm)
6442 /* need to leave party, since we might be teamed up with incompatible char mode players! */
6443 party_leave(Ind, FALSE);
6444 #endif
6445 #ifdef ALLOW_NR_CROSS_ITEMS
6446 if (in_netherrealm(&p_ptr->wpos_old) && !in_netherrealm(&p_ptr->wpos))
6447 for (j = 1; j < INVEN_TOTAL; j++)
6448 p_ptr->inventory[j].NR_tradable = FALSE;
6449 #endif
6450 #ifdef IDDC_NO_TRADE_CHEEZE
6451 /* hack: abuse NR_tradable to mark items _untradable_ for first couple of IDDC floors */
6452 if (p_ptr->wpos.wx == WPOS_IRONDEEPDIVE_X &&
6453 p_ptr->wpos.wy == WPOS_IRONDEEPDIVE_Y) {
6454 /* on entering the first floor, mark all items we already possess for anti-trade-cheeze */
6455 if (p_ptr->wpos.wz == WPOS_IRONDEEPDIVE_Z) {
6456 for (j = 1; j < INVEN_TOTAL; j++) {
6457 if (exceptionally_shareable_item(&p_ptr->inventory[j])) continue;
6458 p_ptr->inventory[j].NR_tradable = TRUE;
6459 }
6460 /* after reaching n-th floor, unmark them to make them freely available for trading again */
6461 } else if (ABS(p_ptr->wpos_old.wz) < IDDC_NO_TRADE_CHEEZE && ABS(p_ptr->wpos.wz) >= IDDC_NO_TRADE_CHEEZE) {
6462 for (j = 1; j < INVEN_TOTAL; j++)
6463 p_ptr->inventory[j].NR_tradable = FALSE;
6464 }
6465 }
6466 #endif
6467
6468 #if defined(DUNGEON_VISIT_BONUS) || defined(ALLOW_NR_CROSS_PARTIES) || defined(ALLOW_NR_CROSS_ITEMS)
6469 wpcopy(&p_ptr->wpos_old, &p_ptr->wpos);
6470 #endif
6471
6472 /* Allow the player again to find another random IDDC town, if he hit a static IDDC town */
6473 if (is_fixed_irondeepdive_town(&p_ptr->wpos, dlv)) p_ptr->IDDC_found_rndtown = FALSE;
6474 /* Cover disallowing the same if he enters a random town someone else already generated */
6475 else if (in_irondeepdive(&p_ptr->wpos) && l_ptr && (l_ptr->flags1 & LF1_RANDOM_TOWN)) p_ptr->IDDC_found_rndtown = TRUE;
6476
6477 /* hack -- update night/day in wilderness levels */
6478 if (!wpos->wz) {
6479 if (IS_DAY) player_day(Ind);
6480 else player_night(Ind);
6481 }
6482
6483 /* Determine starting location */
6484 switch (p_ptr->new_level_method) {
6485 /* Climbed down */
6486 case LEVEL_RECALL_DOWN:
6487 case LEVEL_DOWN: starty = level_down_y(wpos);
6488 startx = level_down_x(wpos);
6489 break;
6490
6491 /* Climbed up */
6492 case LEVEL_RECALL_UP:
6493 case LEVEL_UP: starty = level_up_y(wpos);
6494 startx = level_up_x(wpos);
6495 break;
6496
6497 /* Teleported level */
6498 case LEVEL_RAND: starty = level_rand_y(wpos);
6499 startx = level_rand_x(wpos);
6500 break;
6501
6502 /* Used ghostly travel */
6503 case LEVEL_PROB_TRAVEL:
6504 case LEVEL_GHOST: starty = p_ptr->py;
6505 startx = p_ptr->px;
6506 break;
6507
6508 /* Over the river and through the woods */
6509 case LEVEL_OUTSIDE:
6510 smooth_ambient = TRUE; /* normal wilderness running */
6511 case LEVEL_HOUSE:
6512 starty = p_ptr->py;
6513 startx = p_ptr->px;
6514 break;
6515
6516 /* this is used instead of extending the level_rand_y/x
6517 into the negative direction to prevent us from
6518 alocing so many starting locations. Although this does
6519 not make players teleport to simmilar locations, this
6520 could be achieved by seeding the RNG with the depth. */
6521
6522 case LEVEL_OUTSIDE_RAND:
6523 /* make sure we aren't in an "icky" location */
6524 emergency_x = 0; emergency_y = 0; tries = 0;
6525 do {
6526 starty = rand_int((l_ptr ? l_ptr->hgt : MAX_HGT)-3)+1;
6527 startx = rand_int((l_ptr ? l_ptr->wid : MAX_WID)-3)+1;
6528 if (cave_floor_bold(zcave, starty, startx)) {
6529 emergency_x = startx;
6530 emergency_y = starty;
6531 }
6532 }
6533 while ( ((zcave[starty][startx].info & CAVE_ICKY)
6534 || (zcave[starty][startx].feat == FEAT_DEEP_WATER)
6535 || (!cave_floor_bold(zcave, starty, startx)))
6536 && (++tries < 10000) );
6537 if (tries == 10000 && emergency_x) {
6538 startx = emergency_x;
6539 starty = emergency_y;
6540 }
6541 break;
6542 case LEVEL_TO_TEMPLE:
6543 /* Try to find a temple */
6544 for (y = 0; y < MAX_HGT; y++) {
6545 for (x = 0; x < MAX_WID; x++) {
6546 cave_type* c_ptr = &zcave[y][x];
6547 if (c_ptr->feat == FEAT_SHOP) {
6548 struct c_special *cs_ptr = GetCS(c_ptr, CS_SHOP);
6549 if (cs_ptr) {
6550 int which = cs_ptr->sc.omni;
6551 if (which == STORE_TEMPLE) {
6552 /* Found a temple */
6553 startx = x;
6554 starty = y;
6555 break;
6556 }
6557 }
6558 }
6559 }
6560 if (startx) break;
6561 }
6562
6563 if (!startx) {
6564 /* Random coordinates in case there's no temple */
6565 starty = level_rand_y(wpos);
6566 startx = level_rand_x(wpos);
6567 }
6568 break;
6569 }
6570
6571 /* Highlander Tournament hack: pseudo-teleport the player
6572 after he took a staircase inside the highlander dungeon */
6573 if (sector00separation &&
6574 p_ptr->wpos.wx == WPOS_HIGHLANDER_DUN_X &&
6575 p_ptr->wpos.wy == WPOS_HIGHLANDER_DUN_Y &&
6576 (p_ptr->wpos.wz * WPOS_HIGHLANDER_DUN_Z) > 0
6577 && l_ptr)
6578 starty = l_ptr->hgt + 1; /* for the code right below :) ("Hack -- handle smaller floors") */
6579
6580 /* Hack -- handle smaller floors */
6581 if (l_ptr && (starty > l_ptr->hgt || startx > l_ptr->wid)) {
6582 /* make sure we aren't in an "icky" location */
6583 emergency_x = 0; emergency_y = 0; tries = 0;
6584 do {
6585 starty = rand_int(l_ptr->hgt-3)+1;
6586 startx = rand_int(l_ptr->wid-3)+1;
6587 if (cave_floor_bold(zcave, starty, startx)) {
6588 emergency_x = startx;
6589 emergency_y = starty;
6590 }
6591 }
6592 while ( ((zcave[starty][startx].info & CAVE_ICKY)
6593 || (!cave_floor_bold(zcave, starty, startx)))
6594 && (++tries < 10000) );
6595 if (tries == 10000 && emergency_x) {
6596 startx = emergency_x;
6597 starty = emergency_y;
6598 }
6599 }
6600
6601 //printf("finding area (%d,%d)\n",startx,starty);
6602 /* Place the player in an empty space */
6603 //for (j = 0; j < 1500; ++j)
6604 for (j = 0; j < 5000; j++) {
6605 /* Increasing distance */
6606 d = (j + 149) / 150;
6607
6608 /* Pick a location */
6609 scatter(wpos, &y, &x, starty, startx, d, 1);
6610
6611 /* Must have an "empty" grid */
6612 if (!cave_empty_bold(zcave, y, x)) continue;
6613
6614 /* Not allowed to go onto a icky location (house) if Depth <= 0 */
6615 if (wpos->wz == 0 && !(p_ptr->global_event_temp & PEVF_ICKY_OK)) {
6616 if((zcave[y][x].info & CAVE_ICKY) && (p_ptr->new_level_method != LEVEL_HOUSE)) continue;
6617 if(!(zcave[y][x].info & CAVE_ICKY) && (p_ptr->new_level_method == LEVEL_HOUSE)) continue;
6618 }
6619
6620 /* Prevent recalling or prob-travelling into no-tele vaults and monster nests! - C. Blue */
6621 if ((zcave[y][x].info & (CAVE_STCK | CAVE_NEST_PIT)) &&
6622 (p_ptr->new_level_method == LEVEL_RECALL_UP || p_ptr->new_level_method == LEVEL_RECALL_DOWN ||
6623 p_ptr->new_level_method == LEVEL_RAND || p_ptr->new_level_method == LEVEL_OUTSIDE_RAND ||
6624 p_ptr->new_level_method == LEVEL_PROB_TRAVEL)
6625 && !(p_ptr->global_event_temp & PEVF_STCK_OK))
6626 continue;
6627
6628 /* Prevent landing onto a store entrance */
6629 if (zcave[y][x].feat == FEAT_SHOP) continue;
6630
6631 /* Must be inside the level borders - mikaelh */
6632 if (x < 1 || y < 1 || x > p_ptr->cur_wid - 2 || y > p_ptr->cur_hgt - 2)
6633 continue;
6634
6635 /* should somewhat stay away from certain locations? */
6636 if (p_ptr->avoid_loc)
6637 for (d = 0; d < p_ptr->avoid_loc; d++)
6638 if (distance(y, x, p_ptr->avoid_loc_y[d], p_ptr->avoid_loc_x[d]) < 8)
6639 continue;
6640
6641 break;
6642 }
6643 /* this is required to make sense, isn't it.. */
6644 if (j == 5000) {
6645 x = startx;
6646 y = starty;
6647 }
6648
6649 #if 0
6650 /* Place the player in an empty space */
6651 for (j = 0; j < 1500; ++j) {
6652 /* Increasing distance */
6653 d = (j + 149) / 150;
6654
6655 /* Pick a location */
6656 scatter(wpos, &y, &x, starty, startx, d, 1);
6657
6658 /* Must have an "empty" grid */
6659 if (!cave_empty_bold(zcave, y, x)) continue;
6660
6661 /* Not allowed to go onto a icky location (house) if Depth <= 0 */
6662 if ((wpos->wz == 0) && (zcave[y][x].info & CAVE_ICKY))
6663 break;
6664 }
6665 #endif /*0*/
6666 p_ptr->py = y;
6667 p_ptr->px = x;
6668
6669 grid_affects_player(Ind);
6670
6671 /* Update the player location */
6672 zcave[y][x].m_idx = 0 - Ind;
6673 cave_midx_debug(wpos, y, x, -Ind);
6674
6675 /* Update his golem's location */
6676 for (m_idx = m_top - 1; m_idx >= 0; m_idx--) {
6677 monster_type *m_ptr = &m_list[m_fast[m_idx]];
6678 cave_type **mcave;
6679 mcave = getcave(&m_ptr->wpos);
6680
6681 if (!m_fast[m_idx]) continue;
6682
6683 /* Excise "dead" monsters */
6684 if (!m_ptr->r_idx) continue;
6685
6686 if (m_ptr->owner != p_ptr->id) continue;
6687
6688 if (m_ptr->mind & GOLEM_GUARD && !(m_ptr->mind & GOLEM_FOLLOW)) continue;
6689
6690 /* XXX XXX XXX (merging) */
6691 starty = m_ptr->fy;
6692 startx = m_ptr->fx;
6693 starty = y;
6694 startx = x;
6695
6696 if (!m_ptr->wpos.wz && !(m_ptr->mind & GOLEM_FOLLOW)) continue;
6697 /*
6698 if (m_ptr->mind & GOLEM_GUARD && !(m_ptr->mind&GOLEM_FOLLOW)) continue;
6699 */
6700
6701 /* Place the golems in an empty space */
6702 for (j = 0; j < 1500; ++j) {
6703 /* Increasing distance */
6704 d = (j + 149) / 150;
6705
6706 /* Pick a location */
6707 scatter(wpos, &my, &mx, starty, startx, d, 0);
6708
6709 /* Must have an "empty" grid */
6710 if (!cave_empty_bold(zcave, my, mx)) continue;
6711
6712 /* Not allowed to go onto a icky location (house) if Depth <= 0 */
6713 if ((wpos->wz == 0) && (zcave[my][mx].info & CAVE_ICKY))
6714 continue;
6715 break;
6716 }
6717 if (mcave) {
6718 mcave[m_ptr->fy][m_ptr->fx].m_idx = 0;
6719 everyone_lite_spot(&m_ptr->wpos, m_ptr->fy, m_ptr->fx);
6720 }
6721 wpcopy(&m_ptr->wpos,wpos);
6722 mcave = getcave(&m_ptr->wpos);
6723 m_ptr->fx = mx;
6724 m_ptr->fy = my;
6725 if (mcave) {
6726 mcave[m_ptr->fy][m_ptr->fx].m_idx = m_fast[m_idx];
6727 everyone_lite_spot(&m_ptr->wpos, m_ptr->fy, m_ptr->fx);
6728 }
6729
6730 /* Update the monster (new location) */
6731 update_mon(m_fast[m_idx], TRUE);
6732 }
6733 #if 0
6734 while (TRUE) {
6735 y = rand_range(1, ((Depth) ? (MAX_HGT - 2) : (SCREEN_HGT - 2)));
6736 x = rand_range(1, ((Depth) ? (MAX_WID - 2) : (SCREEN_WID - 2)));
6737
6738 /* Must be a "naked" floor grid */
6739 if (!cave_naked_bold(zcave, y, x)) continue;
6740
6741 /* Refuse to start on anti-teleport grids */
6742 if (zcave[y][x].info & CAVE_ICKY) continue;
6743 break;
6744 }
6745 #endif
6746
6747 panel_calculate(Ind);
6748
6749 /* Hack -- remove tracked monster */
6750 health_track(Ind, 0);
6751
6752 p_ptr->redraw |= (PR_MAP);
6753 p_ptr->redraw |= (PR_DEPTH);
6754
6755 forget_view(Ind);
6756 forget_lite(Ind);
6757 /* original order: update_view first, then update_lite. - C. Blue
6758 Problem: can't see some grids when entering destroyed levels.
6759 Fix: update lite before view.
6760 New problem: Had panic save, thought maybe since lite depends on correctly
6761 initialized view, but otoh view also seems to depend on lite oO.
6762 Turned out that wasn't the panic save (fixed now).
6763 Still new problem: Now after changing wpos, lite would be a square
6764 instead of circle, until moving.
6765 Fix: Add another update_view in the beginning -_-. */
6766 update_view(Ind);
6767 update_lite(Ind);
6768 update_view(Ind);
6769 update_monsters(TRUE);
6770 update_players();
6771
6772 /* Tell him that he should beware */
6773 if (wpos->wz == 0 && !istown(wpos)) {
6774 if (wild_info[wpos->wy][wpos->wx].own) {
6775 cptr p = lookup_player_name(wild_info[wpos->wy][wpos->wx].own);
6776 if (p == NULL) p = "Someone";
6777
6778 msg_format(Ind, "You enter the land of %s.", p);
6779 }
6780 }
6781
6782 /* Clear the flag */
6783 p_ptr->new_level_flag = FALSE;
6784
6785 /* Is arriving in a fixed IDDC-town noteworthy maybe? */
6786 if (is_fixed_irondeepdive_town(&p_ptr->wpos, dlv)) {
6787 if (dlv == 40) {
6788 msg_broadcast_format(0, "\374\377s%s has reached Menegroth.", p_ptr->name);
6789 l_printf("%s \\{s%s reached Menegroth\n", showdate(), p_ptr->name);
6790 } else if (dlv == 80) {
6791 msg_broadcast_format(0, "\374\377s%s has reached Nargothrond.", p_ptr->name);
6792 l_printf("%s \\{s%s reached Nargothrond\n", showdate(), p_ptr->name);
6793 }
6794 }
6795
6796 /* Did we enter/leave a no-run level? Temporarily disable/reenable warning_run */
6797 if ((l_ptr && (l_ptr->flags2 & LF2_NO_RUN)) || (in_sector00(&p_ptr->wpos) && (sector00flags2 & LF2_NO_RUN))) {
6798 if (p_ptr->warning_run < 3) p_ptr->warning_run += 10;
6799 } else if (p_ptr->warning_run >= 10) p_ptr->warning_run -= 10;
6800
6801 /* warning messages, mostly for newbies */
6802 if (p_ptr->ghost) ; /* don't warn ghosts */
6803 else if (p_ptr->warning_bpr2 != 1 && p_ptr->num_blow == 1 &&
6804 /* and don't spam Martial Arts users or mage-staff wielders ;) */
6805 p_ptr->inventory[INVEN_WIELD].k_idx && is_weapon(p_ptr->inventory[INVEN_WIELD].tval)) {
6806 p_ptr->warning_bpr2 = p_ptr->warning_bpr3 = 1;
6807 msg_print(Ind, "\374\377yWARNING! You can currently perform only ONE 'blow per round' (attack).");
6808 msg_print(Ind, "\374\377y If you rely on close combat, you should get at least 2 BpR!");
6809 msg_print(Ind, "\374\377y Possible reasons: Weapon is too heavy or your strength is too low.");
6810 if (p_ptr->inventory[INVEN_ARM].tval == TV_SHIELD) {
6811 if (p_ptr->rogue_like_commands)
6812 msg_print(Ind, "\374\377y Try taking off your shield (\377oSHIFT+t\377y) and see if that helps.");
6813 else
6814 msg_print(Ind, "\374\377y Try taking off your shield ('\377ot\377y' key) and see if that helps.");
6815 }
6816 switch (p_ptr->pclass) {
6817 case CLASS_WARRIOR:
6818 msg_print(Ind, "\374\377y Warriors should try either a dagger, whip, spear or cleaver.");
6819 break;
6820 case CLASS_PALADIN:
6821 msg_print(Ind, "\374\377y Paladins should try either a dagger, whip, spear or cleaver.");
6822 break;
6823 case CLASS_MIMIC:
6824 msg_print(Ind, "\374\377y Mimics should try either a dagger, whip, spear or cleaver.");
6825 break;
6826 case CLASS_ROGUE:
6827 msg_print(Ind, "\374\377y Rogues should try dual-wielding two daggers or main gauches.");
6828 break;
6829 case CLASS_RANGER:
6830 msg_print(Ind, "\374\377y Rangers should try dual-wielding two daggers or sword & dagger.");
6831 break;
6832 }
6833 s_printf("warning_bpr23: %s\n", p_ptr->name);
6834 } else if (p_ptr->warning_wield == 0 &&
6835 p_ptr->num_blow == 1 && !p_ptr->inventory[INVEN_WIELD].k_idx) {
6836 p_ptr->warning_wield = 1;
6837 msg_print(Ind, "\374\377yWARNING: You don't wield a weapon at the moment!");
6838 msg_print(Ind, "\374\377y Press '\377Rw\377y' key. It lets you pick a weapon (as well as other items)");
6839 msg_print(Ind, "\374\377y from your inventory to wield!");
6840 msg_print(Ind, "\374\377y (If you plan to train 'Martial Arts' skill, ignore this warning.)");
6841 s_printf("warning_wield: %s\n", p_ptr->name);
6842 }
6843 #if 1
6844 else if (p_ptr->warning_run < 3) {
6845 p_ptr->warning_run++;
6846 msg_print(Ind, "\374\377yHINT: To run fast, use \377oSHIFT+direction\377y keys.");
6847 msg_print(Ind, "\374\377y For that, \377oNUMLOCK\377y key must be OFF and no awake monster in sight!");
6848 s_printf("warning_run: %s\n", p_ptr->name);
6849 }
6850 #endif
6851 if (p_ptr->warning_lite == 0 && p_ptr->cur_lite == 0 &&
6852 (p_ptr->wpos.wz < 0 || (p_ptr->wpos.wz == 0 && night_surface))) { //Training Tower currently exempt
6853 if (p_ptr->wpos.wz < 0) p_ptr->warning_lite = 1;
6854 msg_print(Ind, "\374\377yHINT: You don't wield any light source at the moment!");
6855 msg_print(Ind, "\374\377y Press '\377ow\377y' to wield a torch or lantern (or other items).");
6856 s_printf("warning_lite: %s\n", p_ptr->name);
6857 }
6858
6859 if (!p_ptr->warning_worldmap && p_ptr->wpos.wz == 0 &&
6860 !in_sector00(&p_ptr->wpos) &&
6861 (ABS(p_ptr->wpos.wx - 32) >= 2 || ABS(p_ptr->wpos.wy - 32) >= 2)) {
6862 msg_print(Ind, "\374\377yHINT: You can press '\377oM\377y' to browse a worldmap.");
6863 msg_print(Ind, "\374\377y Towns, for example Bree, are denoted as yellow 'T'.");
6864 s_printf("warning_worldmap: %s\n", p_ptr->name);
6865 p_ptr->warning_worldmap = 1;
6866 }
6867
6868 if (!p_ptr->warning_dungeon && p_ptr->wpos.wz == 0 &&
6869 !in_sector00(&p_ptr->wpos) &&
6870 (ABS(p_ptr->wpos.wx - 32) >= 3 || ABS(p_ptr->wpos.wy - 32) >= 3)) {
6871 msg_print(Ind, "\374\377yHINT: Consider going to the Training Tower first, to gain some levels.");
6872 msg_print(Ind, "\374\377y After that, seek out a dungeon. The tower is located in Bree.");
6873 s_printf("warning_dungeon: %s\n", p_ptr->name);
6874 p_ptr->warning_dungeon = 1;
6875 }
6876
6877 /* Hack -- jail her/him */
6878 if (!p_ptr->wpos.wz && p_ptr->tim_susp
6879 #ifdef JAIL_TOWN_AREA
6880 && istownarea(&p_ptr->wpos, MAX_TOWNAREA)
6881 #endif
6882 )
6883 imprison(Ind, 0, "old crimes");
6884
6885 /* daylight problems for vampires */
6886 if (!p_ptr->wpos.wz && p_ptr->prace == RACE_VAMPIRE) calc_boni(Ind);
6887
6888 /* moved here, since it simplifies the wpos-changing process and
6889 should keep it highly consistent and linear.
6890 Note: Basically every case that sets p_ptr->new_level_flag = TRUE
6891 can and should be stripped of immediate check_Morgoth() call and
6892 instead rely on its occurance here. Also, there should actually be
6893 no existing case of check_Morgoth() that went without setting said flag,
6894 with the only exception of server join/leave in nserver.c and Morgoth
6895 live spawn (ie not on level generation time) in monster2.c. - C. Blue */
6896 check_Morgoth(Ind);
6897 if (p_ptr->new_level_flag) return;
6898
6899 #ifdef CLIENT_SIDE_WEATHER
6900 /* update his client-side weather */
6901 player_weather(Ind, TRUE, TRUE, TRUE);
6902 #endif
6903
6904 /* Brightly lit Arena Monster Challenge */
6905 if (ge_special_sector && p_ptr->wpos.wx == WPOS_ARENA_X &&
6906 p_ptr->wpos.wy == WPOS_ARENA_Y && p_ptr->wpos.wz == WPOS_ARENA_Z) {
6907 wiz_lite(Ind);
6908 /* Also tell him about this place */
6909 for (j = 0; j < MAX_GLOBAL_EVENTS; j++) {
6910 if (global_event[j].getype != GE_ARENA_MONSTER) continue;
6911 msg_print(Ind, "\377uYou enter the Arena Monster Challenge!");
6912 msg_format(Ind, "\377uType '\377U/evinfo %d\377u' to learn more or '\377U/evsign %d\377u' to challenge.", j + 1, j + 1);
6913 break;
6914 }
6915 }
6916
6917 if (p_ptr->wpos.wx == WPOS_PVPARENA_X && p_ptr->wpos.wy == WPOS_PVPARENA_Y && p_ptr->wpos.wz == WPOS_PVPARENA_Z) {
6918 /* teleport after entering [the PvP arena],
6919 so stairs won't be camped */
6920 teleport_player(Ind, 200, TRUE);
6921 /* Brightly lit PvP Arena */
6922 wiz_lite(Ind);
6923 }
6924
6925 /* PvP-Mode specialties: */
6926 if ((p_ptr->mode & MODE_PVP) && p_ptr->wpos.wz &&
6927 !(p_ptr->wpos.wx == WPOS_PVPARENA_X && p_ptr->wpos.wy == WPOS_PVPARENA_Y && p_ptr->wpos.wz == WPOS_PVPARENA_Z)) { /* <- not in the pvp arena actually */
6928 /* anti-chicken: Don't allow a high player to 'chase' a very low player */
6929 for (j = 1; j <= NumPlayers; j++) {
6930 if (Players[j]->conn == NOT_CONNECTED) continue;
6931 if (is_admin(Players[j])) continue;
6932 if (!(Players[j]->mode & MODE_PVP)) continue;
6933 if (!inarea(&Players[j]->wpos, &p_ptr->wpos)) continue;
6934 if (Players[j]->max_plv < p_ptr->max_plv - 5) {
6935 p_ptr->new_level_method = (p_ptr->wpos.wz > 0 ? LEVEL_RECALL_DOWN : LEVEL_RECALL_UP);
6936 p_ptr->recall_pos.wz = 0;
6937 p_ptr->recall_pos.wx = p_ptr->wpos.wx;
6938 p_ptr->recall_pos.wy = p_ptr->wpos.wy;
6939 // set_recall_timer(Ind, 1);
6940 p_ptr->word_recall = 1;
6941 msg_print(Ind, "\377yYou have sudden visions of a bawking chicken while being recalled!");
6942 }
6943 }
6944 }
6945
6946 /* Hack: Allow players to pass trees always, while in town */
6947 if (istown(&p_ptr->wpos) || isdungeontown(&p_ptr->wpos)) p_ptr->town_pass_trees = TRUE;
6948 else p_ptr->town_pass_trees = FALSE;
6949
6950 #if 0 /* since digging is pretty awesome now, this is too much, and we should be glad that treasure detection items have some use now actually! */
6951 /* High digging results in auto-treasure detection */
6952 if (get_skill(p_ptr, SKILL_DIG) >= 30) floor_detect_treasure(Ind);
6953 #endif
6954
6955 /* If he found a town in the dungeon, map it as much as a normal town would be at night */
6956 if (l_ptr && (l_ptr->flags1 & LF1_DUNGEON_TOWN)) player_dungeontown(Ind);
6957
6958 /* Did we enter a no-tele vault? */
6959 if (zcave[p_ptr->py][p_ptr->px].info & CAVE_STCK) {
6960 msg_print(Ind, "\377DThe air in here feels very still.");
6961 p_ptr->redraw |= PR_DEPTH; /* hack: depth colour indicates no-tele */
6962 /* New: Have bgm indicate no-tele too! (done below in handle_music()) */
6963 }
6964
6965 quest_check_player_location(Ind);
6966
6967 #ifdef USE_SOUND_2010
6968 /* clear boss/floor-specific music */
6969 p_ptr->music_monster = -1;
6970 handle_music(Ind);
6971 handle_ambient_sfx(Ind, &(getcave(&p_ptr->wpos)[p_ptr->py][p_ptr->px]), &p_ptr->wpos, smooth_ambient);
6972 #endif
6973
6974 #ifdef ENABLE_SELF_FLASHING
6975 /* if not travelling through wilderness smoothly,
6976 flicker player for a moment, to allow for easy location */
6977 if (!smooth_ambient && p_ptr->flash_self >= 0) p_ptr->flash_self = cfg.fps / FLASH_SELF_DIV2; //todo: make client option
6978 #endif
6979
6980 clockin(Ind, 7); /* Remember his wpos */
6981 }
6982
6983
6984 /*
6985 * Main loop --KLJ--
6986 *
6987 * This is main loop; it is called every 1/FPS seconds. Usually FPS is about
6988 * 10, so that a normal unhasted unburdened character gets 1 player turn per
6989 * second. Note that we process every player and the monsters, then quit.
6990 * The "scheduling" code (see sched.c) is the REAL main loop, which handles
6991 * various inputs and timings.
6992 */
6993
6994 void dungeon(void) {
6995 int i;
6996 player_type *p_ptr;
6997
6998 /* Return if no one is playing */
6999 /* if (!NumPlayers) return; */
7000
7001 /* Check for death. Go backwards (very important!) */
7002 for (i = NumPlayers; i > 0; i--) {
7003 /* Check connection first */
7004 if (Players[i]->conn == NOT_CONNECTED)
7005 continue;
7006
7007 /* Check for death */
7008 if (Players[i]->death)
7009 player_death(i);
7010 }
7011
7012 /* Check player's depth info */
7013 for (i = 1; i < NumPlayers + 1; i++) {
7014 p_ptr = Players[i];
7015 if (p_ptr->conn == NOT_CONNECTED || !p_ptr->new_level_flag)
7016 continue;
7017 if (p_ptr->iron_winner_ded && p_ptr->wpos.wz != 0) {
7018 p_ptr->new_level_flag = FALSE;
7019 do_cmd_suicide(i);
7020 continue;
7021 }
7022 process_player_change_wpos(i);
7023 }
7024
7025 /* New meta client implementation */
7026 meta_tick();
7027
7028 /* Handle any network stuff */
7029 Net_input();
7030 #if 0
7031 /* Hack -- Compact the object list occasionally */
7032 if (o_top + 16 > MAX_O_IDX) compact_objects(32, FALSE);
7033
7034 /* Hack -- Compact the monster list occasionally */
7035 if (m_top + 32 > MAX_M_IDX) compact_monsters(64, FALSE);
7036
7037 /* Hack -- Compact the trap list occasionally */
7038 if (t_top + 16 > MAX_TR_IDX) compact_traps(32, FALSE);
7039 #endif
7040
7041
7042
7043 /* Note -- this is the END of the last turn */
7044
7045 /* Do final end of turn processing for each player */
7046 for (i = 1; i <= NumPlayers; i++) {
7047 if (Players[i]->conn == NOT_CONNECTED)
7048 continue;
7049
7050 /* Actually process that player */
7051 process_player_end(i);
7052 }
7053
7054 /* paranoia - It's done twice */
7055 /* Check for death. Go backwards (very important!) */
7056 for (i = NumPlayers; i > 0; i--) {
7057 /* Check connection first */
7058 if (Players[i]->conn == NOT_CONNECTED)
7059 continue;
7060
7061 /* Check for death */
7062 if (Players[i]->death)
7063 player_death(i);
7064 }
7065
7066
7067
7068 ///*** BEGIN NEW TURN ***///
7069 turn++;
7070
7071 /* Check for overflow - mikaelh */
7072 #if 0 /* avoid doing this last-minute, since some calcs will already be off */
7073 if (turn < 0)
7074 #else /* give at least ~30 minutes buffer (eg login process requires that approx.) */
7075 if (turn == turn_overflow) /* note: turn is s32b */
7076 #endif
7077 {
7078 /* Reset the turn counter */
7079 /* This will cause some weird things */
7080 /* Players will probably timeout */
7081 turn = 1;
7082
7083 /* Log it */
7084 s_printf("%s: TURN COUNTER RESET (%d)\n", showtime(), turn_overflow);
7085
7086 /* Reset empty party creation times */
7087 for (i = 1; i < MAX_PARTIES; i++) {
7088 if (parties[i].members == 0) parties[i].created = 0;
7089 }
7090 }
7091
7092 /* Do some queued drawing */
7093 process_lite_later();
7094
7095
7096 /* Process quest (de)activation every minute */
7097 if (!(turn % (cfg.fps * 60))) process_quests();
7098
7099 /* process some things once each second.
7100 NOTE: Some of these (global events) mustn't
7101 be handled _after_ a player got set to 'dead',
7102 or gameplay might in very rare occasions get
7103 screwed up (someone dying when he shouldn't) - C. Blue */
7104 if (!(turn % cfg.fps)) {
7105 /* Process global_events */
7106 process_global_events();
7107
7108 /* process special event timers */
7109 process_timers();
7110
7111 /* Call a specific lua function every second */
7112 exec_lua(0, "second_handler()");
7113
7114 /* Process weather effects */
7115 #ifdef CLIENT_SIDE_WEATHER
7116 #ifndef CLIENT_WEATHER_GLOBAL
7117 process_wild_weather();
7118 #else
7119 process_weather_control();
7120 #endif
7121 #else
7122 process_weather_control();
7123 #endif
7124
7125 #ifdef AUCTION_SYSTEM
7126 /* Process auctions */
7127 process_auctions();
7128 #endif
7129
7130 #ifdef USE_SOUND_2010
7131 process_ambient_sfx();
7132 #endif
7133
7134 /* process timed shutdown (/shutrec) */
7135 if (shutdown_recall_timer) shutdown_recall_timer--;
7136
7137 /* process certain player-related timers */
7138 for (i = 1; i <= NumPlayers; i++) {
7139 if (Players[i]->redraw_cooldown) Players[i]->redraw_cooldown--;
7140
7141 /* Arbitrary max number, just to prevent integer overflow.
7142 Should just be higher than the longest interval of any ambient sfx type. */
7143 if (!Players[i]->wpos.wz && /* <- redundant check sort of, caught in process_player_change_wpos() anyway */
7144 Players[i]->ambient_sfx_timer < 200)
7145 Players[i]->ambient_sfx_timer++;
7146 }
7147 }
7148
7149 /* process every 1/5th second */
7150 if (!(turn % (cfg.fps / 5))) {
7151 if (nether_realm_collapsing && !rand_int(8)) {
7152 struct worldpos wpos = {netherrealm_wpos_x, netherrealm_wpos_y, netherrealm_end_wz};
7153 int x = nrc_x, y = nrc_y - 5; /* start somewhat 'above' Zu-Aon's death spot */
7154
7155 /* stay in bounds */
7156 if (x < 20) x = rand_int(37) + 4;//don't cut them off too much
7157 else if (x >= MAX_WID - 20) x = MAX_WID - 40 + rand_int(36);//don't cut them off too much
7158 else x = x - 20 + rand_int(41);
7159 if (y < 15) y = rand_int(16);
7160 else if (y >= MAX_HGT - 15) y = MAX_HGT - 30 + rand_int(23);//don't cut them off at the bottom border too much
7161 else y = y - 15 + rand_int(31);
7162
7163 //cast_lightning(&wpos, rand_int(MAX_WID - 20) + 10, rand_int(MAX_HGT - 15) + 5);
7164 cast_lightning(&wpos, x, y);
7165 }
7166 }
7167
7168 #ifndef CLIENT_SIDE_WEATHER
7169 /* Process server-side weather */
7170 process_weather_effect_creation();
7171 #endif
7172
7173 /* Process server-side visual special fx */
7174 if (season_newyearseve && fireworks && !(turn % (cfg.fps / 4)))
7175 process_firework_creation();
7176
7177
7178
7179 /* Do some beginning of turn processing for each player */
7180 for (i = 1; i <= NumPlayers; i++) {
7181 p_ptr = Players[i];
7182 if (p_ptr->conn == NOT_CONNECTED)
7183 continue;
7184
7185 /* Print queued log messages (anti-spam feature) - C. Blue */
7186 if (p_ptr->last_gold_drop && turn - p_ptr->last_gold_drop_timer >= cfg.fps * 2) {
7187 s_printf("Gold dropped (%d by %s at %d,%d,%d) [anti-spam].\n", p_ptr->last_gold_drop, p_ptr->name, p_ptr->wpos.wx, p_ptr->wpos.wy, p_ptr->wpos.wz);
7188 p_ptr->last_gold_drop = 0;
7189 p_ptr->last_gold_drop_timer = turn;
7190 }
7191
7192 #if 0
7193 /* experimental water animation, trying to not be obnoxious -
7194 strategy: pick a random grid, if it's water, redraw it */
7195 cave_type **zcave = getcave(&p_ptr->wpos);
7196 if (zcave) {
7197 int x = rand_int(p_ptr->panel_col_max - p_ptr->panel_col_min) + p_ptr->panel_col_min;
7198 int y = rand_int(p_ptr->panel_row_max - p_ptr->panel_row_min) + p_ptr->panel_row_min;
7199 lite_spot(i, y, x);
7200 #if 0
7201 struct dun_level *l_ptr = getfloor(&p_ptr->wpos);
7202 /* outside? */
7203 if (!l_ptr) {
7204 int x = rand_int(MAX_WID), y = rand_int(MAX_HGT);
7205 if (zcave[y][x].feat == FEAT_DEEP_WATER ||
7206 zcave[y][x].feat == FEAT_SHAL_WATER)
7207 lite_spot(i, y, x);
7208 /* inside? */
7209 } else {
7210 int x = rand_int(l_ptr->wid), y = rand_int(l_ptr->hgt);
7211 if (zcave[y][x].feat == FEAT_DEEP_WATER ||
7212 zcave[y][x].feat == FEAT_SHAL_WATER)
7213 lite_spot(i, y, x);
7214 }
7215 #endif
7216 }
7217 #endif
7218
7219 #ifdef ENABLE_SELF_FLASHING
7220 /* Check for hilite */
7221 if (p_ptr->flash_self > 0 && !(turn % (cfg.fps / 15))) {
7222 p_ptr->flash_self--;
7223 everyone_lite_spot(&p_ptr->wpos, p_ptr->py, p_ptr->px);
7224 } else
7225 #endif
7226 if (!(turn % (cfg.fps / 6))) {
7227 /* Play server-side animations (consisting of cycling/random colour choices,
7228 instead of animated colours which are circled client-side) */
7229 /* Flicker invisible player? (includes colour animation!) */
7230 // if (p_ptr->invis) update_player(i);
7231 if (p_ptr->invis) {
7232 update_player_flicker(i);
7233 update_player(i);
7234 }
7235 /* Otherwise only take care of colour animation */
7236 // else { /* && p_ptr->body_monster */
7237 everyone_lite_spot(&p_ptr->wpos, p_ptr->py, p_ptr->px);
7238 // }
7239 }
7240
7241 /* Do non-self-related animations and checks too */
7242 if (!(turn % (cfg.fps / 6))) {
7243 #ifdef TELEPORT_SURPRISES
7244 /* Teleport-surprise-effect against monsters */
7245 if (p_ptr->teleported) p_ptr->teleported--;
7246 #endif
7247 }
7248
7249 /* Perform beeping players who are currently being paged by others */
7250 if (p_ptr->paging && !(turn % (cfg.fps / 4))) {
7251 Send_beep(i);
7252 p_ptr->paging--;
7253 }
7254
7255 /* Actually process that player */
7256 process_player_begin(i);
7257 }
7258
7259 /* Process spell effects */
7260 process_effects();
7261
7262 /* Process projections' teleportation effects on monsters */
7263 for (i = 0; i < m_top; i++)
7264 if (m_list[m_fast[i]].do_dist) {
7265 teleport_away(m_fast[i], m_list[m_fast[i]].do_dist);
7266 m_list[m_fast[i]].do_dist = FALSE;
7267 }
7268
7269 #ifdef FLUENT_ARTIFACT_RESETS
7270 /* handle in 1-minute resolution - assume we have less artifacts than 60*cfg.fps */
7271 i = turn % (cfg.fps * 60);
7272 if (!cfg.persistent_artifacts && i < max_a_idx && a_info[i].timeout > 0) {
7273 #ifdef IDDC_ARTIFACT_FAST_TIMEOUT
7274 if (a_info[i].iddc) {
7275 a_info[i].timeout -= 2;
7276 if (a_info[i].timeout == -1) a_info[i].timeout = 0;
7277 } else
7278 #endif
7279 #ifdef WINNER_ARTIFACT_FAST_TIMEOUT
7280 if (a_info[i].winner) {
7281 a_info[i].timeout -= 2;
7282 if (a_info[i].timeout == -1) a_info[i].timeout = 0;
7283 } else
7284 #endif
7285 a_info[i].timeout--;
7286
7287 if (a_info[i].timeout == 0) erase_artifact(i);
7288 else if (a_info[i].timeout == FLUENT_ARTIFACT_WARNING) {
7289 int j, k;
7290 char o_name[ONAME_LEN];
7291 for (j = 1; j <= NumPlayers; j++) {
7292 p_ptr = Players[j];
7293 if (p_ptr->id != a_info[i].carrier) continue;
7294 if (p_ptr->conn == NOT_CONNECTED) continue;
7295 for (k = 0; k < INVEN_TOTAL; k++) {
7296 if (!p_ptr->inventory[k].k_idx) continue;
7297 if (p_ptr->inventory[k].name1 != i) continue;
7298 if (!(p_ptr->inventory[k].ident & ID_MENTAL)) continue;
7299 object_desc(j, o_name, &p_ptr->inventory[k], TRUE, 128);
7300 msg_format(j, "\374\377RYour %s will vanish soon!", o_name);
7301 j = NumPlayers;
7302 break;
7303 }
7304 }
7305 }
7306 }
7307 #endif
7308
7309 /* Process all of the monsters */
7310 if (!(turn % MONSTER_TURNS))
7311 process_monsters();
7312
7313 /* Process programmable NPCs */
7314 if (!(turn % NPC_TURNS))
7315 process_npcs();
7316
7317 /* Process all of the objects */
7318 if ((turn % 10) == 5) process_objects();
7319
7320 /* Process the world */
7321 if (!(turn % 50)) {
7322 if (cfg.runlevel < 6 && time(NULL) - cfg.closetime > 120)
7323 set_runlevel(cfg.runlevel - 1);
7324
7325 if (cfg.runlevel < 5) {
7326 for (i = NumPlayers; i > 0 ;i--) {
7327 if (Players[i]->conn == NOT_CONNECTED) continue;
7328 if (Players[i]->wpos.wz != 0) break;
7329 }
7330 if (!i) set_runlevel(0);
7331 }
7332
7333 if (cfg.runlevel == 2049) {
7334 shutdown_server();
7335 } else if (cfg.runlevel == 2052) {
7336 /* same as /shutdown 0, except server will return -2 instead of -1.
7337 can be used by scripts to initiate maintenance downtime etc. */
7338 set_runlevel(-1);
7339
7340 /* paranoia - set_runlevel() will call exit() */
7341 time(&cfg.closetime);
7342 return;
7343 } else if (cfg.runlevel == 2051) {
7344 int n = 0;
7345 for (i = NumPlayers; i > 0 ;i--) {
7346 p_ptr = Players[i];
7347 if (p_ptr->conn == NOT_CONNECTED) continue;
7348 /* Ignore admins that are loged in */
7349 if (admin_p(i)) continue;
7350 /* count players */
7351 n++;
7352
7353 /* Ignore characters that are afk and not in a dungeon/tower */
7354 // if((p_ptr->wpos.wz == 0) && (p_ptr->afk)) continue;
7355
7356 /* Ignore chars in fixed irondeepdive towns */
7357 if (is_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) continue;
7358 #ifdef IRONDEEPDIVE_EXTRA_FIXED_TOWNS
7359 if (is_extra_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) continue;
7360 #endif
7361
7362 /* extra, just for /shutempty: Ignore all iddc chars who are afk/idle */
7363 if (SHUTDOWN_IGNORE_IDDC(p_ptr)) continue;
7364
7365 /* Ignore characters that are not in a dungeon/tower */
7366 if (p_ptr->wpos.wz == 0) {
7367 /* Don't interrupt events though */
7368 if (p_ptr->wpos.wx != WPOS_SECTOR00_X || p_ptr->wpos.wy != WPOS_SECTOR00_Y || !sector00separation) continue;
7369 }
7370 break;
7371 }
7372 if (!i && (n <= 3)) {
7373 msg_broadcast(-1, "\374\377G<<<\377oServer is being updated, but will be up again in no time.\377G>>>");
7374 cfg.runlevel = 2049;
7375 }
7376 }
7377 #ifdef ENABLE_GO_GAME
7378 else if (cfg.runlevel == 2048 && !go_game_up) {
7379 #else
7380 else if (cfg.runlevel == 2048) {
7381 #endif
7382 for (i = NumPlayers; i > 0 ;i--) {
7383 p_ptr = Players[i];
7384 if (p_ptr->conn == NOT_CONNECTED) continue;
7385
7386 /* Ignore admins that are loged in */
7387 if (admin_p(i)) continue;
7388
7389 /* Ignore chars in fixed irondeepdive towns */
7390 if (is_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) continue;
7391 #ifdef IRONDEEPDIVE_EXTRA_FIXED_TOWNS
7392 if (is_extra_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) continue;
7393 #endif
7394
7395 /* extra, just for /shutempty: Ignore all iddc chars who are afk/idle */
7396 if (SHUTDOWN_IGNORE_IDDC(p_ptr)) continue;
7397
7398 /* Ignore characters that are afk and not in a dungeon/tower */
7399 // if((p_ptr->wpos.wz == 0) && (p_ptr->afk)) continue;
7400
7401 /* Ignore characters that are not in a dungeon/tower */
7402 if (p_ptr->wpos.wz == 0) {
7403 /* Don't interrupt events though */
7404 if (p_ptr->wpos.wx != WPOS_SECTOR00_X || p_ptr->wpos.wy != WPOS_SECTOR00_Y || !sector00separation) continue;
7405 }
7406 break;
7407 }
7408 if (!i) {
7409 msg_broadcast(-1, "\374\377G<<<\377oServer is being updated, but will be up again in no time.\377G>>>");
7410 cfg.runlevel = 2049;
7411 }
7412 } else if (cfg.runlevel == 2047) {
7413 int n = 0;
7414 for (i = NumPlayers; i > 0 ;i--) {
7415 p_ptr = Players[i];
7416 if (p_ptr->conn == NOT_CONNECTED) continue;
7417 /* Ignore admins that are loged in */
7418 if (admin_p(i)) continue;
7419 /* count players */
7420 n++;
7421
7422 /* Ignore characters that are afk and not in a dungeon/tower */
7423 // if((p_ptr->wpos.wz == 0) && (p_ptr->afk)) continue;
7424
7425 /* Ignore chars in fixed irondeepdive towns */
7426 if (is_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) continue;
7427 #ifdef IRONDEEPDIVE_EXTRA_FIXED_TOWNS
7428 if (is_extra_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) continue;
7429 #endif
7430
7431 /* extra, just for /shutempty: Ignore all iddc chars who are afk/idle */
7432 if (SHUTDOWN_IGNORE_IDDC(p_ptr)) continue;
7433
7434 /* Ignore characters that are not in a dungeon/tower */
7435 if (p_ptr->wpos.wz == 0) {
7436 /* Don't interrupt events though */
7437 if (p_ptr->wpos.wx != WPOS_SECTOR00_X || p_ptr->wpos.wy != WPOS_SECTOR00_Y || !sector00separation) continue;
7438 }
7439 break;
7440 }
7441 if (!i && (n <= 8)) {
7442 msg_broadcast(-1, "\374\377G<<<\377oServer is being updated, but will be up again in no time.\377G>>>");
7443 cfg.runlevel = 2049;
7444 }
7445 } else if (cfg.runlevel == 2046) {
7446 int n = 0;
7447 for (i = NumPlayers; i > 0 ;i--) {
7448 p_ptr = Players[i];
7449 if (p_ptr->conn == NOT_CONNECTED) continue;
7450 /* Ignore admins that are loged in */
7451 if (admin_p(i)) continue;
7452 /* count players */
7453 n++;
7454
7455 /* Ignore characters that are afk and not in a dungeon/tower */
7456 // if((p_ptr->wpos.wz == 0) && (p_ptr->afk)) continue;
7457
7458 /* Ignore chars in fixed irondeepdive towns */
7459 if (is_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) continue;
7460 #ifdef IRONDEEPDIVE_EXTRA_FIXED_TOWNS
7461 if (is_extra_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) continue;
7462 #endif
7463
7464 /* extra, just for /shutempty: Ignore all iddc chars who are afk/idle */
7465 if (SHUTDOWN_IGNORE_IDDC(p_ptr)) continue;
7466
7467 /* Ignore characters that are not in a dungeon/tower */
7468 if (p_ptr->wpos.wz == 0) {
7469 /* Don't interrupt events though */
7470 if (p_ptr->wpos.wx != WPOS_SECTOR00_X || p_ptr->wpos.wy != WPOS_SECTOR00_Y || !sector00separation) continue;
7471 }
7472 break;
7473 }
7474 if (!i && (n <= 5)) {
7475 msg_broadcast(-1, "\374\377G<<<\377oServer is being updated, but will be up again in no time.\377G>>>");
7476 cfg.runlevel = 2049;
7477 }
7478 } else if (cfg.runlevel == 2045) {
7479 int n = 0;
7480 for (i = NumPlayers; i > 0 ;i--) {
7481 if (Players[i]->conn == NOT_CONNECTED) continue;
7482 /* Ignore admins that are loged in */
7483 if (admin_p(i)) continue;
7484 /* count players */
7485 n++;
7486 }
7487 if (!n) {
7488 msg_broadcast(-1, "\374\377G<<<\377oServer is being updated, but will be up again in no time.\377G>>>");
7489 cfg.runlevel = 2049;
7490 }
7491 } else if (cfg.runlevel == 2044) {
7492 int n = 0;
7493 for (i = NumPlayers; i > 0 ;i--) {
7494 p_ptr = Players[i];
7495 if (p_ptr->conn == NOT_CONNECTED) continue;
7496
7497 /* Ignore admins that are loged in */
7498 if (admin_p(i)) continue;
7499
7500 /* Ignore perma-afk players! */
7501 //if (p_ptr->afk &&
7502 if (is_inactive(i) >= 30 * 20) /* 20 minutes idle? */
7503 continue;
7504
7505 /* count players */
7506 n++;
7507
7508 /* Ignore characters that are afk and not in a dungeon/tower */
7509 // if((p_ptr->wpos.wz == 0) && (p_ptr->afk)) continue;
7510
7511 /* Ignore chars in fixed irondeepdive towns */
7512 if (is_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) continue;
7513 #ifdef IRONDEEPDIVE_EXTRA_FIXED_TOWNS
7514 if (is_extra_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) continue;
7515 #endif
7516
7517 /* Ignore characters that are not in a dungeon/tower */
7518 if (p_ptr->wpos.wz == 0) {
7519 /* Don't interrupt events though */
7520 if (p_ptr->wpos.wx != WPOS_SECTOR00_X || p_ptr->wpos.wy != WPOS_SECTOR00_Y || !sector00separation) continue;
7521 }
7522 break;
7523 }
7524 if (!i && (n <= 6)) {
7525 msg_broadcast(-1, "\374\377G<<<\377oServer is being updated, but will be up again in no time.\377G>>>");
7526 cfg.runlevel = 2049;
7527 }
7528 }
7529
7530 if (cfg.runlevel == 2043 || cfg.runlevel == 2042) {
7531 if (shutdown_recall_timer <= 60 && shutdown_recall_state < 3) {
7532 msg_broadcast(0, "\374\377I*** \377RServer shutdown in max 1 minute (auto-recall). \377I***");
7533 shutdown_recall_state = 3;
7534 }
7535 else if (shutdown_recall_timer <= 300 && shutdown_recall_state < 2) {
7536 msg_broadcast(0, "\374\377I*** \377RServer shutdown in max 5 minutes (auto-recall). \377I***");
7537 shutdown_recall_state = 2;
7538 }
7539 else if (shutdown_recall_timer <= 900 && shutdown_recall_state < 1) {
7540 msg_broadcast(0, "\374\377I*** \377RServer shutdown in max 15 minutes (auto-recall). \377I***");
7541 shutdown_recall_state = 1;
7542 }
7543 if (!shutdown_recall_timer) {
7544 for (i = NumPlayers; i > 0 ;i--) {
7545 p_ptr = Players[i];
7546 if (p_ptr->conn == NOT_CONNECTED) continue;
7547
7548 /* Don't remove loot from ghosts waiting for res */
7549 if (admin_p(i) || p_ptr->ghost) continue;
7550
7551 /* Don't free people from the Ironman Deep Dive Challenge */
7552 if (in_irondeepdive(&p_ptr->wpos)) continue;
7553
7554 if (p_ptr->wpos.wz) {
7555 p_ptr->recall_pos.wx = p_ptr->wpos.wx;
7556 p_ptr->recall_pos.wy = p_ptr->wpos.wy;
7557 p_ptr->recall_pos.wz = 0;
7558 p_ptr->new_level_method = (p_ptr->wpos.wz > 0 ? LEVEL_RECALL_DOWN : LEVEL_RECALL_UP);
7559 recall_player(i, "");
7560 }
7561 }
7562 if (cfg.runlevel == 2043) {
7563 msg_broadcast(-1, "\374\377G<<<\377oServer is being updated, but will be up again in no time.\377G>>>");
7564 cfg.runlevel = 2049;
7565 } else { //if (cfg.runlevel == 2042) {
7566 msg_broadcast(-1, "\374\377G<<<\377oServer is now going down for maintenance.\377G>>>");
7567 cfg.runlevel = 2052;
7568 }
7569 } else {
7570 for (i = NumPlayers; i > 0 ;i--) {
7571 p_ptr = Players[i];
7572 if (p_ptr->conn == NOT_CONNECTED) continue;
7573
7574 /* Ignore admins that are loged in */
7575 if (admin_p(i)) continue;
7576
7577 /* Ignore chars in fixed irondeepdive towns */
7578 if (is_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) continue;
7579 #ifdef IRONDEEPDIVE_EXTRA_FIXED_TOWNS
7580 if (is_extra_fixed_irondeepdive_town(&p_ptr->wpos, getlevel(&p_ptr->wpos))) continue;
7581 #endif
7582
7583 /* Ignore characters that are afk and not in a dungeon/tower */
7584 // if((p_ptr->wpos.wz == 0) && (p_ptr->afk)) continue;
7585
7586 /* Ignore characters that are not in a dungeon/tower */
7587 if(p_ptr->wpos.wz == 0) {
7588 /* Don't interrupt events though */
7589 if (p_ptr->wpos.wx != WPOS_SECTOR00_X || p_ptr->wpos.wy != WPOS_SECTOR00_Y || !sector00separation) continue;
7590 }
7591 break;
7592 }
7593 if (!i) {
7594 if (cfg.runlevel == 2043) {
7595 msg_broadcast(-1, "\374\377G<<<\377oServer is being updated, but will be up again in no time.\377G>>>");
7596 cfg.runlevel = 2049;
7597 } else { //if (cfg.runlevel == 2042)
7598 msg_broadcast(-1, "\374\377G<<<\377oServer is now going down for maintenance.\377G>>>");
7599 cfg.runlevel = 2052;
7600 }
7601 }
7602 }
7603 }
7604
7605 /* Hack -- Compact the object list occasionally */
7606 if (o_top + 160 > MAX_O_IDX) compact_objects(320, TRUE);
7607
7608 /* Hack -- Compact the monster list occasionally */
7609 if (m_top + 320 > MAX_M_IDX) compact_monsters(640, TRUE);
7610
7611 /* Hack -- Compact the trap list occasionally */
7612 // if (t_top + 160 > MAX_TR_IDX) compact_traps(320, TRUE);
7613
7614 /* Tell a day passed */
7615 // if (((turn + (DAY_START * 10L)) % (10L * DAY)) == 0)
7616 if (!(turn % DAY)) { /* midnight */
7617 char buf[20];
7618
7619 snprintf(buf, 20, "%s", get_day(bst(YEAR, turn))); /* hack: abuse get_day()'s capabilities */
7620 msg_broadcast_format(0,
7621 "\377GToday it is %s of the %s year of the third age.",
7622 get_month_name(bst(DAY, turn), FALSE, FALSE), buf);
7623
7624 #ifdef MUCHO_RUMOURS
7625 /* the_sandman prints a rumour */
7626 if (NumPlayers) {
7627 msg_print(1, "Suddenly a thought comes to your mind:");
7628 fortune(1, TRUE);
7629 }
7630 #endif
7631 }
7632
7633 for (i = 1; i < NumPlayers + 1; i++) {
7634 if (Players[i]->conn == NOT_CONNECTED)
7635 continue;
7636
7637 /* Process the world of that player */
7638 process_world(i);
7639 }
7640 }
7641
7642 /* Clean up Bree regularly to prevent too dangerous towns in which weaker characters cant move around */
7643 // if (!(turn % 650000)) { /* 650k ~ 3hours */
7644 // if (!(turn % (cfg.fps * 3600))) { /* 1 h */
7645 if (!(turn % (cfg.fps * 600))) { /* new timing after function was changed to "thin_surface_spawns()" */
7646 thin_surface_spawns();
7647 //spam s_printf("%s Surface spawns thinned.\n", showtime());
7648 }
7649
7650 /* Process everything else */
7651 if (!(turn % 10)) {
7652 process_various();
7653
7654 /* Hack -- Regenerate the monsters every hundred game turns */
7655 if (!(turn % 100)) regen_monsters();
7656
7657 /* process delayed requests */
7658 for (i = 1; i <= NumPlayers; i++) {
7659 p_ptr = Players[i];
7660 if (p_ptr->delay_str) {
7661 p_ptr->delay_str -= 10;
7662 if (p_ptr->delay_str <= 0) {
7663 p_ptr->delay_str = 0;
7664 Send_request_str(i, p_ptr->delay_str_id, p_ptr->delay_str_prompt, p_ptr->delay_str_std);
7665 }
7666 }
7667 if (p_ptr->delay_cfr) {
7668 p_ptr->delay_cfr -= 10;
7669 if (p_ptr->delay_cfr <= 0) {
7670 p_ptr->delay_cfr = 0;
7671 Send_request_cfr(i, p_ptr->delay_cfr_id, p_ptr->delay_cfr_prompt, p_ptr->delay_cfr_default_yes);
7672 }
7673 }
7674 }
7675 }
7676
7677 #ifdef DUNGEON_VISIT_BONUS
7678 /* Keep track of frequented dungeons, every minute */
7679 if (!(turn % (cfg.fps * 60))) {
7680 dungeon_type *d_ptr;
7681 wilderness_type *w_ptr;
7682 # ifdef DUNGEON_VISIT_BONUS_DEPTHRANGE
7683 int depthrange;
7684 # endif
7685
7686 for (i = 1; i < NumPlayers + 1; i++) {
7687 p_ptr = Players[i];
7688 if (p_ptr->conn == NOT_CONNECTED) continue;
7689
7690 if (p_ptr->wpos.wz == 0) continue;
7691 w_ptr = &wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx];
7692 if (p_ptr->wpos.wz < 0) d_ptr = w_ptr->dungeon;
7693 else if (p_ptr->wpos.wz > 0) d_ptr = w_ptr->tower;
7694 else continue; //paranoia
7695
7696 # if 0
7697 /* NOTE: We're currently counting up for -each- player in there.
7698 Maybe should be changed to generic 'visited or not visited'. */
7699 if (dungeon_visit_frequency[d_ptr->id] < VISIT_TIME_CAP)
7700 dungeon_visit_frequency[d_ptr->id]++;
7701 # else
7702 /* NOTE about NOTE: Not anymore. Now # of players doesn't matter: */
7703 if (dungeon_visit_frequency[d_ptr->id] < VISIT_TIME_CAP)
7704 dungeon_visit_check[d_ptr->id] = TRUE;
7705 # endif
7706
7707 # ifdef DUNGEON_VISIT_BONUS_DEPTHRANGE
7708 /* Also keep track of which depths are mostly frequented */
7709 depthrange = getlevel(&p_ptr->wpos) / 10;
7710 /* Excempt Valinor (dlv 200) */
7711 if (depthrange < 20
7712 && depthrange_visited[depthrange] < VISIT_TIME_CAP);
7713 depthrange_visited[depthrange]++;
7714 # endif
7715 }
7716
7717 # if 1
7718 for (i = 1; i <= dungeon_id_max; i++)
7719 if (dungeon_visit_check[i]) {
7720 dungeon_visit_check[i] = FALSE;
7721 dungeon_visit_frequency[i]++;
7722 }
7723 # endif
7724 }
7725 /* Decay visit frequency for all dungeons over time. */
7726 /* Also update the 'rest bonus' each dungeon gives:
7727 Use <startfloor + 2/3 * (startfloor-endfloor)> as main comparison value. */
7728 if (!(turn % (cfg.fps * 60 * 10))) {
7729 # ifdef DUNGEON_VISIT_BONUS_DEPTHRANGE
7730 for (i = 0; i < 20; i++) {
7731 if (depthrange_visited[i])
7732 depthrange_visited[i]--;
7733
7734 /* update the depth-range scale in regards to its most contributing dungeon */
7735 //todo; see below
7736 }
7737 # endif
7738 for (i = 1; i <= dungeon_id_max; i++) {
7739 if (dungeon_visit_frequency[i])
7740 dungeon_visit_frequency[i]--;
7741
7742 /* update bonus of this dungeon */
7743 # ifdef DUNGEON_VISIT_BONUS_DEPTHRANGE
7744 /* more sophisticated algoritm.
7745 Todo: find a good way how to do this :-p.
7746 Idea (C. Blue):
7747 players increase the depthrange_visited counter for the dlvl they are on,
7748 dungeons then compare it with their average depth (which is as stated above
7749 start + 2/3 * (end-start) floor), and only start counting as "not visited"
7750 if the dungeon depths that ARE visited actually are comparable to the
7751 avg depth of the dungeon in question.
7752 Main problem: Handle multiple dungeons adding to the same depthrange in
7753 pretty different scales, eg 'player A is all the time in dungeon A which
7754 only is lvl 1-9, while player B spends even much more time in the very first
7755 level of dungeon B which goes from lvl 1-49. Now how are the numbers scaled
7756 down to determine the actual 'visitedness' of dungeon A for example? */
7757 # endif
7758
7759 /* straightforward simple way without DUNGEON_VISIT_BONUS_DEPTHRANGE */
7760 set_dungeon_bonus(i, FALSE);
7761 }
7762 }
7763 #endif
7764
7765 /* Process day/night changes on world_surface */
7766 if (!(turn % HOUR)) process_day_and_night();
7767
7768 /* Refresh everybody's displays */
7769 for (i = 1; i < NumPlayers + 1; i++) {
7770 p_ptr = Players[i];
7771
7772 if (p_ptr->conn == NOT_CONNECTED)
7773 continue;
7774
7775 /* Notice stuff */
7776 if (p_ptr->notice) notice_stuff(i);
7777
7778 /* Update stuff */
7779 if (p_ptr->update) update_stuff(i);
7780
7781 /* Redraw stuff */
7782 if (p_ptr->redraw) redraw_stuff(i);
7783
7784 /* Window stuff */
7785 if (p_ptr->window) window_stuff(i);
7786 }
7787
7788 /* Animate player's @ in his own view here on server side */
7789 /* This animation is only for mana shield / GOI indication */
7790 if (!(turn % 5))
7791 for (i = 1; i < NumPlayers + 1; i++) {
7792 /* Colour animation is done in lite_spot */
7793 lite_spot(i, Players[i]->py, Players[i]->px);
7794 }
7795
7796 /* Process debugging/helper functions - C. Blue */
7797 if (store_debug_mode &&
7798 /* '/ 10 ' stands for quick motion, ie time * 10 */
7799 (!(turn % ((store_debug_mode * (10L * cfg.store_turns)) / store_debug_quickmotion))))
7800 store_debug_stock();
7801
7802 #ifdef ARCADE_SERVER
7803 /* Process special Arcade Server things */
7804 if (turn % (cfg.fps / 3) == 1) exec_lua(1, "firin()");
7805 if (turn % tron_speed == 1) exec_lua(1, "tron()");
7806 #endif
7807
7808 #ifdef ENABLE_GO_GAME
7809 /* Process Go AI engine communication (its replies) */
7810 if (go_engine_processing) go_engine_process();
7811 #endif
7812
7813 /* Send any information over the network */
7814 Net_output();
7815 }
7816
7817 void set_runlevel(int val) {
7818 //static bool meta = TRUE;
7819
7820 switch(val) {
7821 case -1:
7822 /* terminate: return a value that lets a script know that
7823 it must not restart us. */
7824 cfg.runlevel = -1;
7825 s_printf("***SERVER MAINTENANCE TERMINATION***\n");
7826 case 0:
7827 shutdown_server();
7828 case 1:
7829 /* Logout all remaining players except admins */
7830 msg_broadcast(0, "\377rServer shutdown imminent!");
7831 break;
7832 case 2:
7833 /* Force recalling of all players to town if
7834 configured */
7835 msg_broadcast(0, "\377rServer about to close down. Recall soon");
7836 break;
7837 case 3:
7838 /* Hide from the meta - server socket still open */
7839 Report_to_meta(META_DIE);
7840 //meta = FALSE;
7841 msg_broadcast(0, "\377rServer will close soon.");
7842 break;
7843 case 4:
7844 /* Dungeons are closed */
7845 msg_broadcast(0, "\377yThe dungeons are now closed.");
7846 break;
7847 case 5:
7848 /* Shutdown warning mode, automatic timer */
7849 // msg_broadcast(0, "\377yWarning. Server shutdown will take place in five minutes.");
7850 msg_broadcast(0, "\374\377yWarning. Server shutdown will take place in ten minutes.");
7851 break;
7852 case 1024:
7853 Report_to_meta(META_DIE);
7854 //meta = FALSE;
7855 break;
7856 /* Hack -- character edit (possessor) mode */
7857 case 2042:
7858 case 2043:
7859 case 2044:
7860 case 2045:
7861 case 2046:
7862 case 2047:
7863 case 2048:
7864 case 2051:
7865 /* Shutdown as soon as server is empty (admins don't count) */
7866 break;
7867 case 2049:
7868 /* Usually not called here - just a temporary hack value (see dungeon.c) */
7869 shutdown_server();
7870 break;
7871 case 6:
7872 /* Running */
7873 default:
7874 /* Cancelled shutdown */
7875 if (cfg.runlevel != 6)
7876 msg_broadcast(0, "\377GServer shutdown cancelled.");
7877 Report_to_meta(META_START);
7878 //meta = TRUE;
7879 val = 6;
7880 break;
7881 }
7882 time(&cfg.closetime);
7883 cfg.runlevel = val;
7884 }
7885
7886 /*
7887 * Actually play a game
7888 *
7889 * If the "new_game" parameter is true, then, after loading the
7890 * server-specific savefiles, we will start anew.
7891 */
7892 void play_game(bool new_game, bool all_terrains, bool dry_Bree, bool new_wilderness, bool new_flavours, bool new_houses) {
7893 int h = 0, m = 0, s = 0, dwd = 0, dd = 0, dm = 0, dy = 0;
7894 time_t now;
7895 struct tm *tmp;
7896 //int i, n;
7897
7898 /* Init the RNG */
7899 // Is it a good idea ? DGDGDGD -- maybe FIXME
7900 // if (Rand_quick)
7901 {
7902 u32b seed;
7903
7904 /* Basic seed */
7905 seed = (time(NULL));
7906
7907 #ifdef SET_UID
7908
7909 /* Mutate the seed on Unix machines */
7910 seed = ((seed >> 3) * (getpid() << 1));
7911
7912 #endif
7913
7914 /* Use the complex RNG */
7915 Rand_quick = FALSE;
7916
7917 /* Seed the "complex" RNG */
7918 Rand_state_init(seed);
7919 }
7920
7921 /*** Init the wild_info array... for more information see wilderness.c ***/
7922 init_wild_info();
7923
7924 /* Load list of banned players */
7925 load_banlist();
7926
7927 /* Attempt to load the server state information */
7928 if (!load_server_info()) {
7929 /* Oops */
7930 quit("broken server savefile(s)");
7931 }
7932
7933 /* Nothing loaded */
7934 if (!server_state_loaded) {
7935 /* Make server state info */
7936 new_game = TRUE;
7937
7938 /* Create a new dungeon */
7939 server_dungeon = FALSE;
7940 }
7941 else server_dungeon = TRUE;
7942
7943 /* Roll new town */
7944 if (new_game) {
7945 /* Ignore the dungeon */
7946 server_dungeon = FALSE;
7947
7948 /* Start in town */
7949 /* dlev = 0;*/
7950
7951 /* Hack -- seed for flavors */
7952 seed_flavor = rand_int(0x10000000);
7953
7954 /* Hack -- seed for town layout */
7955 seed_town = rand_int(0x10000000);
7956
7957 /* Initialize server state information */
7958 server_birth();
7959
7960 /* Generate the wilderness */
7961 genwild(all_terrains, dry_Bree);
7962
7963 /* Generate the towns */
7964 wild_spawn_towns();
7965
7966 /* Create dungeon index info */
7967 s_printf("Indexing dungeons..\n");
7968 reindex_dungeons();
7969
7970 /* Hack -- force town surrounding types
7971 * This really shouldn't be here; just a makeshift and to be
7972 * replaced by multiple-town generator */
7973 //wild_bulldoze();
7974
7975 /* Hack -- enter the world */
7976 turn = 1;
7977 } else {
7978 /* use with lua_forget_map() */
7979 if (new_wilderness) {
7980 int i, x, y;
7981 wilderness_type *w_ptr;
7982 struct dungeon_type *d_ptr;
7983
7984 s_printf("Resetting wilderness..\n");
7985
7986 /* Hack -- seed for town layout */
7987 seed_town = rand_int(0x10000000);
7988
7989 /* erase all house information and re-init, consistent with init_other() */
7990 s_printf(" ..erasing old info..\n");
7991
7992 /* free old objects (worldmap/houses/monster inventory) */
7993 for (i = 0; i < o_max; i++) {
7994 /* Skip dead objects */
7995 if (!o_list[i].k_idx) continue;
7996 if (true_artifact_p(&o_list[i])) handle_art_d(o_list[i].name1);
7997 questitem_d(&o_list[i], o_list[i].number);
7998 }
7999 C_KILL(o_list, MAX_O_IDX, object_type);
8000 C_MAKE(o_list, MAX_O_IDX, object_type);
8001 o_max = 1;
8002 o_nxt = 1;
8003 o_top = 0;
8004
8005 /* free old monsters */
8006 C_KILL(m_list, MAX_M_IDX, monster_type);
8007 C_MAKE(m_list, MAX_M_IDX, monster_type);
8008 m_max = 1;
8009 m_nxt = 1;
8010 m_top = 0;
8011
8012 /* free old houses[] info */
8013 for (i = 0; i < num_houses; i++) {
8014 KILL(houses[i].dna, struct dna_type);
8015 if (!(houses[i].flags & HF_RECT))
8016 C_KILL(houses[i].coords.poly, MAXCOORD, char);
8017 #ifndef USE_MANG_HOUSE_ONLY
8018 C_KILL(houses[i].stock, houses[i].stock_size, object_type);
8019 #endif
8020 }
8021 C_KILL(houses, house_alloc, house_type);
8022 house_alloc = 1024;
8023 C_MAKE(houses, house_alloc, house_type);
8024 num_houses = 0;
8025
8026 /* free old town[] and town[]->store info */
8027 if (town) {
8028 for (i = 0; i < numtowns; i++) dealloc_stores(i);
8029 C_KILL(town, numtowns, struct town_type);
8030 }
8031 numtowns = 0;
8032
8033 /* free old dungeon/tower info */
8034 for (y = 0 ;y < MAX_WILD_Y; y++) {
8035 for (x = 0; x < MAX_WILD_X; x++) {
8036 w_ptr = &wild_info[y][x];
8037 if (w_ptr->flags & WILD_F_DOWN) {
8038 d_ptr = w_ptr->dungeon;
8039 for (i = 0; i < d_ptr->maxdepth; i++) {
8040 C_KILL(d_ptr->level[i].uniques_killed, MAX_R_IDX, char);
8041 }
8042 C_KILL(d_ptr->level, d_ptr->maxdepth, struct dun_level);
8043 KILL(d_ptr, struct dungeon_type);
8044 }
8045 if (w_ptr->flags & WILD_F_UP) {
8046 d_ptr = w_ptr->tower;
8047 for (i = 0; i < d_ptr->maxdepth; i++) {
8048 C_KILL(d_ptr->level[i].uniques_killed, MAX_R_IDX, char);
8049 }
8050 C_KILL(d_ptr->level, d_ptr->maxdepth, struct dun_level);
8051 KILL(d_ptr, struct dungeon_type);
8052 }
8053 }
8054 }
8055
8056 /*** Init the wild_info array... for more information see wilderness.c ***/
8057 init_wild_info();
8058
8059 /* Ignore the dungeon */
8060 server_dungeon = FALSE;
8061
8062 /* Generate the wilderness */
8063 s_printf(" ..generating wilderness..\n");
8064 genwild(all_terrains, dry_Bree);
8065
8066 /* Generate the towns */
8067 s_printf(" ..spawning towns..\n");
8068 wild_spawn_towns();
8069
8070 /* Discard old dungeon index info */
8071 s_printf(" ..reindexing dungeons..\n");
8072 reindex_dungeons();
8073
8074 s_printf("..done.\n");
8075 }
8076 if (new_flavours) {
8077 /* use with lua_forget_flavours() */
8078 s_printf("Resetting flavours.\n");
8079
8080 /* Hack -- seed for flavors */
8081 seed_flavor = rand_int(0x10000000);
8082 }
8083 if (new_houses) {
8084 int i;
8085
8086 s_printf("Reinitializing houses.\n");
8087
8088 /* free old houses[] info */
8089 for (i = 0; i < num_houses; i++) {
8090 KILL(houses[i].dna, struct dna_type);
8091 if (!(houses[i].flags & HF_RECT))
8092 C_KILL(houses[i].coords.poly, MAXCOORD, char);
8093 #ifndef USE_MANG_HOUSE_ONLY
8094 C_KILL(houses[i].stock, houses[i].stock_size, object_type);
8095 #endif
8096 }
8097 C_KILL(houses, house_alloc, house_type);
8098 house_alloc = 1024;
8099 C_MAKE(houses, house_alloc, house_type);
8100 num_houses = 0;
8101 }
8102 }
8103
8104 /* Initialize wilderness 'level' */
8105 init_wild_info_aux(0,0);
8106
8107
8108 /* Flash a message */
8109 s_printf("Please wait...\n");
8110
8111 /* Flavor the objects */
8112 flavor_init();
8113
8114 s_printf("Object flavors initialized...\n");
8115
8116 /* Reset the visual mappings */
8117 reset_visuals();
8118
8119 /* Make a town if necessary */
8120 /*
8121 * NOTE: The central town of Angband is handled in a special way;
8122 * If it was static when saved, we shouldn't allocate it.
8123 * If not static, or it's new game, we should allocate it.
8124 */
8125 /*
8126 * For sure, we should redesign it for real multiple-towns!
8127 * - Jir -
8128 */
8129 if (!server_dungeon) {
8130 struct worldpos twpos;
8131 twpos.wx = cfg.town_x;
8132 twpos.wy = cfg.town_y;
8133 twpos.wz = 0;
8134 /* Allocate space for it */
8135 alloc_dungeon_level(&twpos);
8136
8137 /* Actually generate the town */
8138 generate_cave(&twpos, NULL);
8139 }
8140
8141 /* Finish initializing dungeon monsters */
8142 setup_monsters();
8143
8144 /* Detect and fix wrong monster counts. Important to keep uniques spawnable:
8145 Their counts might have been corrupted by panic save or similar crash. */
8146 /* First set all to zero */
8147 for (h = 0; h < MAX_R_IDX; h++) r_info[h].cur_num = 0;
8148 /* Now count how many monsters there are of each race */
8149 for (h = 0; h < m_max; h++)
8150 if (m_list[h].r_idx) r_info[m_list[h].r_idx].cur_num++;
8151
8152 /* Finish initializing dungeon objects */
8153 setup_objects();
8154
8155 /* Server initialization is now "complete" */
8156 server_generated = TRUE;
8157
8158 /* Set up the contact socket, so we can allow players to connect */
8159 setup_contact_socket();
8160
8161 /* Set up the network server */
8162 if (Setup_net_server() == -1)
8163 quit("Couldn't set up net server");
8164
8165 /* scan for inactive players */
8166 scan_players();
8167 scan_accounts();
8168 scan_houses();
8169
8170 #if defined CLIENT_SIDE_WEATHER && !defined CLIENT_WEATHER_GLOBAL
8171 /* initialize weather */
8172 wild_weather_init();
8173 #endif
8174
8175 init_day_and_night();
8176
8177 cfg.runlevel = 6; /* Server is running */
8178
8179 /* Set up the main loop */
8180 install_timer_tick(dungeon, cfg.fps);
8181
8182 /* Execute custom startup script - C. Blue */
8183 time(&now);
8184 tmp = localtime(&now);
8185 h = tmp->tm_hour;
8186 m = tmp->tm_min;
8187 s = tmp->tm_sec;
8188 get_date(&dwd, &dd, &dm, &dy);
8189 exec_lua(0, format("playloop_startup(\"%s\", %d, %d, %d, %d, %d, %d, %d)", showtime(), h, m, s, dwd, dd, dm, dy));
8190
8191 quest_handle_disabled_on_startup();
8192
8193 /* Loop forever */
8194 sched();
8195
8196 /* This should never, ever happen */
8197 s_printf("sched returned!!!\n");
8198
8199 /* Close stuff */
8200 close_game();
8201
8202 /* Quit */
8203 quit(NULL);
8204 }
8205
8206
8207 void shutdown_server(void) {
8208 s_printf("Shutting down.\n");
8209
8210 /* Kick every player out and save his game */
8211 while(NumPlayers > 0) {
8212 /* Note the we always save the first player */
8213 player_type *p_ptr = Players[1];
8214
8215 /* Notify players who are afk and even pseudo-afk rogues */
8216 #if 0 /* always send a page beep? */
8217 Send_beep(1);
8218 #endif
8219 #if 0 /* only when afk or idle? */
8220 if (p_ptr->afk) Send_beep(1);
8221 else if (p_ptr->turns_idle >= cfg.fps * AUTO_AFK_TIMER) Send_beep(1);
8222 #endif
8223 #if 1 /* send a warning sound (usually same as page beep) */
8224 // sound(1, "warning", "page", SFX_TYPE_NO_OVERLAP, FALSE);
8225 sound(1, "page", NULL, SFX_TYPE_NO_OVERLAP, FALSE);
8226 #endif
8227 Net_output1(1);
8228
8229 /* Indicate cause */
8230 strcpy(p_ptr->died_from, "server shutdown");
8231
8232 /* Try to save */
8233 if (!save_player(1)) Destroy_connection(p_ptr->conn, "Server shutdown (save failed)");
8234
8235 /* Successful save */
8236 if (cfg.runlevel == -1)
8237 Destroy_connection(p_ptr->conn, "Server is undergoing maintenance and may take a little while to restart.");
8238 else
8239 Destroy_connection(p_ptr->conn, "Server has been updated, please login again."); /* was "Server shutdown (save succeeded)" */
8240 }
8241
8242 /* Save list of banned players */
8243 save_banlist();
8244
8245 /* Save dynamic quest info */
8246 save_quests();
8247
8248 /* Save the server state */
8249 if (!save_server_info()) quit("Server state save failed!");
8250
8251 /* Tell the metaserver that we're gone */
8252 Report_to_meta(META_DIE);
8253
8254 #ifdef ENABLE_GO_GAME
8255 /* Shut down Go AI engine and its pipes */
8256 go_engine_terminate();
8257 #endif
8258
8259 if (cfg.runlevel == -1)
8260 quit("Terminating");
8261 else
8262 quit("Server state saved");
8263 }
8264
8265 void pack_overflow(int Ind) {
8266 player_type *p_ptr = Players[Ind];
8267
8268 /* XXX XXX XXX Pack Overflow */
8269 if (p_ptr->inventory[INVEN_PACK].k_idx) {
8270 object_type *o_ptr;
8271 int amt, i, j = 0;
8272 u32b f1, f2, f3, f4, f5, f6, esp;
8273 char o_name[ONAME_LEN];
8274
8275 /* Choose an item to spill */
8276 for (i = INVEN_PACK - 1; i >= 0; i--) {
8277 o_ptr = &p_ptr->inventory[i];
8278 object_flags(o_ptr, &f1, &f2, &f3, &f4, &f5, &f6, &esp);
8279
8280 if (!check_guard_inscription(o_ptr->note, 'd') &&
8281 !((f4 & TR4_CURSE_NO_DROP) && cursed_p(o_ptr)) &&
8282 !o_ptr->questor) {
8283 j = 1;
8284 break;
8285 }
8286 }
8287
8288 if (!j) i = INVEN_PACK;
8289
8290 /* Access the slot to be dropped */
8291 o_ptr = &p_ptr->inventory[i];
8292
8293 /* Drop all of that item */
8294 amt = o_ptr->number;
8295
8296 /* Disturbing */
8297 disturb(Ind, 0, 0);
8298
8299 /* Warning */
8300 // msg_print(Ind, "\376\377oYour pack overflows!");
8301
8302 /* Describe */
8303 object_desc(Ind, o_name, o_ptr, TRUE, 3);
8304
8305 /* Message */
8306 msg_format(Ind, "\376\377oYour pack overflows! You drop %s.", o_name);
8307
8308 #ifdef USE_SOUND_2010
8309 sound_item(Ind, o_ptr->tval, o_ptr->sval, "pickup_");
8310 #endif
8311
8312 /* Drop it (carefully) near the player */
8313 drop_near_severe(Ind, o_ptr, 0, &p_ptr->wpos, p_ptr->py, p_ptr->px);
8314
8315 /* Decrease the item, optimize. */
8316 inven_item_increase(Ind, i, -amt);
8317 inven_item_optimize(Ind, i);
8318 }
8319 }
8320
8321 /* Handle special timed events that don't fit in /
8322 aren't related to 'Global Events' routines - C. Blue
8323 (To be called every second.)
8324 Now also used for Go minigame. */
8325 void process_timers() {
8326 struct worldpos wpos;
8327 cave_type **zcave;
8328 int y, x, i;
8329
8330 #ifdef ENABLE_GO_GAME
8331 /* Process Go AI engine communication (its replies) */
8332 if (go_game_up) go_engine_clocks();
8333 #endif
8334
8335 /* PvP Arena in 0,0 - Release monsters: */
8336 if (timer_pvparena1) {
8337 /* check for existence of arena */
8338 wpos.wx = WPOS_PVPARENA_X;
8339 wpos.wy = WPOS_PVPARENA_Y;
8340 wpos.wz = WPOS_PVPARENA_Z;
8341 if (!(zcave = getcave(&wpos))) return;
8342
8343 timer_pvparena1--;
8344 if (!timer_pvparena1) {
8345 /* start next countdown */
8346 timer_pvparena1 = 90; //45 was too fast, disallowing ppl to leave the arena sort of
8347
8348 if ((timer_pvparena3 % 2) == 0) { /* cycle preparation? */
8349 /* clear old monsters and items */
8350 wipe_m_list(&wpos);
8351 wipe_o_list_safely(&wpos);
8352 /* close all doors */
8353 for (i = 1; i <= 6; i++) {
8354 y = 2;
8355 x = (i * 10) - 3;
8356 zcave[y][x].feat = FEAT_SEALED_DOOR;
8357 everyone_lite_spot(&wpos, y, x);
8358 }
8359 }
8360
8361 if (timer_pvparena3 == 0) { /* prepare first cycle */
8362 y = 1;
8363 x = (1 * 10) - 3;
8364 summon_override_checks = SO_ALL;
8365 //866 elite uruk, 563 young red dragon
8366 // place_monster_aux(&wpos, y, x, 866, FALSE, FALSE, 100, 0);
8367 // place_monster_one(&wpos, y, x, 866, FALSE, FALSE, FALSE, 100, 0);
8368 place_monster_one(&wpos, y, x, 102, FALSE, FALSE, FALSE, 100, 0);//large k
8369 x = (2 * 10) - 3;
8370 //487 storm giant
8371 // place_monster_aux(&wpos, y, x, 487, FALSE, FALSE, 100, 0);
8372 // place_monster_one(&wpos, y, x, 563, FALSE, FALSE, FALSE, 100, 0);
8373 place_monster_one(&wpos, y, x, 249, FALSE, FALSE, FALSE, 100, 0);//light Z(271) //vlasta(249)
8374 x = (3 * 10) - 3;
8375 //609 baron of hell
8376 // place_monster_aux(&wpos, y, x, 590, FALSE, FALSE, 100, 0);
8377 // place_monster_one(&wpos, y, x, 487, FALSE, FALSE, FALSE, 100, 0);
8378 place_monster_one(&wpos, y, x, 866, FALSE, FALSE, FALSE, 100, 0);//elite o
8379 x = (4 * 10) - 3;
8380 //590 mature gold d
8381 // place_monster_aux(&wpos, y, x, 720, FALSE, FALSE, 100, 0);
8382 // place_monster_one(&wpos, y, x, 720, FALSE, FALSE, FALSE, 100, 0);
8383 place_monster_one(&wpos, y, x, 563, FALSE, FALSE, FALSE, 100, 0);//young red d
8384 x = (5 * 10) - 3;
8385 //995 marilith, 558 colossus
8386 // place_monster_aux(&wpos, y, x, 558, FALSE, FALSE, 100, 0);
8387 // place_monster_one(&wpos, y, x, 558, FALSE, FALSE, FALSE, 100, 0);
8388 place_monster_one(&wpos, y, x, 194, FALSE, FALSE, FALSE, 100, 0);//tengu
8389 x = (6 * 10) - 3;
8390 //602 bronze D, 720 barbazu
8391 // place_monster_aux(&wpos, y, x, 609, FALSE, FALSE, 100, 0);
8392 // place_monster_one(&wpos, y, x, 609, FALSE, FALSE, FALSE, 100, 0);
8393 place_monster_one(&wpos, y, x, 321, FALSE, FALSE, FALSE, 100, 0);//stone P
8394 summon_override_checks = SO_NONE;
8395 timer_pvparena3++; /* start releasing cycle */
8396 return;
8397 } else if (timer_pvparena3 == 2) { /* prepare second cycle */
8398 summon_override_checks = SO_ALL;
8399 for (i = 1; i <= 6; i++) {
8400 y = 1;
8401 x = (i * 10) - 3;
8402 //613 hellhound is too tough, 963 aranea im_pois, 986 3-h hydra, 249 vlasta
8403 //440 5-h hydra, 387 4-h hydra, 341 chimaera, 301 2-h hydra, 325 gold dfly
8404 // place_monster_aux(&wpos, y, x, 963, FALSE, FALSE, 100, 0);
8405 //place_monster_one(&wpos, y, x, i % 3 ? i % 2 ? 341 : 325 : 301, FALSE, FALSE, FALSE, 100, 0);
8406 place_monster_one(&wpos, y, x, i % 3 ? i % 2 ? 295 : 325 : 275, FALSE, FALSE, FALSE, 100, 0);//sphinx,gold dfly,tarantula
8407 everyone_lite_spot(&wpos, y, x);
8408 }
8409 summon_override_checks = SO_NONE;
8410 timer_pvparena3++; /* start releasing cycle */
8411 return;
8412 }
8413
8414 /* clear previous monster */
8415 wipe_m_list_roaming(&wpos);
8416 if (timer_pvparena2 > 1) {
8417 /* erase monster that didn't come out of its chamber */
8418 y = 1;
8419 x = ((timer_pvparena2 - 1) * 10) - 3;
8420 if (zcave[y][x].m_idx > 0) delete_monster_idx(zcave[y][x].m_idx, TRUE);
8421 /* erase monster that stopped on its chamber door */
8422 y = 2;
8423 if (zcave[y][x].m_idx > 0) delete_monster_idx(zcave[y][x].m_idx, TRUE);
8424 }
8425
8426 /* open current door to release monster */
8427 y = 2;
8428 x = (timer_pvparena2 * 10) - 3;
8429 zcave[y][x].feat = FEAT_UNSEALED_DOOR;
8430 everyone_lite_spot(&wpos, y, x);
8431
8432 /* after 6th monster, take a break and switch wave cycle */
8433 if (timer_pvparena2 == 6) {
8434 /* prepare next cycle next time */
8435 timer_pvparena3++;
8436 /* max number of cycles? */
8437 timer_pvparena3 = timer_pvparena3 % 4;
8438
8439 /* next time, begin at monster #1 again */
8440 timer_pvparena2 = 1;
8441 return;
8442 }
8443
8444 /* next time, release next monster */
8445 timer_pvparena2++;
8446 }
8447 }
8448
8449 }
8450
8451 /* during new years eve, cast fireworks! - C. Blue
8452 NOTE: Called four times per second (if fireworks are enabled). */
8453 static void process_firework_creation() {
8454 int i;
8455
8456 if (!fireworks_delay) { /* fire! */
8457 worldpos wpos;
8458 switch(rand_int(4)) {
8459 case 0: fireworks_delay = 0; break;
8460 case 1: fireworks_delay = 1; break;
8461 case 2: fireworks_delay = 4; break;
8462 case 3: fireworks_delay = 8; break;
8463 }
8464
8465 /* Fireworks in Bree */
8466 wpos.wx = 32; wpos.wy = 32; wpos.wz = 0;
8467
8468 /* Launch multiple rockets ;) - mikaelh */
8469 for (i = 0; i < fireworks; i++) {
8470 /* "type" determines colour and explosion style */
8471 cast_fireworks(&wpos, rand_int(MAX_WID - 120) + 60, rand_int(MAX_HGT - 40) + 20);
8472 }
8473 } else {
8474 fireworks_delay--;
8475 }
8476 }
8477
8478
8479 #if defined CLIENT_SIDE_WEATHER && defined CLIENT_WEATHER_GLOBAL
8480 /* Update all affected (ie on worldmap surface) players' client-side weather.
8481 NOTE: Called on opportunity of _global_ weather undergoing any change. */
8482 static void players_weather() {
8483 int i;
8484
8485 for (i = 1; i <= NumPlayers; i++) {
8486 /* Skip non-connected players */
8487 if (Players[i]->conn == NOT_CONNECTED) continue;
8488 /* Skip players not on world surface - player_weather() actually checks this too though */
8489 if (Players[i]->wpos.wz) continue;
8490
8491 /* send weather update to him */
8492 player_weather(i, FALSE, TRUE, FALSE);
8493 }
8494 }
8495 #endif
8496
8497 #if defined CLIENT_WEATHER_GLOBAL || !defined CLIENT_SIDE_WEATHER
8498 /* manage and toggle weather and wind state - C. Blue
8499 NOTE: Called once per second,
8500 and for CLIENT_SIDE_WEATHER only if also CLIENT_WEATHER_GLOBAL. */
8501 static void process_weather_control() {
8502
8503 #ifdef CLIENT_SIDE_WEATHER
8504 /* NOTE: we are only supposed to get here if also CLIENT_WEATHER_GLOBAL. */
8505
8506 /* during winter, it snows: */
8507 if (season == SEASON_WINTER) {
8508 if (!weather) { /* not snowing? */
8509 if (weather_duration <= 0 && weather_frequency > 0) { /* change weather? */
8510 weather = 2; /* snowing now */
8511 players_weather();
8512 weather_duration = weather_frequency * 60 * 4;
8513 } else if (weather_duration > 0) {
8514 weather_duration--;
8515 }
8516 } else { /* it's currently snowing */
8517 if (weather_duration <= 0 && (4 - weather_frequency) > 0) { /* change weather? */
8518 weather = 0; /* stop snowing */
8519 players_weather();
8520 weather_duration = (4 - weather_frequency) * 60 * 4;
8521 } else if (weather_duration > 0) {
8522 weather_duration--;
8523 }
8524 }
8525 /* during spring, summer and autumn, it rains: */
8526 } else {
8527 if (weather) { /* it's currently raining */
8528 if (weather_duration <= 0 && weather_frequency > 0) { /* change weather? */
8529 weather = 0; /* stop raining */
8530 players_weather();
8531 //s_printf("WEATHER: Stopping rain.\n");
8532 weather_duration = rand_int(60 * 30 / weather_frequency) + 60 * 30 / weather_frequency;
8533 } else weather_duration--;
8534 } else { /* not raining at the moment */
8535 if (weather_duration <= 0 && (4 - weather_frequency) > 0) { /* change weather? */
8536 weather = 1; /* start raining */
8537 players_weather();
8538 //s_printf("WEATHER: Starting rain.\n");
8539 weather_duration = rand_int(60 * 9) + 60 * weather_frequency;
8540 } else if (weather_duration > 0) {
8541 weather_duration--;
8542 }
8543 }
8544 }
8545
8546 /* manage wind */
8547 if (wind_gust > 0) {
8548 wind_gust--; /* gust from east */
8549 if (!wind_gust) players_weather();
8550 } else if (wind_gust < 0) {
8551 wind_gust++; /* gust from west */
8552 if (!wind_gust) players_weather();
8553 } else if (!wind_gust_delay) { /* gust of wind coming up? */
8554 wind_gust_delay = 15 + rand_int(240); /* so sometimes no gust at all during 4-min snow periods */
8555 wind_gust = rand_int(60) + 5;
8556 if (rand_int(2)) {
8557 wind_gust = -wind_gust;
8558 }
8559 players_weather();
8560 } else wind_gust_delay--;
8561
8562 #else /* server-side weather: */
8563
8564 /* during winter, it snows: */
8565 if (season == SEASON_WINTER) {
8566 if (!weather) { /* not snowing? */
8567 if (weather_duration <= 0 && weather_frequency > 0) { /* change weather? */
8568 weather = 1; /* snowing now */
8569 weather_duration = weather_frequency * 60 * 4;
8570 } else if (weather_duration > 0) {
8571 weather_duration--;
8572 }
8573 } else { /* it's currently snowing */
8574 if (weather_duration <= 0 && (4 - weather_frequency) > 0) { /* change weather? */
8575 weather = 0; /* stop snowing */
8576 weather_duration = (4 - weather_frequency) * 60 * 4;
8577 } else if (weather_duration > 0) {
8578 weather_duration--;
8579 }
8580 }
8581 /* during spring, summer and autumn, it rains: */
8582 } else {
8583 if (weather) { /* it's currently raining */
8584 if (weather_duration <= 0 && weather_frequency > 0) { /* change weather? */
8585 weather = 0; /* stop raining */
8586 //s_printf("WEATHER: Stopping rain.\n");
8587 weather_duration = rand_int(60 * 30 / weather_frequency) + 60 * 30 / weather_frequency;
8588 } else weather_duration--;
8589 } else { /* not raining at the moment */
8590 if (weather_duration <= 0 && (4 - weather_frequency) > 0) { /* change weather? */
8591 weather = 1; /* start raining */
8592 //s_printf("WEATHER: Starting rain.\n");
8593 weather_duration = rand_int(60 * 9) + 60 * weather_frequency;
8594 } else if (weather_duration > 0) {
8595 weather_duration--;
8596 }
8597 }
8598 }
8599
8600 /* manage wind */
8601 if (wind_gust > 0) wind_gust--; /* gust from east */
8602 else if (wind_gust < 0) wind_gust++; /* gust from west */
8603 else if (!wind_gust_delay) { /* gust of wind coming up? */
8604 wind_gust_delay = 15 + rand_int(240); /* so sometimes no gust at all during 4-min snow periods */
8605 wind_gust = rand_int(60) + 5;
8606 if (rand_int(2)) wind_gust = -wind_gust;
8607 } else wind_gust_delay--;
8608
8609 #endif
8610
8611 }
8612 #endif
8613
8614 /* create actual weather effects.
8615 (animating/excising is then done in process_effects())
8616 NOTE: Called each turn. */
8617 #ifndef CLIENT_SIDE_WEATHER
8618 static void process_weather_effect_creation() {
8619
8620 /* clear skies or new years eve fireworks? do nothing */
8621 if (!weather || fireworks) return;
8622
8623 /* winter? then it snows: */
8624 if (season == SEASON_WINTER) {
8625 if (!(turn % ((cfg.fps + 29) / 30))) {
8626 worldpos wpos;
8627 /* Create snowflakes in Bree */
8628 wpos.wx = 32; wpos.wy = 32; wpos.wz = 0;
8629 cast_snowflake(&wpos, rand_int(MAX_WID - 2) + 1, 8);
8630 }
8631 /* spring, summer or autumn? it rains: */
8632 } else {
8633 if (!(turn % ((cfg.fps + 59) / 60))) {
8634 worldpos wpos;
8635 /* Create raindrops in Bree */
8636 wpos.wx = 32; wpos.wy = 32; wpos.wz = 0;
8637 cast_raindrop(&wpos, rand_int(MAX_WID - 2) + 1);
8638 cast_raindrop(&wpos, rand_int(MAX_WID - 2) + 1);
8639 }
8640 }
8641 }
8642 #endif
8643
8644 #ifdef CLIENT_SIDE_WEATHER
8645 #ifndef CLIENT_WEATHER_GLOBAL
8646 /* initialize some weather-related variables */
8647 static void wild_weather_init() {
8648 wilderness_type *w_ptr;
8649 int i, x, y;
8650
8651 /* initialize amount of clouds */
8652 season_change(season, FALSE);
8653
8654 for (x = 0; x < MAX_WILD_X; x++)
8655 for (y = 0; y < MAX_WILD_Y; y++) {
8656 w_ptr = &wild_info[y][x];
8657
8658 /* initialize weather vars */
8659
8660 /* initialize cloud vars */
8661 for (i = 0; i < 10; i++) {
8662 w_ptr->cloud_idx[i] = -1; /* be inactive by default */
8663 w_ptr->cloud_x1[i] = -9999; /* hack for client: disabled */
8664 }
8665 }
8666 }
8667
8668 /* DEBUGGING NOTES - C. Blue
8669 There might be a bug where weather_updated is not TRUE'd for
8670 the player's wilderness sector when using /mkcloud, which might also
8671 be a bug in normal cloud creation. The player will then need to leave
8672 and reenter his sector for the cloud to take effect.
8673 Further bug info: In cloud_erase() the same cloud of a found cloud_idx
8674 (here in /rmcloud) will not be found to be 'touching this sector'.
8675 FURTHER: Seems inconsistent use of cloud_x1/x2/y1/y2:
8676 cloud_create() uses them as start+destination, cloud_move/erase use
8677 them as box-defining points for finding the cloud's covering area. oO */
8678
8679
8680 /* Manange and control weather separately for each worldmap sector,
8681 assumed that client-side weather is used, depending on clouds.
8682 NOTE: Called once per second. */
8683 /* Note: Meanings of cloud_state (not implemented):
8684 1..100: growing (decrementing, until reaching 1)
8685 -1..-100: shrinking (incrementing, until reaching -1 or critically low radius
8686 */
8687 static void process_wild_weather() {
8688 int i;
8689
8690 /* process clouds forming, dissolving
8691 and moving over world map */
8692 for (i = 0; i < MAX_CLOUDS; i++) {
8693 /* does cloud exist? */
8694 if (cloud_dur[i]) {
8695 /* hack: allow dur = -1 to last forever */
8696 if (cloud_dur[i] > 0) {
8697 /* hack to not have clouds near fireworks */
8698 if (season_newyearseve) {
8699 int txm = (cloud_x1[i] + (cloud_x2[i] - cloud_x1[i]) / 2) / MAX_WID; /* central wpos of this cloud */
8700 int tym = cloud_y1[i] / MAX_HGT;
8701 if (distance(tym, txm, cfg.town_y, cfg.town_x) <= 4) cloud_dur[i] = 1;
8702 }
8703 /* lose essence from raining/snowing */
8704 cloud_dur[i]--;
8705 /* if cloud dissolves, keep track */
8706 if (!cloud_dur[i]) {
8707 //s_printf("erasing %d\n", i);//TEST_SERVER
8708 cloud_erase(i);
8709 clouds--;
8710 /* take a break for this second ;) */
8711 continue;
8712 }
8713 }
8714 /* Move it */
8715 cloud_move(i, FALSE);
8716 }
8717
8718 /* create cloud? limit value depends on season */
8719 else if (clouds < max_clouds_seasonal) {
8720 #ifdef TEST_SERVER /* hack: fixed location for easier live testing? */
8721 //around Bree
8722 cloud_create(i, 32 * MAX_HGT, 32 * MAX_WID);
8723 cloud_state[i] = 1;
8724 #else
8725 /* create cloud at random starting x, y world _grid_ coords (!) */
8726 cloud_create(i,
8727 rand_int(MAX_WILD_X * MAX_WID),
8728 rand_int(MAX_WILD_Y * MAX_HGT));
8729 #endif
8730 }
8731 }
8732
8733 /* update players' local client-side weather if required */
8734 local_weather_update();
8735 }
8736
8737 /* Change a cloud's movement.
8738 (Note: Continuous movement is performed by
8739 clients via buffered direction & duration.)
8740 New note: Negative values should probably work too (inverse direction). */
8741 static void cloud_set_movement(int i) {
8742 #ifdef WEATHER_NO_CLOUD_MOVEMENT
8743 { /* hack: Try to fix the eternal rain bug:
8744 Disable cloud movement for now - C. Blue */
8745 cloud_xm100[i] = 0;
8746 cloud_ym100[i] = 0;
8747 cloud_mdur[i] = 30 + rand_int(300);
8748 return;
8749 }
8750 #endif
8751
8752 #ifdef TEST_SERVER /* hack: fixed location for easier live testing? */
8753 #if 0
8754 cloud_xm100[i] = 100;
8755 cloud_ym100[i] = 100;
8756 cloud_mdur[i] = 10;
8757 #endif
8758 #if 1
8759 cloud_xm100[i] = 0;
8760 cloud_ym100[i] = 0;
8761 cloud_mdur[i] = 10;
8762 #endif
8763 #else
8764 if (rand_int(2)) {
8765 /* no pseudo-wind */
8766 cloud_xm100[i] = 0;
8767 cloud_ym100[i] = 0;
8768 } else {
8769 /* pseudo-wind */
8770 cloud_xm100[i] = randint(100);
8771 cloud_ym100[i] = randint(100);
8772 }
8773 cloud_mdur[i] = 30 + rand_int(300); /* seconds */
8774 #endif
8775 }
8776
8777 /* remove cloud status off all previously affected wilderness sectors,
8778 move & resize cloud,
8779 imprint cloud status on all currently affected wilderness sectors.
8780 Set each affected sector's 'weather_updated' if there was a change.
8781 Note: Wild sectors have a limit of amount of concurrent clouds
8782 they can be affected by (10).
8783 'resend_direction' explanation:
8784 If the direction of this cloud changed. the affected wilderness
8785 sectors will definitely need to be set to weather_updated, so
8786 the clients will by synchronized to the new cloud movement.
8787 NOTE: 'change' means that either cloud movement changes or that
8788 a wild sector toggles affected/unaffected state, simply. */
8789 /* make rain fall down slower? */
8790 #if 1
8791 #define WEATHER_GEN_TICKS 3
8792 #define WEATHER_SNOW_MULT 3
8793 #else
8794 /* make rain fall down faster? (recommended) */
8795 #define WEATHER_GEN_TICKS 2
8796 #define WEATHER_SNOW_MULT 4
8797 #endif
8798 static void cloud_move(int i, bool newly_created) {
8799 bool resend_dir = FALSE, sector_changed;
8800 wilderness_type *w_ptr;
8801 int x, y, xs, ys, xd, yd, j;
8802 int txm, tym, tgx, tgy, d, dx, dy;
8803 int xs_add_prev = 0, ys_add_prev = 0, xd_add_prev = 0, yd_add_prev = 0;
8804 bool was_affected, is_affected, can_become_affected;
8805 int was_affected_idx = 0; /* slaying compiler warning */
8806 bool final_cloud_in_sector;
8807
8808
8809 /* process cloud shaping & movement --------------------------------------- */
8810
8811 /* perform growing/shrinking (todo: implement) */
8812 if (cloud_state[i] > 1) {
8813 cloud_state[i]--;
8814 /* grow */
8815 } else if (cloud_state[i] < -1) {
8816 cloud_state[i]++;
8817 /* shrink */
8818 }
8819
8820 /* process movement
8821 Note: This is done both server- and client-side,
8822 and synch'ed whenever movement changes or
8823 a new worldmap sector becomes (un)affected
8824 which is currently visited by tbe player to
8825 synch with. */
8826 cloud_mdur[i]--;
8827 /* change in movement? */
8828 if (!cloud_mdur[i]) {
8829 cloud_set_movement(i);
8830 /* update all players' cloud direction information */
8831 resend_dir = TRUE;
8832 }
8833
8834 /* perform movement */
8835 cloud_xfrac[i] += cloud_xm100[i];
8836 cloud_yfrac[i] += cloud_ym100[i];
8837 x = cloud_xfrac[i] / 100;
8838 y = cloud_yfrac[i] / 100;
8839 if (x) {
8840 cloud_x1[i] += x;
8841 cloud_x2[i] += x;
8842 cloud_xfrac[i] -= x * 100;
8843 /* we possibly left a sector behind by moving on: */
8844 if (x > 0) xs_add_prev = -1;
8845 else xd_add_prev = 1;
8846 }
8847 if (y) {
8848 cloud_y1[i] += y;
8849 cloud_y2[i] += y;
8850 cloud_yfrac[i] += y * 100;
8851 /* we possibly left a sector behind by moving on: */
8852 if (y > 0) ys_add_prev = -1;
8853 else yd_add_prev = 1;
8854 }
8855
8856
8857 /* imprint new situation on wild sectors locally --------------------------- */
8858
8859 /* check all worldmap sectors affected by this cloud
8860 and modify local weather situation accordingly if needed */
8861 /* NOTE regarding hardcoding: These calcs depend on cloud creation algo a lot */
8862 txm = (cloud_x1[i] + (cloud_x2[i] - cloud_x1[i]) / 2) / MAX_WID; /* central wpos of this cloud */
8863 tym = cloud_y1[i] / MAX_HGT;
8864 xs = CLOUD_XS(cloud_x1[i], cloud_y1[i], cloud_x2[i], cloud_y2[i], cloud_dsum[i]);
8865 xd = CLOUD_XD(cloud_x1[i], cloud_y1[i], cloud_x2[i], cloud_y2[i], cloud_dsum[i]);
8866 ys = CLOUD_YS(cloud_x1[i], cloud_y1[i], cloud_x2[i], cloud_y2[i], cloud_dsum[i]);
8867 yd = CLOUD_YD(cloud_x1[i], cloud_y1[i], cloud_x2[i], cloud_y2[i], cloud_dsum[i]);
8868 /* traverse all wild sectors that could maybe be affected or
8869 have been affected by this cloud, very roughly calculated
8870 (just a rectangle mask), fine check is done inside. */
8871 for (x = xs + xs_add_prev; x <= xd + xd_add_prev; x++)
8872 for (y = ys + ys_add_prev; y <= yd + yd_add_prev; y++) {
8873 /* skip sectors out of array bounds */
8874 if (x < 0 || x >= MAX_WILD_X || y < 0 || y >= MAX_WILD_Y) continue;
8875
8876 w_ptr = &wild_info[y][x];
8877
8878 sector_changed = FALSE; /* assume no change */
8879 was_affected = FALSE;
8880 is_affected = FALSE;
8881 can_become_affected = FALSE; /* assume no free space left in local cloud array of this wild sector */
8882 final_cloud_in_sector = TRUE; /* assume this cloud is the only one keeping the weather up here */
8883
8884 /* was the sector affected before moving? */
8885 for (j = 0; j < 10; j++) {
8886 /* cloud occurs in this sector? so sector was already affected */
8887 if (w_ptr->cloud_idx[j] == i) {
8888 was_affected = TRUE;
8889 was_affected_idx = j;
8890 }
8891 /* free space in cloud array? means we could add another cloud if we want */
8892 else if (w_ptr->cloud_idx[j] == -1) can_become_affected = TRUE;
8893 else if (w_ptr->cloud_idx[j] != -1) final_cloud_in_sector = FALSE;
8894 }
8895 if (!was_affected) final_cloud_in_sector = FALSE;
8896
8897 /* if this sector wasn't affected before, and we don't
8898 have free space left in its local cloud array,
8899 then we won't be able to imprint on it anyway, so we
8900 may as well ignore and leave this sector now. */
8901 if (!was_affected && !can_become_affected) continue;
8902
8903 #ifdef TEST_SERVER
8904 //SPAM(after a short while) s_printf("cloud-debug 1.\n");
8905 #endif
8906 /* is the sector affected now after moving? */
8907 /* calculate coordinates for deciding test case */
8908 /* NOTE regarding hardcoding: These calcs depend on cloud creation algo a lot */
8909 if (x < txm) tgx = (x + 1) * MAX_WID - 1; /* x: left edge of current sector */
8910 else if (x > txm) tgx = x * MAX_WID; /* x: right edge of current sector */
8911 else tgx = cloud_x1[i] + (cloud_x2[i] - cloud_x1[i]) / 2; /* x: center point of current cloud */
8912 if (y < tym) tgy = (y + 1) * MAX_HGT - 1; /* analogous to x above */
8913 else if (y > tym) tgy = y * MAX_HGT;
8914 else tgy = cloud_y1[i];
8915 /* test whether cloud touches the sector (taken from distance()) */
8916 /* Calculate distance to cloud focus point 1: */
8917 dy = (tgy > cloud_y1[i]) ? (tgy - cloud_y1[i]) : (cloud_y1[i] - tgy);
8918 dx = (tgx > cloud_x1[i]) ? (tgx - cloud_x1[i]) : (cloud_x1[i] - tgx);
8919 d = (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
8920 /* Calculate distance to cloud focus point 2: */
8921 dy = (tgy > cloud_y2[i]) ? (tgy - cloud_y2[i]) : (cloud_y2[i] - tgy);
8922 dx = (tgx > cloud_x2[i]) ? (tgx - cloud_x2[i]) : (cloud_x2[i] - tgx);
8923 /* ..and sum them up */
8924 d += (dy > dx) ? (dy + (dx >> 1)) : (dx + (dy >> 1));
8925
8926 /* is sector affected now? add cloud to its local cloud array */
8927 if (d <= cloud_dsum[i]) {
8928 is_affected = TRUE;
8929 #ifdef TEST_SERVER
8930 //s_printf("cloud-debug 2.\n");
8931 #endif
8932
8933 /* update old cloud data or add a new entry if it didn't exist previously */
8934 for (j = 0; j < 10; j++) {
8935 /* unchanged cloud situation leads to continuing.. */
8936 if (was_affected && w_ptr->cloud_idx[j] != i) continue;
8937 if (!was_affected && w_ptr->cloud_idx[j] != -1) continue;
8938 #ifdef TEST_SERVER
8939 //s_printf("cloud-debug 3.\n");
8940 #endif
8941
8942 /* imprint cloud data to this wild sector's local cloud array */
8943 w_ptr->cloud_idx[j] = i;
8944 w_ptr->cloud_x1[j] = cloud_x1[i];
8945 w_ptr->cloud_y1[j] = cloud_y1[i];
8946 w_ptr->cloud_x2[j] = cloud_x2[i];
8947 w_ptr->cloud_y2[j] = cloud_y2[i];
8948 w_ptr->cloud_dsum[j] = cloud_dsum[i];
8949 w_ptr->cloud_xm100[j] = cloud_xm100[i];
8950 w_ptr->cloud_ym100[j] = cloud_ym100[i];
8951 #if 0
8952 /* meta data for Send_weather() */
8953 if (!w_ptr->cloud_updated[j]) {
8954 w_ptr->cloud_updated[j] = TRUE;
8955 w_ptr->clouds_to_update++;
8956 }
8957 #endif
8958 /* define weather situation accordingly */
8959 switch (w_ptr->type) {
8960 case WILD_ICE:
8961 w_ptr->weather_type = 2; /* always snow in icy waste */
8962 break;
8963 case WILD_DESERT:
8964 w_ptr->weather_type = 1; /* never snow in desert */
8965 break;
8966 default:
8967 /* depends on season */
8968 w_ptr->weather_type = (season == SEASON_WINTER ? 2 : 1);
8969 }
8970 #ifdef TEST_SERVER
8971 //s_printf("weather_type debug: wt=%d, x,y=%d,%d.\n", w_ptr->weather_type, x, y);
8972 #if 0
8973 if (NumPlayers && Players[NumPlayers]->wpos.wx == x && Players[NumPlayers]->wpos.wy == y) {
8974 s_printf("weather_type debug: wt=%d, x,y=%d,%d.\n", w_ptr->weather_type, x, y);
8975 s_printf("cloud debug all: cidx=%d, x1,y1=%d,%d, dsum=%d.\n",
8976 w_ptr->cloud_idx[j], w_ptr->cloud_x1[j], w_ptr->cloud_y1[j], w_ptr->cloud_dsum[j]);
8977 }
8978 #endif
8979 #endif
8980
8981 #ifndef WEATHER_WINDS /* no winds */
8982 w_ptr->weather_wind = 0; /* todo: change =p (implement winds, actually -- currently we're
8983 using pseudo-winds by just setting random cloud movement - C. Blue */
8984 w_ptr->weather_wind_vertical = 0;
8985 #else /* winds */
8986 #ifndef WEATHER_NO_CLOUD_MOVEMENT /* Cloud movemenet is disabled as a workaround for the 'eternal rain' bug.. */
8987 /* note- pretty provisional implementation, since winds shouldnt depend
8988 on cloud movement, but actually the other way round ;) This is merely
8989 so we get to see some wind already, and these 'winds' would also conflict
8990 if multiple clouds moving into different directions met.. - C. Blue */
8991 if (cloud_xm100[i] > 40) w_ptr->weather_wind = 5 - (2 * ((cloud_xm100[i] - 40) / 21));
8992 else if (cloud_xm100[i] < -40) w_ptr->weather_wind = 6 - (2 * ((-cloud_xm100[i] - 40) / 21));
8993 else w_ptr->weather_wind = 0;
8994 /* also determine vertical pseudo winds, just for server-side running speed calculations */
8995 if (cloud_ym100[i] > 40) w_ptr->weather_wind_vertical = 5 - (2 * ((cloud_ym100[i] - 40) / 21));
8996 else if (cloud_ym100[i] < -40) w_ptr->weather_wind_vertical = 6 - (2 * ((-cloud_ym100[i] - 40) / 21));
8997 else w_ptr->weather_wind_vertical = 0;
8998 #else /* ..so a little hack is needed to bring back 'windy' weather^^ - C. Blue */
8999 /* hack - randomly assume some winds, that stay sufficiently consistent */
9000 {
9001 /* this should allow smooth/consistent winds over slight changes in a player's wilderness position: */
9002 int seed = (y + x + ((int)((turn / (cfg.fps * 1200)) % 90))) / 3; /* hourly change */
9003 switch (seed % 30) {
9004 case 0: case 1: case 2: case 3: w_ptr->weather_wind = 0; break;
9005 case 4: case 5: case 6: w_ptr->weather_wind = 5; break;
9006 case 7: case 8: w_ptr->weather_wind = 3; break;
9007 case 9: w_ptr->weather_wind = 1; break;
9008 case 10: case 11: w_ptr->weather_wind = 3; break;
9009 case 12: case 13: case 14: w_ptr->weather_wind = 5; break;
9010 case 15: case 16: case 17: case 18: w_ptr->weather_wind = 0; break;
9011 case 19: case 20: case 21: w_ptr->weather_wind = 6; break;
9012 case 22: case 23: w_ptr->weather_wind = 4; break;
9013 case 24: w_ptr->weather_wind = 2; break;
9014 case 25: case 26: w_ptr->weather_wind = 4; break;
9015 case 27: case 28: case 29: w_ptr->weather_wind = 6; break;
9016 }
9017 w_ptr->weather_wind_vertical = 0;
9018 }
9019 #endif
9020 #endif
9021
9022 w_ptr->weather_intensity =
9023 (w_ptr->weather_type == 2 && (!w_ptr->weather_wind || w_ptr->weather_wind >= 3)) ?
9024 5 : 8;
9025 w_ptr->weather_speed =
9026 #if 1 /* correct! (this is a different principle than 'weather_intensity' above) */
9027 (w_ptr->weather_type == 2) ? WEATHER_SNOW_MULT * WEATHER_GEN_TICKS :
9028 /* hack: for non-windy rainfall, accelerate raindrop falling speed by 1: */
9029 (w_ptr->weather_wind ? 1 * WEATHER_GEN_TICKS : WEATHER_GEN_TICKS - 1);
9030 #else /* just for testing stuff */
9031 (w_ptr->weather_type == 2 && (!w_ptr->weather_wind || w_ptr->weather_wind >= 3)) ?
9032 WEATHER_SNOW_MULT * WEATHER_GEN_TICKS : 1 * WEATHER_GEN_TICKS;
9033 #endif
9034 break;
9035 }
9036 }
9037 /* sector is not affected. If it was previously affected,
9038 delete cloud from its local array now. */
9039 else if (was_affected) {
9040 #ifdef TEST_SERVER
9041 //s_printf("cloud-debug 4.\n");
9042 #endif
9043 /* erase cloud locally */
9044 w_ptr->cloud_idx[was_affected_idx] = -1;
9045 w_ptr->cloud_x1[was_affected_idx] = -9999; /* hack for client: client sees this as 'disabled' */
9046 #if 0
9047 /* meta data for Send_weather() */
9048 if (!w_ptr->cloud_updated[was_affected_idx]) {
9049 w_ptr->cloud_updated[was_affected_idx] = TRUE;
9050 w_ptr->clouds_to_update++;
9051 }
9052 #endif
9053
9054 /* if this was the last cloud in this sector,
9055 define (stop) weather situation accordingly */
9056 if (final_cloud_in_sector) {
9057 #ifdef TEST_SERVER
9058 //s_printf("cloud-debug 5.\n");
9059 #endif
9060 w_ptr->weather_type = 0; /* make weather 'run out slowly' */
9061 }
9062 }
9063
9064 /* so, did this sector actually 'change' after all? */
9065 if (was_affected != is_affected) sector_changed = TRUE;
9066
9067 /* if the local situation did actually change,
9068 mark as updated for re-sending it to all players on it */
9069 if (sector_changed || newly_created || resend_dir)
9070 w_ptr->weather_updated = TRUE;
9071 }
9072 }
9073
9074 static void cloud_erase(int i) {
9075 wilderness_type *w_ptr;
9076 int x, y, xs, ys, xd, yd, j;
9077 bool was_affected;
9078 int was_affected_idx = 0; /* slaying compiler warning */
9079 bool final_cloud_in_sector;
9080
9081 /* imprint new situation on wild sectors locally --------------------------- */
9082
9083 /* check all worldmap sectors affected by this cloud
9084 and modify local weather situation accordingly if needed */
9085 /* NOTE regarding hardcoding: These calcs depend on cloud creation algo a lot */
9086 xs = CLOUD_XS(cloud_x1[i], cloud_y1[i], cloud_x2[i], cloud_y2[i], cloud_dsum[i]);
9087 xd = CLOUD_XD(cloud_x1[i], cloud_y1[i], cloud_x2[i], cloud_y2[i], cloud_dsum[i]);
9088 ys = CLOUD_YS(cloud_x1[i], cloud_y1[i], cloud_x2[i], cloud_y2[i], cloud_dsum[i]);
9089 yd = CLOUD_YD(cloud_x1[i], cloud_y1[i], cloud_x2[i], cloud_y2[i], cloud_dsum[i]);
9090 /* traverse all wild sectors that could maybe be affected or
9091 have been affected by this cloud, very roughly calculated
9092 (just a rectangle mask), fine check is done inside. */
9093 for (x = xs; x <= xd; x++)
9094 for (y = ys; y <= yd; y++) {
9095 /* skip sectors out of array bounds */
9096 if (x < 0 || x >= MAX_WILD_X || y < 0 || y >= MAX_WILD_Y) continue;
9097
9098 w_ptr = &wild_info[y][x];
9099 //if (Players[1] && Players[1]->wpos.wx == x && Players[1]->wpos.wy == y) s_printf("p1 here\n");
9100
9101 was_affected = FALSE;
9102 final_cloud_in_sector = TRUE; /* assume this cloud is the only one keeping the weather up here */
9103
9104 /* was the sector affected before erasing? */
9105 for (j = 0; j < 10; j++) {
9106 /* cloud occurs in this sector? so sector was already affected */
9107 if (w_ptr->cloud_idx[j] == i) {
9108 was_affected = TRUE;
9109 was_affected_idx = j;
9110 }
9111 else if (w_ptr->cloud_idx[j] != -1) final_cloud_in_sector = FALSE;
9112 }
9113 if (!was_affected) final_cloud_in_sector = FALSE;
9114
9115 if (was_affected) {
9116 /* erase cloud locally */
9117 w_ptr->cloud_idx[was_affected_idx] = -1;
9118 w_ptr->cloud_x1[was_affected_idx] = -9999; /* hack for client: client sees this as 'disabled' */
9119 #if 0
9120 /* meta data for Send_weather() */
9121 if (!w_ptr->cloud_updated[was_affected_idx]) {
9122 w_ptr->cloud_updated[was_affected_idx] = TRUE;
9123 w_ptr->clouds_to_update++;
9124 }
9125 #endif
9126
9127 /* if this was the last cloud in this sector,
9128 define (stop) weather situation accordingly */
9129 if (final_cloud_in_sector) {
9130 w_ptr->weather_type = 0; /* make weather 'run out slowly' */
9131 }
9132
9133 /* so, did this sector actually 'change' after all? */
9134 //sector_changed -> TRUE
9135 /* if the local situation did actually change,
9136 mark as updated for re-sending it to all players on it */
9137 w_ptr->weather_updated = TRUE;
9138 }
9139 }
9140 }
9141
9142 /* Create a new cloud with given index and worldmap _grid_ coords of its center
9143 This does not check whether there will be too many clouds! */
9144 void cloud_create(int i, int cx, int cy) {
9145 /* cloud dimensions: */
9146 int sx, sy, dx, dy, dsum;
9147 /* worldmap coords: */
9148 int x, y, xs, xd, ys, yd;
9149
9150 /* decide on initial size (largest ie horizontal diameter) */
9151 dsum = MAX_WID + rand_int(MAX_WID * 5);
9152 sx = cx - dsum / 4;
9153 sy = cy;
9154 dx = cx + dsum / 4;
9155 dy = cy;
9156
9157 xs = CLOUD_XS(sx, sy, dx, dy, dsum);
9158 xd = CLOUD_XD(sx, sy, dx, dy, dsum);
9159 ys = CLOUD_YS(sx, sy, dx, dy, dsum);
9160 yd = CLOUD_YD(sx, sy, dx, dy, dsum);
9161
9162 /* hack: not many clouds over deserts */
9163 for (x = xs - 1; x <= xd + 1; x++) {
9164 for (y = ys - 1; y <= yd + 1; y++) {
9165 if (in_bounds_wild(y, x) &&
9166 wild_info[y][x].type == WILD_DESERT)
9167 if (rand_int(10)) return;
9168
9169 /* leave loops */
9170 x = 9999;
9171 break;
9172 }
9173 }
9174
9175 /* we have one more cloud now */
9176 clouds++;
9177 /* create cloud by setting it's life time */
9178 cloud_dur[i] = 30 + rand_int(600); /* seconds */
9179 /* set horizontal diameter */
9180 cloud_dsum[i] = dsum;
9181 /* set location/destination */
9182 cloud_x1[i] = sx;
9183 cloud_y1[i] = sy;
9184 cloud_x2[i] = dx;
9185 cloud_y2[i] = dy;
9186 /* decide on growing/shrinking/constant cloud state */
9187 cloud_state[i] = rand_int(2) ? 1 : (rand_int(2) ? rand_int(100) : -rand_int(100));
9188 /* decide on initial movement */
9189 cloud_set_movement(i);
9190 /* add this cloud to its initial wild sector(s) */
9191 cloud_move(i, TRUE);
9192 }
9193
9194
9195 /* update players' local client-side weather if required.
9196 called each time by process_wild_weather, aka 1/s. */
9197 void local_weather_update(void) {
9198 int i;
9199
9200 /* HACK part 1: play random thunderclaps if player is receiving harsh weather.
9201 Note: this is synched to all players in the same worldmap sector,
9202 for consistency. :) */
9203 int thunderstorm, thunderclap = 999, vol = rand_int(86);
9204 thunderstorm = (turn / (cfg.fps * 3600)) % 6; /* n out of every 6 world map sector clusters have thunderstorms going */
9205 if (!(turn % (cfg.fps * 10))) thunderclap = rand_int(5); /* every 10s there is a 1 in 5 chance of thunderclap (in a thunderstorm area) */
9206
9207 /* update players' local client-side weather if required */
9208 for (i = 1; i <= NumPlayers; i++) {
9209 /* Skip non-connected players */
9210 if (Players[i]->conn == NOT_CONNECTED) continue;
9211 /* Skip players not on world surface - player_weather() actually checks this too though */
9212 if (Players[i]->wpos.wz) continue;
9213
9214 /* HACK part 2: if harsh weather, play random world-sector-synched thunderclaps */
9215 #if 0 /* debug */
9216 if (thunderclap == 0) {
9217 s_printf("p %d - w %d, t %d\n",
9218 ((Players[i]->wpos.wy + Players[i]->wpos.wx) / 5) % 6,
9219 thunderstorm,
9220 wild_info[Players[i]->wpos.wy][Players[i]->wpos.wx].weather_type);
9221 }
9222 #endif
9223 if (thunderclap == 0 &&
9224 wild_info[Players[i]->wpos.wy][Players[i]->wpos.wx].weather_type == 1 && /* no blizzards for now, just rainstorms */
9225 //wild_info[Players[i]->wpos.wy][Players[i]->wpos.wx].weather_wind &&
9226 ((Players[i]->wpos.wy + Players[i]->wpos.wx) / 5) % 6 == thunderstorm) {
9227 sound_vol(i, "thunder", NULL, SFX_TYPE_WEATHER, FALSE, 15 + (vol + Players[i]->wpos.wy + Players[i]->wpos.wx) % 86);
9228 }
9229
9230 /* no change in local situation? nothing to do then */
9231 if (!wild_info[Players[i]->wpos.wy][Players[i]->wpos.wx].weather_updated) continue;
9232 /* update player's local weather */
9233 #ifdef TEST_SERVER /* DEBUG */
9234 #if 0
9235 s_printf("updating weather for player %d.\n", i);
9236 #endif
9237 #endif
9238 player_weather(i, FALSE, TRUE, FALSE);
9239 }
9240 /* reclear 'weather_updated' flag after all players have been updated */
9241 for (i = 1; i <= NumPlayers; i++)
9242 wild_info[Players[i]->wpos.wy][Players[i]->wpos.wx].weather_updated = FALSE;
9243 }
9244 #endif /* !CLIENT_WEATHER_GLOBAL */
9245 #endif /* CLIENT_SIDE_WEATHER */
9246
9247 /* calculate slow-downs of running speed due to environmental circumstances / grid features - C. Blue
9248 Note: a.t.m. Terrain-related slowdowns take precedence over wind-related slowdowns, cancelling them. */
9249 void eff_running_speed(int *real_speed, player_type *p_ptr, cave_type *c_ptr) {
9250 #if 1 /* NEW_RUNNING_FEAT */
9251 if (!is_admin(p_ptr) && !p_ptr->ghost && !p_ptr->tim_wraith) {
9252 /* are we in fact running-levitating? */
9253 //if ((f_info[c_ptr->feat].flags1 & (FF1_CAN_LEVITATE | FF1_CAN_RUN)) && p_ptr->levitate) {
9254 if ((f_info[c_ptr->feat].flags1 & (FF1_CAN_LEVITATE | FF1_CAN_RUN))) {
9255 /* Allow level 50 druids to run at full speed */
9256 if (!(p_ptr->pclass == CLASS_DRUID && p_ptr->lev >= 50)) {
9257 if (f_info[c_ptr->feat].flags1 & FF1_SLOW_LEVITATING_1) *real_speed /= 2;
9258 if (f_info[c_ptr->feat].flags1 & FF1_SLOW_LEVITATING_2) *real_speed /= 4;
9259 }
9260 }
9261 /* or running-swimming? */
9262 else if ((c_ptr->feat == 84 || c_ptr->feat == 103 || c_ptr->feat == 174 || c_ptr->feat == 187) && p_ptr->can_swim) {
9263 /* Allow Aquatic players run/swim at full speed */
9264 if (!r_info[p_ptr->body_monster].flags7&RF7_AQUATIC) {
9265 if (f_info[c_ptr->feat].flags1 & FF1_SLOW_SWIMMING_1) *real_speed /= 2;
9266 if (f_info[c_ptr->feat].flags1 & FF1_SLOW_SWIMMING_2) *real_speed /= 4;
9267 }
9268 }
9269 /* or just normally running? */
9270 else {
9271 if (f_info[c_ptr->feat].flags1 & FF1_SLOW_RUNNING_1) *real_speed /= 2;
9272 if (f_info[c_ptr->feat].flags1 & FF1_SLOW_RUNNING_2) *real_speed /= 4;
9273 }
9274 }
9275 #endif
9276
9277 #if 0 /* enable? */
9278 #if defined CLIENT_SIDE_WEATHER && !defined CLIENT_WEATHER_GLOBAL
9279 { int wind, real_speed_vertical;
9280 /* hack: wind without rain doesn't count, since it might confuse the players */
9281 if (!wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_type) return;
9282
9283 real_speed_vertical = *real_speed;
9284 /* running against strong wind is slower :) - C. Blue */
9285 wind = wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_wind;
9286 if (!wind || *real_speed != cfg.running_speed) ;
9287 /* if no wind, or if we're already slowed down: nothing */
9288 else if (wind % 2) {
9289 /* west wind */
9290 if (p_ptr->find_current == 1 || p_ptr->find_current == 4 || p_ptr->find_current == 7)
9291 *real_speed = (*real_speed * (wind + 3)) / 10;
9292 } else {
9293 /* east wind */
9294 if (p_ptr->find_current == 3 || p_ptr->find_current == 6 || p_ptr->find_current == 9)
9295 *real_speed = (*real_speed * (wind + 6)) / 10;
9296 }
9297 /* also check vertical winds (which are only used for exactly this purpose here) */
9298 wind = wild_info[p_ptr->wpos.wy][p_ptr->wpos.wx].weather_wind_vertical;
9299 if (!wind || real_speed_vertical != cfg.running_speed) ;
9300 /* if no wind, or if we're already slowed down: nothing */
9301 else if (wind % 2) {
9302 /* west wind */
9303 if (p_ptr->find_current == 7 || p_ptr->find_current == 8 || p_ptr->find_current == 9)
9304 real_speed_vertical = (real_speed_vertical * (wind + 3)) / 10;
9305 } else {
9306 /* east wind */
9307 if (p_ptr->find_current == 1 || p_ptr->find_current == 2 || p_ptr->find_current == 3)
9308 real_speed_vertical = (real_speed_vertical * (wind + 6)) / 10;
9309 }
9310 if (real_speed_vertical < *real_speed) *real_speed = real_speed_vertical;
9311 }
9312 #endif
9313 #endif
9314 }
9315
9316 /* Initiates forced shutdown with all players getting recalled automatically.
9317 Added this for use within LUA files, for automatic seasonal event updating. - C. Blue */
9318 void timed_shutdown(int k, bool terminate) {
9319 int i;
9320
9321 // msg_admins(0, format("\377w* Shutting down in %d minutes *", k));
9322 if (terminate)
9323 msg_broadcast_format(0, "\374\377I*** \377RAutomatic recall and server maintenance shutdown in %d minute%s. \377I***", k, (k == 1) ? "" : "s");
9324 else
9325 msg_broadcast_format(0, "\374\377I*** \377RAutomatic recall and server restart in %d minute%s. \377I***", k, (k == 1) ? "" : "s");
9326
9327 for (i = 1; i <= NumPlayers; i++) {
9328 if (Players[i]->conn == NOT_CONNECTED) continue;
9329 if (Players[i]->paging) continue;
9330 Players[i]->paging = 2;
9331 }
9332
9333 cfg.runlevel = terminate ? 2042 : 2043;
9334 shutdown_recall_timer = k * 60;
9335
9336 /* hack: suppress duplicate message */
9337 if (k <= 1) shutdown_recall_state = 3;
9338 else if (k <= 5) shutdown_recall_state = 2;
9339 else if (k <= 15) shutdown_recall_state = 1;
9340 else shutdown_recall_state = 0;
9341
9342 s_printf("AUTOSHUTREC: %d minute(s).\n", k);
9343 }
9344
9345 int recall_depth_idx(struct worldpos *wpos, player_type *p_ptr) {
9346 int j;
9347
9348 /* cannot recall in 0,0? */
9349 if (!wpos->wx && !wpos->wy) return (-1);
9350
9351 /* no dungeon/tower here? */
9352 if (wpos->wz > 0 && !wild_info[wpos->wy][wpos->wx].tower) return (-1);
9353 if (wpos->wz <= 0 && !wild_info[wpos->wy][wpos->wx].dungeon) return (-1);/* assume basic recall prefers dungeon over tower */
9354
9355 for (j = 0; j < MAX_D_IDX * 2; j++) {
9356 /* it's a dungeon that's new to us - add it! */
9357 if (!p_ptr->max_depth_wx[j] && !p_ptr->max_depth_wy[j]) {
9358 p_ptr->max_depth_wx[j] = wpos->wx;
9359 p_ptr->max_depth_wy[j] = wpos->wy;
9360 p_ptr->max_depth_tower[j] = (wpos->wz > 0);
9361 return j;
9362 }
9363 /* check dungeons we've already been to */
9364 if (p_ptr->max_depth_wx[j] == wpos->wx &&
9365 p_ptr->max_depth_wy[j] == wpos->wy &&
9366 p_ptr->max_depth_tower[j] == (wpos->wz > 0))
9367 return j;
9368 }
9369 s_printf("p_ptr->max_depth[]: TOO MANY DUNGEONS ('%s',%d,%d,%d)!\n", p_ptr->name, wpos->wx, wpos->wy, wpos->wz);
9370 return (-1);
9371 }
9372 int get_recall_depth(struct worldpos *wpos, player_type *p_ptr) {
9373 int i = recall_depth_idx(wpos, p_ptr);
9374 if (i == -1) return 0;
9375 return p_ptr->max_depth[i];
9376 }
9377