1 /**
2 * @file objects.cpp
3 *
4 * Implementation of object functionality, interaction, spawning, loading, etc.
5 */
6 #include "all.h"
7 #include "options.h"
8
9 DEVILUTION_BEGIN_NAMESPACE
10
11 int trapid;
12 int trapdir;
13 BYTE *pObjCels[40];
14 char ObjFileList[40];
15 int objectactive[MAXOBJECTS];
16 /** Specifies the number of active objects. */
17 int nobjects;
18 int leverid;
19 int objectavail[MAXOBJECTS];
20 ObjectStruct object[MAXOBJECTS];
21 BOOL InitObjFlag;
22 BOOL LoadMapObjsFlag;
23 int numobjfiles;
24 int dword_6DE0E0;
25
26 /** Specifies the X-coordinate delta between barrels. */
27 int bxadd[8] = { -1, 0, 1, -1, 1, -1, 0, 1 };
28 /** Specifies the Y-coordinate delta between barrels. */
29 int byadd[8] = { -1, -1, -1, 0, 0, 1, 1, 1 };
30 /** Maps from shrine_id to shrine name. */
31 const char *const shrinestrs[] = {
32 "Mysterious",
33 "Hidden",
34 "Gloomy",
35 "Weird",
36 "Magical",
37 "Stone",
38 "Religious",
39 "Enchanted",
40 "Thaumaturgic",
41 "Fascinating",
42 "Cryptic",
43 "Magical",
44 "Eldritch",
45 "Eerie",
46 "Divine",
47 "Holy",
48 "Sacred",
49 "Spiritual",
50 "Spooky",
51 "Abandoned",
52 "Creepy",
53 "Quiet",
54 "Secluded",
55 "Ornate",
56 "Glimmering",
57 "Tainted",
58 "Oily",
59 "Glowing",
60 "Mendicant's",
61 "Sparkling",
62 "Town",
63 "Shimmering",
64 "Solar",
65 "Murphy's",
66 };
67 /** Specifies the minimum dungeon level on which each shrine will appear. */
68 char shrinemin[] = {
69 1, // Mysterious
70 1, // Hidden
71 1, // Gloomy
72 1, // Weird
73 1, // Magical
74 1, // Stone
75 1, // Religious
76 1, // Enchanted
77 1, // Thaumaturgic
78 1, // Fascinating
79 1, // Cryptic
80 1, // Magical
81 1, // Eldritch
82 1, // Eerie
83 1, // Divine
84 1, // Holy
85 1, // Sacred
86 1, // Spiritual
87 1, // Spooky
88 1, // Abandoned
89 1, // Creepy
90 1, // Quiet
91 1, // Secluded
92 1, // Ornate
93 1, // Glimmering
94 1, // Tainted
95 1, // Oily
96 1, // Glowing
97 1, // Mendicant's
98 1, // Sparkling
99 1, // Town
100 1, // Shimmering
101 1, // Solar,
102 1, // Murphy's
103 };
104 /** Specifies the maximum dungeon level on which each shrine will appear. */
105 char shrinemax[] = {
106 MAX_LVLS, // Mysterious
107 MAX_LVLS, // Hidden
108 MAX_LVLS, // Gloomy
109 MAX_LVLS, // Weird
110 MAX_LVLS, // Magical
111 MAX_LVLS, // Stone
112 MAX_LVLS, // Religious
113 8, // Enchanted
114 MAX_LVLS, // Thaumaturgic
115 MAX_LVLS, // Fascinating
116 MAX_LVLS, // Cryptic
117 MAX_LVLS, // Magical
118 MAX_LVLS, // Eldritch
119 MAX_LVLS, // Eerie
120 MAX_LVLS, // Divine
121 MAX_LVLS, // Holy
122 MAX_LVLS, // Sacred
123 MAX_LVLS, // Spiritual
124 MAX_LVLS, // Spooky
125 MAX_LVLS, // Abandoned
126 MAX_LVLS, // Creepy
127 MAX_LVLS, // Quiet
128 MAX_LVLS, // Secluded
129 MAX_LVLS, // Ornate
130 MAX_LVLS, // Glimmering
131 MAX_LVLS, // Tainted
132 MAX_LVLS, // Oily
133 MAX_LVLS, // Glowing
134 MAX_LVLS, // Mendicant's
135 MAX_LVLS, // Sparkling
136 MAX_LVLS, // Town
137 MAX_LVLS, // Shimmering
138 MAX_LVLS, // Solar,
139 MAX_LVLS, // Murphy's
140 };
141 /**
142 * Specifies the game type for which each shrine may appear.
143 * SHRINETYPE_ANY - 0 - sp & mp
144 * SHRINETYPE_SINGLE - 1 - sp only
145 * SHRINETYPE_MULTI - 2 - mp only
146 */
147
148 BYTE shrineavail[] = {
149 SHRINETYPE_ANY, // SHRINE_MYSTERIOUS
150 SHRINETYPE_ANY, // SHRINE_HIDDEN
151 SHRINETYPE_SINGLE, // SHRINE_GLOOMY
152 SHRINETYPE_SINGLE, // SHRINE_WEIRD
153 SHRINETYPE_ANY, // SHRINE_MAGICAL
154 SHRINETYPE_ANY, // SHRINE_STONE
155 SHRINETYPE_ANY, // SHRINE_RELIGIOUS
156 SHRINETYPE_ANY, // SHRINE_ENCHANTED
157 SHRINETYPE_SINGLE, // SHRINE_THAUMATURGIC
158 SHRINETYPE_ANY, // SHRINE_FASCINATING
159 SHRINETYPE_ANY, // SHRINE_CRYPTIC
160 SHRINETYPE_ANY, // SHRINE_MAGICAL2
161 SHRINETYPE_ANY, // SHRINE_ELDRITCH
162 SHRINETYPE_ANY, // SHRINE_EERIE
163 SHRINETYPE_ANY, // SHRINE_DIVINE
164 SHRINETYPE_ANY, // SHRINE_HOLY
165 SHRINETYPE_ANY, // SHRINE_SACRED
166 SHRINETYPE_ANY, // SHRINE_SPIRITUAL
167 SHRINETYPE_MULTI, // SHRINE_SPOOKY
168 SHRINETYPE_ANY, // SHRINE_ABANDONED
169 SHRINETYPE_ANY, // SHRINE_CREEPY
170 SHRINETYPE_ANY, // SHRINE_QUIET
171 SHRINETYPE_ANY, // SHRINE_SECLUDED
172 SHRINETYPE_ANY, // SHRINE_ORNATE
173 SHRINETYPE_ANY, // SHRINE_GLIMMERING
174 SHRINETYPE_MULTI, // SHRINE_TAINTED
175 SHRINETYPE_ANY, // SHRINE_OILY
176 SHRINETYPE_ANY, // SHRINE_GLOWING
177 SHRINETYPE_ANY, // SHRINE_MENDICANT
178 SHRINETYPE_ANY, // SHRINE_SPARKLING
179 SHRINETYPE_ANY, // SHRINE_TOWN
180 SHRINETYPE_ANY, // SHRINE_SHIMMERING
181 SHRINETYPE_SINGLE, // SHRINE_SOLAR
182 SHRINETYPE_ANY, // SHRINE_MURPHYS
183 };
184 /** Maps from book_id to book name. */
185 const char *const StoryBookName[] = {
186 "The Great Conflict",
187 "The Wages of Sin are War",
188 "The Tale of the Horadrim",
189 "The Dark Exile",
190 "The Sin War",
191 "The Binding of the Three",
192 "The Realms Beyond",
193 "Tale of the Three",
194 "The Black King",
195 "Journal: The Ensorcellment",
196 "Journal: The Meeting",
197 "Journal: The Tirade",
198 "Journal: His Power Grows",
199 "Journal: NA-KRUL",
200 "Journal: The End",
201 "A Spellbook",
202 };
203 /** Specifies the speech IDs of each dungeon type narrator book, for each player class. */
204 _speech_id StoryText[3][3] = {
205 { TEXT_BOOK11, TEXT_BOOK12, TEXT_BOOK13 },
206 { TEXT_BOOK21, TEXT_BOOK22, TEXT_BOOK23 },
207 { TEXT_BOOK31, TEXT_BOOK32, TEXT_BOOK33 }
208 };
209
InitObjectGFX()210 void InitObjectGFX()
211 {
212 BOOLEAN fileload[56];
213 char filestr[32];
214 int i, j;
215
216 memset(fileload, FALSE, sizeof(fileload));
217
218 int lvl = currlevel;
219 if (currlevel >= 21 && currlevel <= 24)
220 lvl -= 20;
221 else if (currlevel >= 17 && currlevel <= 20)
222 lvl -= 8;
223 for (i = 0; AllObjects[i].oload != -1; i++) {
224 if (AllObjects[i].oload == 1
225 && (int)lvl >= AllObjects[i].ominlvl
226 && (int)lvl <= AllObjects[i].omaxlvl) {
227 fileload[AllObjects[i].ofindex] = TRUE;
228 }
229 if (AllObjects[i].otheme != THEME_NONE) {
230 for (j = 0; j < numthemes; j++) {
231 if (themes[j].ttype == AllObjects[i].otheme)
232 fileload[AllObjects[i].ofindex] = TRUE;
233 }
234 }
235
236 if (AllObjects[i].oquest != -1) {
237 if (QuestStatus(AllObjects[i].oquest))
238 fileload[AllObjects[i].ofindex] = TRUE;
239 }
240 }
241
242 for (i = 0; i < 56; i++) {
243 if (fileload[i]) {
244 ObjFileList[numobjfiles] = i;
245 sprintf(filestr, "Objects\\%s.CEL", ObjMasterLoadList[i]);
246 if (currlevel >= 17 && currlevel < 21)
247 sprintf(filestr, "Objects\\%s.CEL", ObjHiveLoadList[i]);
248 else if (currlevel >= 21)
249 sprintf(filestr, "Objects\\%s.CEL", ObjCryptLoadList[i]);
250 pObjCels[numobjfiles] = LoadFileInMem(filestr, NULL);
251 numobjfiles++;
252 }
253 }
254 }
255
FreeObjectGFX()256 void FreeObjectGFX()
257 {
258 int i;
259
260 for (i = 0; i < numobjfiles; i++) {
261 MemFreeDbg(pObjCels[i]);
262 }
263 numobjfiles = 0;
264 }
265
RndLocOk(int xp,int yp)266 bool RndLocOk(int xp, int yp)
267 {
268 if (dMonster[xp][yp] != 0)
269 return FALSE;
270 if (dPlayer[xp][yp] != 0)
271 return FALSE;
272 if (dObject[xp][yp] != 0)
273 return FALSE;
274 if (dFlags[xp][yp] & BFLAG_POPULATED)
275 return FALSE;
276 if (nSolidTable[dPiece[xp][yp]])
277 return FALSE;
278 if (leveltype != DTYPE_CATHEDRAL || dPiece[xp][yp] <= 126 || dPiece[xp][yp] >= 144)
279 return TRUE;
280 return FALSE;
281 }
282
WallTrapLocOkK(int xp,int yp)283 static bool WallTrapLocOkK(int xp, int yp)
284 {
285 if (dFlags[xp][yp] & BFLAG_POPULATED)
286 return FALSE;
287
288 if (nTrapTable[dPiece[xp][yp]] != FALSE)
289 return TRUE;
290 else
291 return FALSE;
292 }
293
InitRndLocObj(int min,int max,int objtype)294 void InitRndLocObj(int min, int max, int objtype)
295 {
296 int i, xp, yp, numobjs;
297
298 numobjs = random_(139, max - min) + min;
299
300 for (i = 0; i < numobjs; i++) {
301 while (1) {
302 xp = random_(139, 80) + 16;
303 yp = random_(139, 80) + 16;
304 if (RndLocOk(xp - 1, yp - 1)
305 && RndLocOk(xp, yp - 1)
306 && RndLocOk(xp + 1, yp - 1)
307 && RndLocOk(xp - 1, yp)
308 && RndLocOk(xp, yp)
309 && RndLocOk(xp + 1, yp)
310 && RndLocOk(xp - 1, yp + 1)
311 && RndLocOk(xp, yp + 1)
312 && RndLocOk(xp + 1, yp + 1)) {
313 AddObject(objtype, xp, yp);
314 break;
315 }
316 }
317 }
318 }
319
InitRndLocBigObj(int min,int max,int objtype)320 void InitRndLocBigObj(int min, int max, int objtype)
321 {
322 int i, xp, yp, numobjs;
323
324 numobjs = random_(140, max - min) + min;
325 for (i = 0; i < numobjs; i++) {
326 while (1) {
327 xp = random_(140, 80) + 16;
328 yp = random_(140, 80) + 16;
329 if (RndLocOk(xp - 1, yp - 2)
330 && RndLocOk(xp, yp - 2)
331 && RndLocOk(xp + 1, yp - 2)
332 && RndLocOk(xp - 1, yp - 1)
333 && RndLocOk(xp, yp - 1)
334 && RndLocOk(xp + 1, yp - 1)
335 && RndLocOk(xp - 1, yp)
336 && RndLocOk(xp, yp)
337 && RndLocOk(xp + 1, yp)
338 && RndLocOk(xp - 1, yp + 1)
339 && RndLocOk(xp, yp + 1)
340 && RndLocOk(xp + 1, yp + 1)) {
341 AddObject(objtype, xp, yp);
342 break;
343 }
344 }
345 }
346 }
347
InitRndLocObj5x5(int min,int max,int objtype)348 void InitRndLocObj5x5(int min, int max, int objtype)
349 {
350 bool exit;
351 int xp, yp, numobjs, i, cnt, m, n;
352
353 numobjs = min + random_(139, max - min);
354 for (i = 0; i < numobjs; i++) {
355 cnt = 0;
356 exit = FALSE;
357 while (!exit) {
358 exit = TRUE;
359 xp = random_(139, 80) + 16;
360 yp = random_(139, 80) + 16;
361 for (n = -2; n <= 2; n++) {
362 for (m = -2; m <= 2; m++) {
363 if (!RndLocOk(xp + m, yp + n))
364 exit = FALSE;
365 }
366 }
367 if (!exit) {
368 cnt++;
369 if (cnt > 20000)
370 return;
371 }
372 }
373 AddObject(objtype, xp, yp);
374 }
375 }
376
ClrAllObjects()377 void ClrAllObjects()
378 {
379 int i;
380
381 memset(object, 0, sizeof(object));
382 nobjects = 0;
383 for (i = 0; i < MAXOBJECTS; i++) {
384 objectavail[i] = i;
385 }
386 memset(objectactive, 0, sizeof(objectactive));
387 trapdir = 0;
388 trapid = 1;
389 leverid = 1;
390 }
391
AddTortures()392 void AddTortures()
393 {
394 int ox, oy;
395
396 for (oy = 0; oy < MAXDUNY; oy++) {
397 for (ox = 0; ox < MAXDUNX; ox++) {
398 if (dPiece[ox][oy] == 367) {
399 AddObject(OBJ_TORTURE1, ox, oy + 1);
400 AddObject(OBJ_TORTURE3, ox + 2, oy - 1);
401 AddObject(OBJ_TORTURE2, ox, oy + 3);
402 AddObject(OBJ_TORTURE4, ox + 4, oy - 1);
403 AddObject(OBJ_TORTURE5, ox, oy + 5);
404 AddObject(OBJ_TNUDEM1, ox + 1, oy + 3);
405 AddObject(OBJ_TNUDEM2, ox + 4, oy + 5);
406 AddObject(OBJ_TNUDEM3, ox + 2, oy);
407 AddObject(OBJ_TNUDEM4, ox + 3, oy + 2);
408 AddObject(OBJ_TNUDEW1, ox + 2, oy + 4);
409 AddObject(OBJ_TNUDEW2, ox + 2, oy + 1);
410 AddObject(OBJ_TNUDEW3, ox + 4, oy + 2);
411 }
412 }
413 }
414 }
AddCandles()415 void AddCandles()
416 {
417 int tx, ty;
418
419 tx = quests[Q_PWATER]._qtx;
420 ty = quests[Q_PWATER]._qty;
421 AddObject(OBJ_STORYCANDLE, tx - 2, ty + 1);
422 AddObject(OBJ_STORYCANDLE, tx + 3, ty + 1);
423 AddObject(OBJ_STORYCANDLE, tx - 1, ty + 2);
424 AddObject(OBJ_STORYCANDLE, tx + 2, ty + 2);
425 }
426
AddBookLever(int lx1,int ly1,int lx2,int ly2,int x1,int y1,int x2,int y2,_speech_id msg)427 void AddBookLever(int lx1, int ly1, int lx2, int ly2, int x1, int y1, int x2, int y2, _speech_id msg)
428 {
429 bool exit;
430 int xp, yp, ob, cnt, m, n;
431
432 cnt = 0;
433 exit = FALSE;
434 while (!exit) {
435 exit = TRUE;
436 xp = random_(139, 80) + 16;
437 yp = random_(139, 80) + 16;
438 for (n = -2; n <= 2; n++) {
439 for (m = -2; m <= 2; m++) {
440 if (!RndLocOk(xp + m, yp + n))
441 exit = FALSE;
442 }
443 }
444 if (!exit) {
445 cnt++;
446 if (cnt > 20000)
447 return;
448 }
449 }
450
451 if (QuestStatus(Q_BLIND))
452 AddObject(OBJ_BLINDBOOK, xp, yp);
453 if (QuestStatus(Q_WARLORD))
454 AddObject(OBJ_STEELTOME, xp, yp);
455 if (QuestStatus(Q_BLOOD)) {
456 xp = 2 * setpc_x + 25;
457 yp = 2 * setpc_y + 40;
458 AddObject(OBJ_BLOODBOOK, xp, yp);
459 }
460 ob = dObject[xp][yp] - 1;
461 SetObjMapRange(ob, x1, y1, x2, y2, leverid);
462 SetBookMsg(ob, msg);
463 leverid++;
464 object[ob]._oVar6 = object[ob]._oAnimFrame + 1;
465 }
466
InitRndBarrels()467 void InitRndBarrels()
468 {
469 int numobjs; // number of groups of barrels to generate
470 int xp, yp;
471 _object_id o;
472 bool found;
473 int p; // regulates chance to stop placing barrels in current group
474 int dir;
475 int t; // number of tries of placing next barrel in current group
476 int c; // number of barrels in current group
477 int i;
478
479 numobjs = random_(143, 5) + 3;
480 for (i = 0; i < numobjs; i++) {
481 do {
482 xp = random_(143, 80) + 16;
483 yp = random_(143, 80) + 16;
484 } while (!RndLocOk(xp, yp));
485 o = (random_(143, 4) != 0) ? OBJ_BARREL : OBJ_BARRELEX;
486 AddObject(o, xp, yp);
487 found = TRUE;
488 p = 0;
489 c = 1;
490 while (random_(143, p) == 0 && found) {
491 t = 0;
492 found = FALSE;
493 while (TRUE) {
494 if (t >= 3)
495 break;
496 dir = random_(143, 8);
497 xp += bxadd[dir];
498 yp += byadd[dir];
499 found = RndLocOk(xp, yp);
500 t++;
501 if (found)
502 break;
503 }
504 if (found) {
505 o = (random_(143, 5) != 0) ? OBJ_BARREL : OBJ_BARRELEX;
506 AddObject(o, xp, yp);
507 c++;
508 }
509 p = c >> 1;
510 }
511 }
512 }
513
AddL1Objs(int x1,int y1,int x2,int y2)514 void AddL1Objs(int x1, int y1, int x2, int y2)
515 {
516 int i, j, pn;
517
518 for (j = y1; j < y2; j++) {
519 for (i = x1; i < x2; i++) {
520 pn = dPiece[i][j];
521 if (pn == 270)
522 AddObject(OBJ_L1LIGHT, i, j);
523 if (pn == 44 || pn == 51 || pn == 214)
524 AddObject(OBJ_L1LDOOR, i, j);
525 if (pn == 46 || pn == 56)
526 AddObject(OBJ_L1RDOOR, i, j);
527 }
528 }
529 }
530
add_crypt_objs(int x1,int y1,int x2,int y2)531 void add_crypt_objs(int x1, int y1, int x2, int y2)
532 {
533 int i, j, pn;
534
535 for (j = y1; j < y2; j++) {
536 for (i = x1; i < x2; i++) {
537 pn = dPiece[i][j];
538 if (pn == 77)
539 AddObject(OBJ_L1LDOOR, i, j);
540 if (pn == 80)
541 AddObject(OBJ_L1RDOOR, i, j);
542 }
543 }
544 }
545
AddL2Objs(int x1,int y1,int x2,int y2)546 void AddL2Objs(int x1, int y1, int x2, int y2)
547 {
548 int i, j, pn;
549
550 for (j = y1; j < y2; j++) {
551 for (i = x1; i < x2; i++) {
552 pn = dPiece[i][j];
553 if (pn == 13 || pn == 541)
554 AddObject(OBJ_L2LDOOR, i, j);
555 if (pn == 17 || pn == 542)
556 AddObject(OBJ_L2RDOOR, i, j);
557 }
558 }
559 }
560
AddL3Objs(int x1,int y1,int x2,int y2)561 void AddL3Objs(int x1, int y1, int x2, int y2)
562 {
563 int i, j, pn;
564
565 for (j = y1; j < y2; j++) {
566 for (i = x1; i < x2; i++) {
567 pn = dPiece[i][j];
568 if (pn == 531)
569 AddObject(OBJ_L3LDOOR, i, j);
570 if (pn == 534)
571 AddObject(OBJ_L3RDOOR, i, j);
572 }
573 }
574 }
575
TorchLocOK(int xp,int yp)576 bool TorchLocOK(int xp, int yp)
577 {
578 if (dFlags[xp][yp] & BFLAG_POPULATED)
579 return FALSE;
580 return TRUE;
581 }
582
AddL2Torches()583 void AddL2Torches()
584 {
585 int i, j, pn;
586
587 for (j = 0; j < MAXDUNY; j++) {
588 for (i = 0; i < MAXDUNX; i++) {
589 if (!TorchLocOK(i, j))
590 continue;
591
592 pn = dPiece[i][j];
593 if (pn == 1 && random_(145, 3) == 0)
594 AddObject(OBJ_TORCHL2, i, j);
595
596 if (pn == 5 && random_(145, 3) == 0)
597 AddObject(OBJ_TORCHR2, i, j);
598
599 if (pn == 37 && random_(145, 10) == 0 && dObject[i - 1][j] == 0)
600 AddObject(OBJ_TORCHL, i - 1, j);
601
602 if (pn == 41 && random_(145, 10) == 0 && dObject[i][j - 1] == 0)
603 AddObject(OBJ_TORCHR, i, j - 1);
604 }
605 }
606 }
607
AddObjTraps()608 void AddObjTraps()
609 {
610 char oi_trap, oi;
611 int i, j;
612 int xp, yp;
613 int rndv;
614
615 if (currlevel == 1)
616 rndv = 10;
617 if (currlevel >= 2)
618 rndv = 15;
619 if (currlevel >= 5)
620 rndv = 20;
621 if (currlevel >= 7)
622 rndv = 25;
623 for (j = 0; j < MAXDUNY; j++) {
624 for (i = 0; i < MAXDUNX; i++) {
625 if (dObject[i][j] <= 0 || random_(144, 100) >= rndv)
626 continue;
627
628 oi = dObject[i][j] - 1;
629 if (!AllObjects[object[oi]._otype].oTrapFlag)
630 continue;
631
632 if (random_(144, 2) == 0) {
633 xp = i - 1;
634 while (!nSolidTable[dPiece[xp][j]])
635 xp--;
636
637 if (!WallTrapLocOkK(xp, j) || i - xp <= 1)
638 continue;
639
640 AddObject(OBJ_TRAPL, xp, j);
641 oi_trap = dObject[xp][j] - 1;
642 object[oi_trap]._oVar1 = i;
643 object[oi_trap]._oVar2 = j;
644 object[oi]._oTrapFlag = TRUE;
645 } else {
646 yp = j - 1;
647 while (!nSolidTable[dPiece[i][yp]])
648 yp--;
649
650 if (!WallTrapLocOkK(i, yp) || j - yp <= 1)
651 continue;
652
653 AddObject(OBJ_TRAPR, i, yp);
654 oi_trap = dObject[i][yp] - 1;
655 object[oi_trap]._oVar1 = i;
656 object[oi_trap]._oVar2 = j;
657 object[oi]._oTrapFlag = TRUE;
658 }
659 }
660 }
661 }
662
AddChestTraps()663 void AddChestTraps()
664 {
665 int i, j;
666 char oi;
667
668 for (j = 0; j < MAXDUNY; j++) {
669 for (i = 0; i < MAXDUNX; i++) {
670 if (dObject[i][j] > 0) {
671 oi = dObject[i][j] - 1;
672 if (object[oi]._otype >= OBJ_CHEST1 && object[oi]._otype <= OBJ_CHEST3 && !object[oi]._oTrapFlag && random_(0, 100) < 10) {
673 object[oi]._otype += OBJ_TCHEST1 - OBJ_CHEST1;
674 object[oi]._oTrapFlag = TRUE;
675 if (leveltype == DTYPE_CATACOMBS) {
676 object[oi]._oVar4 = random_(0, 2);
677 } else {
678 object[oi]._oVar4 = random_(0, gbIsHellfire ? 6 : 3);
679 }
680 }
681 }
682 }
683 }
684 }
685
LoadMapObjects(BYTE * pMap,int startx,int starty,int x1,int y1,int w,int h,int leveridx)686 void LoadMapObjects(BYTE *pMap, int startx, int starty, int x1, int y1, int w, int h, int leveridx)
687 {
688 int rw, rh, i, j, oi, type;
689 BYTE *lm;
690 long mapoff;
691
692 LoadMapObjsFlag = TRUE;
693 InitObjFlag = TRUE;
694
695 lm = pMap;
696 rw = *lm;
697 lm += 2;
698 rh = *lm;
699 mapoff = (rw * rh + 1) * 2;
700 rw <<= 1;
701 rh <<= 1;
702 mapoff += rw * 2 * rh * 2;
703 lm += mapoff;
704
705 for (j = 0; j < rh; j++) {
706 for (i = 0; i < rw; i++) {
707 if (*lm) {
708 type = *lm;
709 AddObject(ObjTypeConv[type], startx + 16 + i, starty + 16 + j);
710 oi = ObjIndex(startx + 16 + i, starty + 16 + j);
711 SetObjMapRange(oi, x1, y1, x1 + w, y1 + h, leveridx);
712 }
713 lm += 2;
714 }
715 }
716 InitObjFlag = FALSE;
717 LoadMapObjsFlag = FALSE;
718 }
719
LoadMapObjs(BYTE * pMap,int startx,int starty)720 void LoadMapObjs(BYTE *pMap, int startx, int starty)
721 {
722 int rw, rh;
723 int i, j;
724 BYTE *lm;
725 long mapoff;
726
727 LoadMapObjsFlag = TRUE;
728 InitObjFlag = TRUE;
729 lm = pMap;
730 rw = *lm;
731 lm += 2;
732 rh = *lm;
733 mapoff = (rw * rh + 1) * 2;
734 rw <<= 1;
735 rh <<= 1;
736 mapoff += 2 * rw * rh * 2;
737 lm += mapoff;
738
739 for (j = 0; j < rh; j++) {
740 for (i = 0; i < rw; i++) {
741 if (*lm) {
742 AddObject(ObjTypeConv[*lm], startx + 16 + i, starty + 16 + j);
743 }
744 lm += 2;
745 }
746 }
747 InitObjFlag = FALSE;
748 LoadMapObjsFlag = FALSE;
749 }
750
AddDiabObjs()751 void AddDiabObjs()
752 {
753 BYTE *lpSetPiece;
754
755 lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab1.DUN", NULL);
756 LoadMapObjects(lpSetPiece, 2 * diabquad1x, 2 * diabquad1y, diabquad2x, diabquad2y, 11, 12, 1);
757 mem_free_dbg(lpSetPiece);
758 lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab2a.DUN", NULL);
759 LoadMapObjects(lpSetPiece, 2 * diabquad2x, 2 * diabquad2y, diabquad3x, diabquad3y, 11, 11, 2);
760 mem_free_dbg(lpSetPiece);
761 lpSetPiece = LoadFileInMem("Levels\\L4Data\\diab3a.DUN", NULL);
762 LoadMapObjects(lpSetPiece, 2 * diabquad3x, 2 * diabquad3y, diabquad4x, diabquad4y, 9, 9, 3);
763 mem_free_dbg(lpSetPiece);
764 }
765
objects_add_lv22(int s)766 void objects_add_lv22(int s)
767 {
768 bool exit;
769 int xp, yp, cnt, m, n;
770
771 cnt = 0;
772 exit = FALSE;
773 while (!exit) {
774 exit = TRUE;
775 xp = random_(139, 80) + 16;
776 yp = random_(139, 80) + 16;
777 for (n = -2; n <= 2; n++) {
778 for (m = -3; m <= 3; m++) {
779 if (!RndLocOk(xp + m, yp + n))
780 exit = FALSE;
781 }
782 }
783 if (!exit) {
784 cnt++;
785 if (cnt > 20000)
786 return;
787 }
788 }
789 objects_44D8C5(OBJ_STORYBOOK, s, xp, yp);
790 AddObject(OBJ_STORYCANDLE, xp - 2, yp + 1);
791 AddObject(OBJ_STORYCANDLE, xp - 2, yp);
792 AddObject(OBJ_STORYCANDLE, xp - 1, yp - 1);
793 AddObject(OBJ_STORYCANDLE, xp + 1, yp - 1);
794 AddObject(OBJ_STORYCANDLE, xp + 2, yp);
795 AddObject(OBJ_STORYCANDLE, xp + 2, yp + 1);
796 }
797
objects_add_lv24()798 void objects_add_lv24()
799 {
800 objects_rnd_454BEA();
801 switch (random_(0, 6)) {
802 case 0:
803 objects_454AF0(6, UberRow + 3, UberCol);
804 objects_454AF0(7, UberRow + 2, UberCol - 3);
805 objects_454AF0(8, UberRow + 2, UberCol + 2);
806 break;
807 case 1:
808 objects_454AF0(6, UberRow + 3, UberCol);
809 objects_454AF0(8, UberRow + 2, UberCol - 3);
810 objects_454AF0(7, UberRow + 2, UberCol + 2);
811 break;
812 case 2:
813 objects_454AF0(7, UberRow + 3, UberCol);
814 objects_454AF0(6, UberRow + 2, UberCol - 3);
815 objects_454AF0(8, UberRow + 2, UberCol + 2);
816 break;
817 case 3:
818 objects_454AF0(7, UberRow + 3, UberCol);
819 objects_454AF0(8, UberRow + 2, UberCol - 3);
820 objects_454AF0(6, UberRow + 2, UberCol + 2);
821 break;
822 case 4:
823 objects_454AF0(8, UberRow + 3, UberCol);
824 objects_454AF0(7, UberRow + 2, UberCol - 3);
825 objects_454AF0(6, UberRow + 2, UberCol + 2);
826 break;
827 case 5:
828 objects_454AF0(8, UberRow + 3, UberCol);
829 objects_454AF0(6, UberRow + 2, UberCol - 3);
830 objects_454AF0(7, UberRow + 2, UberCol + 2);
831 break;
832 }
833 }
834
objects_454AF0(int a1,int a2,int a3)835 void objects_454AF0(int a1, int a2, int a3)
836 {
837 objects_44D8C5(OBJ_STORYBOOK, a1, a2, a3);
838 }
839
AddStoryBooks()840 void AddStoryBooks()
841 {
842 int xp, yp, xx, yy;
843 int cnt;
844 bool done;
845
846 cnt = 0;
847 done = FALSE;
848 while (!done) {
849 done = TRUE;
850 xp = random_(139, 80) + 16;
851 yp = random_(139, 80) + 16;
852 for (yy = -2; yy <= 2; yy++) {
853 for (xx = -3; xx <= 3; xx++) {
854 if (!RndLocOk(xx + xp, yy + yp))
855 done = FALSE;
856 }
857 }
858 if (!done) {
859 cnt++;
860 if (cnt > 20000)
861 return;
862 }
863 }
864 AddObject(OBJ_STORYBOOK, xp, yp);
865 AddObject(OBJ_STORYCANDLE, xp - 2, yp + 1);
866 AddObject(OBJ_STORYCANDLE, xp - 2, yp);
867 AddObject(OBJ_STORYCANDLE, xp - 1, yp - 1);
868 AddObject(OBJ_STORYCANDLE, xp + 1, yp - 1);
869 AddObject(OBJ_STORYCANDLE, xp + 2, yp);
870 AddObject(OBJ_STORYCANDLE, xp + 2, yp + 1);
871 }
872
AddHookedBodies(int freq)873 void AddHookedBodies(int freq)
874 {
875 int i, j, ii, jj;
876
877 for (j = 0; j < DMAXY; j++) {
878 jj = 16 + j * 2;
879 for (i = 0; i < DMAXX; i++) {
880 ii = 16 + i * 2;
881 if (dungeon[i][j] != 1 && dungeon[i][j] != 2)
882 continue;
883 if (random_(0, freq) != 0)
884 continue;
885 if (!SkipThemeRoom(i, j))
886 continue;
887 if (dungeon[i][j] == 1 && dungeon[i + 1][j] == 6) {
888 switch (random_(0, 3)) {
889 case 0:
890 AddObject(OBJ_TORTURE1, ii + 1, jj);
891 break;
892 case 1:
893 AddObject(OBJ_TORTURE2, ii + 1, jj);
894 break;
895 case 2:
896 AddObject(OBJ_TORTURE5, ii + 1, jj);
897 break;
898 }
899 continue;
900 }
901 if (dungeon[i][j] == 2 && dungeon[i][j + 1] == 6) {
902 switch (random_(0, 2)) {
903 case 0:
904 AddObject(OBJ_TORTURE3, ii, jj);
905 break;
906 case 1:
907 AddObject(OBJ_TORTURE4, ii, jj);
908 break;
909 }
910 }
911 }
912 }
913 }
914
AddL4Goodies()915 void AddL4Goodies()
916 {
917 AddHookedBodies(6);
918 InitRndLocObj(2, 6, OBJ_TNUDEM1);
919 InitRndLocObj(2, 6, OBJ_TNUDEM2);
920 InitRndLocObj(2, 6, OBJ_TNUDEM3);
921 InitRndLocObj(2, 6, OBJ_TNUDEM4);
922 InitRndLocObj(2, 6, OBJ_TNUDEW1);
923 InitRndLocObj(2, 6, OBJ_TNUDEW2);
924 InitRndLocObj(2, 6, OBJ_TNUDEW3);
925 InitRndLocObj(2, 6, OBJ_DECAP);
926 InitRndLocObj(1, 3, OBJ_CAULDRON);
927 }
928
AddLazStand()929 void AddLazStand()
930 {
931 int xp, yp, xx, yy;
932 int cnt;
933 bool found;
934
935 cnt = 0;
936 found = FALSE;
937 while (!found) {
938 found = TRUE;
939 xp = random_(139, 80) + 16;
940 yp = random_(139, 80) + 16;
941 for (yy = -3; yy <= 3; yy++) {
942 for (xx = -2; xx <= 3; xx++) {
943 if (!RndLocOk(xp + xx, yp + yy))
944 found = FALSE;
945 }
946 }
947 if (!found) {
948 cnt++;
949 if (cnt > 10000) {
950 InitRndLocObj(1, 1, OBJ_LAZSTAND);
951 return;
952 }
953 }
954 }
955 AddObject(OBJ_LAZSTAND, xp, yp);
956 AddObject(OBJ_TNUDEM2, xp, yp + 2);
957 AddObject(OBJ_STORYCANDLE, xp + 1, yp + 2);
958 AddObject(OBJ_TNUDEM3, xp + 2, yp + 2);
959 AddObject(OBJ_TNUDEW1, xp, yp - 2);
960 AddObject(OBJ_STORYCANDLE, xp + 1, yp - 2);
961 AddObject(OBJ_TNUDEW2, xp + 2, yp - 2);
962 AddObject(OBJ_STORYCANDLE, xp - 1, yp - 1);
963 AddObject(OBJ_TNUDEW3, xp - 1, yp);
964 AddObject(OBJ_STORYCANDLE, xp - 1, yp + 1);
965 }
966
InitObjects()967 void InitObjects()
968 {
969 _speech_id sp_id;
970 BYTE *mem;
971
972 ClrAllObjects();
973 dword_6DE0E0 = 0;
974 if (currlevel == 16) {
975 AddDiabObjs();
976 } else {
977 InitObjFlag = TRUE;
978 AdvanceRndSeed();
979 if (currlevel == 9 && !gbIsMultiplayer)
980 AddSlainHero();
981 if (currlevel == quests[Q_MUSHROOM]._qlevel && quests[Q_MUSHROOM]._qactive == QUEST_INIT)
982 AddMushPatch();
983
984 if (currlevel == 4 || currlevel == 8 || currlevel == 12)
985 AddStoryBooks();
986 if (currlevel == 21) {
987 objects_add_lv22(1);
988 } else if (currlevel == 22) {
989 objects_add_lv22(2);
990 objects_add_lv22(3);
991 } else if (currlevel == 23) {
992 objects_add_lv22(4);
993 objects_add_lv22(5);
994 }
995 if (currlevel == 24) {
996 objects_add_lv24();
997 }
998 if (leveltype == DTYPE_CATHEDRAL) {
999 if (QuestStatus(Q_BUTCHER))
1000 AddTortures();
1001 if (QuestStatus(Q_PWATER))
1002 AddCandles();
1003 if (QuestStatus(Q_LTBANNER))
1004 AddObject(OBJ_SIGNCHEST, 2 * setpc_x + 26, 2 * setpc_y + 19);
1005 InitRndLocBigObj(10, 15, OBJ_SARC);
1006 if (currlevel >= 21)
1007 add_crypt_objs(0, 0, MAXDUNX, MAXDUNY);
1008 else
1009 AddL1Objs(0, 0, MAXDUNX, MAXDUNY);
1010 InitRndBarrels();
1011 }
1012 if (leveltype == DTYPE_CATACOMBS) {
1013 if (QuestStatus(Q_ROCK))
1014 InitRndLocObj5x5(1, 1, OBJ_STAND);
1015 if (QuestStatus(Q_SCHAMB))
1016 InitRndLocObj5x5(1, 1, OBJ_BOOK2R);
1017 AddL2Objs(0, 0, MAXDUNX, MAXDUNY);
1018 AddL2Torches();
1019 if (QuestStatus(Q_BLIND)) {
1020 if (plr[myplr]._pClass == PC_WARRIOR) {
1021 sp_id = TEXT_BLINDING;
1022 } else if (plr[myplr]._pClass == PC_ROGUE) {
1023 sp_id = TEXT_RBLINDING;
1024 } else if (plr[myplr]._pClass == PC_SORCERER) {
1025 sp_id = TEXT_MBLINDING;
1026 } else if (plr[myplr]._pClass == PC_MONK) {
1027 sp_id = TEXT_HBLINDING;
1028 } else if (plr[myplr]._pClass == PC_BARD) {
1029 sp_id = TEXT_BBLINDING;
1030 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
1031 sp_id = TEXT_BLINDING;
1032 }
1033 quests[Q_BLIND]._qmsg = sp_id;
1034 AddBookLever(0, 0, MAXDUNX, MAXDUNY, setpc_x, setpc_y, setpc_w + setpc_x + 1, setpc_h + setpc_y + 1, sp_id);
1035 mem = LoadFileInMem("Levels\\L2Data\\Blind2.DUN", NULL);
1036 LoadMapObjs(mem, 2 * setpc_x, 2 * setpc_y);
1037 mem_free_dbg(mem);
1038 }
1039 if (QuestStatus(Q_BLOOD)) {
1040 if (plr[myplr]._pClass == PC_WARRIOR) {
1041 sp_id = TEXT_BLOODY;
1042 } else if (plr[myplr]._pClass == PC_ROGUE) {
1043 sp_id = TEXT_RBLOODY;
1044 } else if (plr[myplr]._pClass == PC_SORCERER) {
1045 sp_id = TEXT_MBLOODY;
1046 } else if (plr[myplr]._pClass == PC_MONK) {
1047 sp_id = TEXT_HBLOODY;
1048 } else if (plr[myplr]._pClass == PC_BARD) {
1049 sp_id = TEXT_BBLOODY;
1050 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
1051 sp_id = TEXT_BLOODY;
1052 }
1053 quests[Q_BLOOD]._qmsg = sp_id;
1054 AddBookLever(0, 0, MAXDUNX, MAXDUNY, setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7, sp_id);
1055 AddObject(OBJ_PEDISTAL, 2 * setpc_x + 25, 2 * setpc_y + 32);
1056 }
1057 InitRndBarrels();
1058 }
1059 if (leveltype == DTYPE_CAVES) {
1060 AddL3Objs(0, 0, MAXDUNX, MAXDUNY);
1061 InitRndBarrels();
1062 }
1063 if (leveltype == DTYPE_HELL) {
1064 if (QuestStatus(Q_WARLORD)) {
1065 if (plr[myplr]._pClass == PC_WARRIOR) {
1066 sp_id = TEXT_BLOODWAR;
1067 } else if (plr[myplr]._pClass == PC_ROGUE) {
1068 sp_id = TEXT_RBLOODWAR;
1069 } else if (plr[myplr]._pClass == PC_SORCERER) {
1070 sp_id = TEXT_MBLOODWAR;
1071 } else if (plr[myplr]._pClass == PC_MONK) {
1072 sp_id = TEXT_HBLOODWAR;
1073 } else if (plr[myplr]._pClass == PC_BARD) {
1074 sp_id = TEXT_BBLOODWAR;
1075 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
1076 sp_id = TEXT_BLOODWAR;
1077 }
1078 quests[Q_WARLORD]._qmsg = sp_id;
1079 AddBookLever(0, 0, MAXDUNX, MAXDUNY, setpc_x, setpc_y, setpc_x + setpc_w, setpc_y + setpc_h, sp_id);
1080 mem = LoadFileInMem("Levels\\L4Data\\Warlord.DUN", NULL);
1081 LoadMapObjs(mem, 2 * setpc_x, 2 * setpc_y);
1082 mem_free_dbg(mem);
1083 }
1084 if (QuestStatus(Q_BETRAYER) && !gbIsMultiplayer)
1085 AddLazStand();
1086 InitRndBarrels();
1087 AddL4Goodies();
1088 }
1089 InitRndLocObj(5, 10, OBJ_CHEST1);
1090 InitRndLocObj(3, 6, OBJ_CHEST2);
1091 InitRndLocObj(1, 5, OBJ_CHEST3);
1092 if (leveltype != DTYPE_HELL)
1093 AddObjTraps();
1094 if (leveltype > DTYPE_CATHEDRAL)
1095 AddChestTraps();
1096 InitObjFlag = FALSE;
1097 }
1098 }
1099
SetMapObjects(BYTE * pMap,int startx,int starty)1100 void SetMapObjects(BYTE *pMap, int startx, int starty)
1101 {
1102 int rw, rh;
1103 int i, j;
1104 BYTE *lm, *h;
1105 long mapoff;
1106 int fileload[56];
1107 char filestr[32];
1108
1109 ClrAllObjects();
1110 for (i = 0; i < 56; i++)
1111 fileload[i] = FALSE;
1112 InitObjFlag = TRUE;
1113
1114 for (i = 0; AllObjects[i].oload != -1; i++) {
1115 if (AllObjects[i].oload == 1 && leveltype == AllObjects[i].olvltype)
1116 fileload[AllObjects[i].ofindex] = TRUE;
1117 }
1118
1119 lm = pMap;
1120 rw = *lm;
1121 lm += 2;
1122 rh = *lm;
1123 mapoff = (rw * rh + 1) * 2;
1124 rw <<= 1;
1125 rh <<= 1;
1126 mapoff += 2 * rw * rh * 2;
1127 lm += mapoff;
1128 h = lm;
1129
1130 for (j = 0; j < rh; j++) {
1131 for (i = 0; i < rw; i++) {
1132 if (*lm) {
1133 fileload[AllObjects[ObjTypeConv[*lm]].ofindex] = TRUE;
1134 }
1135 lm += 2;
1136 }
1137 }
1138
1139 for (i = 0; i < 56; i++) {
1140 if (!fileload[i])
1141 continue;
1142
1143 ObjFileList[numobjfiles] = i;
1144 sprintf(filestr, "Objects\\%s.CEL", ObjMasterLoadList[i]);
1145 pObjCels[numobjfiles] = LoadFileInMem(filestr, NULL);
1146 numobjfiles++;
1147 }
1148
1149 lm = h;
1150 for (j = 0; j < rh; j++) {
1151 for (i = 0; i < rw; i++) {
1152 if (*lm)
1153 AddObject(ObjTypeConv[*lm], startx + 16 + i, starty + 16 + j);
1154 lm += 2;
1155 }
1156 }
1157 InitObjFlag = FALSE;
1158 }
1159
DeleteObject_(int oi,int i)1160 void DeleteObject_(int oi, int i)
1161 {
1162 int ox, oy;
1163
1164 ox = object[oi]._ox;
1165 oy = object[oi]._oy;
1166 dObject[ox][oy] = 0;
1167 objectavail[-nobjects + MAXOBJECTS] = oi;
1168 nobjects--;
1169 if (nobjects > 0 && i != nobjects)
1170 objectactive[i] = objectactive[nobjects];
1171 }
1172
SetupObject(int i,int x,int y,int ot)1173 void SetupObject(int i, int x, int y, int ot)
1174 {
1175 int ofi;
1176 int j;
1177
1178 object[i]._otype = ot;
1179 ofi = AllObjects[ot].ofindex;
1180 object[i]._ox = x;
1181 object[i]._oy = y;
1182 j = 0;
1183 while (ObjFileList[j] != ofi) {
1184 j++;
1185 }
1186 object[i]._oAnimData = pObjCels[j];
1187 object[i]._oAnimFlag = AllObjects[ot].oAnimFlag;
1188 if (AllObjects[ot].oAnimFlag) {
1189 object[i]._oAnimDelay = AllObjects[ot].oAnimDelay;
1190 object[i]._oAnimCnt = random_(146, AllObjects[ot].oAnimDelay);
1191 object[i]._oAnimLen = AllObjects[ot].oAnimLen;
1192 object[i]._oAnimFrame = random_(146, AllObjects[ot].oAnimLen - 1) + 1;
1193 } else {
1194 object[i]._oAnimDelay = 1000;
1195 object[i]._oAnimCnt = 0;
1196 object[i]._oAnimLen = AllObjects[ot].oAnimLen;
1197 object[i]._oAnimFrame = AllObjects[ot].oAnimDelay;
1198 }
1199 object[i]._oAnimWidth = AllObjects[ot].oAnimWidth;
1200 object[i]._oSolidFlag = AllObjects[ot].oSolidFlag;
1201 object[i]._oMissFlag = AllObjects[ot].oMissFlag;
1202 object[i]._oLight = AllObjects[ot].oLightFlag;
1203 object[i]._oDelFlag = FALSE;
1204 object[i]._oBreak = AllObjects[ot].oBreak;
1205 object[i]._oSelFlag = AllObjects[ot].oSelFlag;
1206 object[i]._oPreFlag = FALSE;
1207 object[i]._oTrapFlag = FALSE;
1208 object[i]._oDoorFlag = FALSE;
1209 }
1210
SetObjMapRange(int i,int x1,int y1,int x2,int y2,int v)1211 void SetObjMapRange(int i, int x1, int y1, int x2, int y2, int v)
1212 {
1213 object[i]._oVar1 = x1;
1214 object[i]._oVar2 = y1;
1215 object[i]._oVar3 = x2;
1216 object[i]._oVar4 = y2;
1217 object[i]._oVar8 = v;
1218 }
1219
SetBookMsg(int i,_speech_id msg)1220 void SetBookMsg(int i, _speech_id msg)
1221 {
1222 object[i]._oVar7 = msg;
1223 }
1224
AddL1Door(int i,int x,int y,int ot)1225 void AddL1Door(int i, int x, int y, int ot)
1226 {
1227 object[i]._oDoorFlag = TRUE;
1228 if (ot == 1) {
1229 object[i]._oVar1 = dPiece[x][y];
1230 object[i]._oVar2 = dPiece[x][y - 1];
1231 } else {
1232 object[i]._oVar1 = dPiece[x][y];
1233 object[i]._oVar2 = dPiece[x - 1][y];
1234 }
1235 object[i]._oVar4 = 0;
1236 }
1237
AddSCambBook(int i)1238 void AddSCambBook(int i)
1239 {
1240 object[i]._oVar1 = setpc_x;
1241 object[i]._oVar2 = setpc_y;
1242 object[i]._oVar3 = setpc_w + setpc_x + 1;
1243 object[i]._oVar4 = setpc_h + setpc_y + 1;
1244 object[i]._oVar6 = object[i]._oAnimFrame + 1;
1245 }
1246
AddChest(int i,int t)1247 void AddChest(int i, int t)
1248 {
1249 if (random_(147, 2) == 0)
1250 object[i]._oAnimFrame += 3;
1251 object[i]._oRndSeed = AdvanceRndSeed();
1252 switch (t) {
1253 case OBJ_CHEST1:
1254 case OBJ_TCHEST1:
1255 if (setlevel) {
1256 object[i]._oVar1 = 1;
1257 break;
1258 }
1259 object[i]._oVar1 = random_(147, 2);
1260 break;
1261 case OBJ_TCHEST2:
1262 case OBJ_CHEST2:
1263 if (setlevel) {
1264 object[i]._oVar1 = 2;
1265 break;
1266 }
1267 object[i]._oVar1 = random_(147, 3);
1268 break;
1269 case OBJ_TCHEST3:
1270 case OBJ_CHEST3:
1271 if (setlevel) {
1272 object[i]._oVar1 = 3;
1273 break;
1274 }
1275 object[i]._oVar1 = random_(147, 4);
1276 break;
1277 }
1278 object[i]._oVar2 = random_(147, 8);
1279 }
1280
AddL2Door(int i,int x,int y,int ot)1281 void AddL2Door(int i, int x, int y, int ot)
1282 {
1283 object[i]._oDoorFlag = TRUE;
1284 if (ot == OBJ_L2LDOOR)
1285 ObjSetMicro(x, y, 538);
1286 else
1287 ObjSetMicro(x, y, 540);
1288 dSpecial[x][y] = 0;
1289 object[i]._oVar4 = 0;
1290 }
1291
AddL3Door(int i,int x,int y,int ot)1292 void AddL3Door(int i, int x, int y, int ot)
1293 {
1294 object[i]._oDoorFlag = TRUE;
1295 if (ot == OBJ_L3LDOOR)
1296 ObjSetMicro(x, y, 531);
1297 else
1298 ObjSetMicro(x, y, 534);
1299 object[i]._oVar4 = 0;
1300 }
1301
AddSarc(int i)1302 void AddSarc(int i)
1303 {
1304 dObject[object[i]._ox][object[i]._oy - 1] = -(i + 1);
1305 object[i]._oVar1 = random_(153, 10);
1306 object[i]._oRndSeed = AdvanceRndSeed();
1307 if (object[i]._oVar1 >= 8)
1308 object[i]._oVar2 = PreSpawnSkeleton();
1309 }
1310
AddFlameTrap(int i)1311 void AddFlameTrap(int i)
1312 {
1313 object[i]._oVar1 = trapid;
1314 object[i]._oVar2 = 0;
1315 object[i]._oVar3 = trapdir;
1316 object[i]._oVar4 = 0;
1317 }
1318
AddFlameLvr(int i)1319 void AddFlameLvr(int i)
1320 {
1321 object[i]._oVar1 = trapid;
1322 object[i]._oVar2 = MIS_FLAMEC;
1323 }
1324
AddTrap(int i,int ot)1325 void AddTrap(int i, int ot)
1326 {
1327 int mt;
1328
1329 mt = currlevel / 3 + 1;
1330 if (currlevel > 16) {
1331 mt = (currlevel - 4) / 3 + 1;
1332 }
1333 if (currlevel > 20) {
1334 mt = (currlevel - 8) / 3 + 1;
1335 }
1336 mt = random_(148, mt);
1337 if (mt == 0)
1338 object[i]._oVar3 = MIS_ARROW;
1339 if (mt == 1)
1340 object[i]._oVar3 = MIS_FIREBOLT;
1341 if (mt == 2)
1342 object[i]._oVar3 = MIS_LIGHTCTRL;
1343 object[i]._oVar4 = 0;
1344 }
1345
AddObjLight(int i,int r)1346 void AddObjLight(int i, int r)
1347 {
1348 if (InitObjFlag) {
1349 DoLighting(object[i]._ox, object[i]._oy, r, -1);
1350 object[i]._oVar1 = -1;
1351 } else {
1352 object[i]._oVar1 = 0;
1353 }
1354 }
1355
AddBarrel(int i,int t)1356 void AddBarrel(int i, int t)
1357 {
1358 object[i]._oVar1 = 0;
1359 object[i]._oRndSeed = AdvanceRndSeed();
1360 object[i]._oVar2 = (t == OBJ_BARRELEX) ? 0 : random_(149, 10);
1361 object[i]._oVar3 = random_(149, 3);
1362
1363 if (object[i]._oVar2 >= 8)
1364 object[i]._oVar4 = PreSpawnSkeleton();
1365 }
1366
AddShrine(int i)1367 void AddShrine(int i)
1368 {
1369 int val;
1370 bool slist[NUM_SHRINETYPE];
1371 int j;
1372 object[i]._oPreFlag = TRUE;
1373
1374 int shrines = gbIsHellfire ? NUM_SHRINETYPE : 26;
1375
1376 for (j = 0; j < shrines; j++) {
1377 slist[j] = currlevel >= shrinemin[j] && currlevel <= shrinemax[j];
1378 if (gbIsMultiplayer && shrineavail[j] == 1) {
1379 slist[j] = false;
1380 } else if (!gbIsMultiplayer && shrineavail[j] == 2) {
1381 slist[j] = false;
1382 }
1383 }
1384 do {
1385 val = random_(150, shrines);
1386 } while (!slist[val]);
1387
1388 object[i]._oVar1 = val;
1389 if (random_(150, 2) != 0) {
1390 object[i]._oAnimFrame = 12;
1391 object[i]._oAnimLen = 22;
1392 }
1393 }
1394
AddBookcase(int i)1395 void AddBookcase(int i)
1396 {
1397 object[i]._oRndSeed = AdvanceRndSeed();
1398 object[i]._oPreFlag = TRUE;
1399 }
1400
AddBookstand(int i)1401 void AddBookstand(int i)
1402 {
1403 object[i]._oRndSeed = AdvanceRndSeed();
1404 }
1405
AddBloodFtn(int i)1406 void AddBloodFtn(int i)
1407 {
1408 object[i]._oRndSeed = AdvanceRndSeed();
1409 }
1410
AddPurifyingFountain(int i)1411 void AddPurifyingFountain(int i)
1412 {
1413 int ox, oy;
1414
1415 ox = object[i]._ox;
1416 oy = object[i]._oy;
1417 dObject[ox][oy - 1] = -(i + 1);
1418 dObject[ox - 1][oy] = -(i + 1);
1419 dObject[ox - 1][oy - 1] = -(i + 1);
1420 object[i]._oRndSeed = AdvanceRndSeed();
1421 }
1422
AddArmorStand(int i)1423 void AddArmorStand(int i)
1424 {
1425 if (!armorFlag) {
1426 object[i]._oAnimFlag = 2;
1427 object[i]._oSelFlag = 0;
1428 }
1429
1430 object[i]._oRndSeed = AdvanceRndSeed();
1431 }
1432
AddGoatShrine(int i)1433 void AddGoatShrine(int i)
1434 {
1435 object[i]._oRndSeed = AdvanceRndSeed();
1436 }
1437
AddCauldron(int i)1438 void AddCauldron(int i)
1439 {
1440 object[i]._oRndSeed = AdvanceRndSeed();
1441 }
1442
AddMurkyFountain(int i)1443 void AddMurkyFountain(int i)
1444 {
1445 int ox, oy;
1446
1447 ox = object[i]._ox;
1448 oy = object[i]._oy;
1449 dObject[ox][oy - 1] = -(i + 1);
1450 dObject[ox - 1][oy] = -(i + 1);
1451 dObject[ox - 1][oy - 1] = -(i + 1);
1452 object[i]._oRndSeed = AdvanceRndSeed();
1453 }
1454
AddTearFountain(int i)1455 void AddTearFountain(int i)
1456 {
1457 object[i]._oRndSeed = AdvanceRndSeed();
1458 }
1459
AddDecap(int i)1460 void AddDecap(int i)
1461 {
1462 object[i]._oRndSeed = AdvanceRndSeed();
1463 object[i]._oAnimFrame = random_(151, 8) + 1;
1464 object[i]._oPreFlag = TRUE;
1465 }
1466
AddVilebook(int i)1467 void AddVilebook(int i)
1468 {
1469 if (setlevel && setlvlnum == SL_VILEBETRAYER) {
1470 object[i]._oAnimFrame = 4;
1471 }
1472 }
1473
AddMagicCircle(int i)1474 void AddMagicCircle(int i)
1475 {
1476 object[i]._oRndSeed = AdvanceRndSeed();
1477 object[i]._oPreFlag = TRUE;
1478 object[i]._oVar6 = 0;
1479 object[i]._oVar5 = 1;
1480 }
1481
AddBrnCross(int i)1482 void AddBrnCross(int i)
1483 {
1484 object[i]._oRndSeed = AdvanceRndSeed();
1485 }
1486
AddPedistal(int i)1487 void AddPedistal(int i)
1488 {
1489 object[i]._oVar1 = setpc_x;
1490 object[i]._oVar2 = setpc_y;
1491 object[i]._oVar3 = setpc_x + setpc_w;
1492 object[i]._oVar4 = setpc_y + setpc_h;
1493 object[i]._oVar6 = 0;
1494 }
1495
AddStoryBook(int i)1496 void AddStoryBook(int i)
1497 {
1498 SetRndSeed(glSeedTbl[16]);
1499
1500 object[i]._oVar1 = random_(0, 3);
1501 if (currlevel == 4)
1502 object[i]._oVar2 = StoryText[object[i]._oVar1][0];
1503 else if (currlevel == 8)
1504 object[i]._oVar2 = StoryText[object[i]._oVar1][1];
1505 else if (currlevel == 12)
1506 object[i]._oVar2 = StoryText[object[i]._oVar1][2];
1507 object[i]._oVar3 = (currlevel >> 2) + 3 * object[i]._oVar1 - 1;
1508 object[i]._oAnimFrame = 5 - 2 * object[i]._oVar1;
1509 object[i]._oVar4 = object[i]._oAnimFrame + 1;
1510 }
1511
AddWeaponRack(int i)1512 void AddWeaponRack(int i)
1513 {
1514 if (!weaponFlag) {
1515 object[i]._oAnimFlag = 2;
1516 object[i]._oSelFlag = 0;
1517 }
1518 object[i]._oRndSeed = AdvanceRndSeed();
1519 }
1520
AddTorturedBody(int i)1521 void AddTorturedBody(int i)
1522 {
1523 object[i]._oRndSeed = AdvanceRndSeed();
1524 object[i]._oAnimFrame = random_(0, 4) + 1;
1525 object[i]._oPreFlag = TRUE;
1526 }
1527
GetRndObjLoc(int randarea,int * xx,int * yy)1528 void GetRndObjLoc(int randarea, int *xx, int *yy)
1529 {
1530 bool failed;
1531 int i, j, tries;
1532
1533 if (randarea == 0)
1534 return;
1535
1536 tries = 0;
1537 while (1) {
1538 tries++;
1539 if (tries > 1000 && randarea > 1)
1540 randarea--;
1541 *xx = random_(0, MAXDUNX);
1542 *yy = random_(0, MAXDUNY);
1543 failed = FALSE;
1544 for (i = 0; i < randarea && !failed; i++) {
1545 for (j = 0; j < randarea && !failed; j++) {
1546 failed = !RndLocOk(i + *xx, j + *yy);
1547 }
1548 }
1549 if (!failed)
1550 break;
1551 }
1552 }
1553
AddMushPatch()1554 void AddMushPatch()
1555 {
1556 int i;
1557 int y, x;
1558
1559 if (nobjects < MAXOBJECTS) {
1560 i = objectavail[0];
1561 GetRndObjLoc(5, &x, &y);
1562 dObject[x + 1][y + 1] = -(i + 1);
1563 dObject[x + 2][y + 1] = -(i + 1);
1564 dObject[x + 1][y + 2] = -(i + 1);
1565 AddObject(OBJ_MUSHPATCH, x + 2, y + 2);
1566 }
1567 }
1568
AddSlainHero()1569 void AddSlainHero()
1570 {
1571 int x, y;
1572
1573 GetRndObjLoc(5, &x, &y);
1574 AddObject(OBJ_SLAINHERO, x + 2, y + 2);
1575 }
1576
objects_44D8C5(int ot,int v2,int ox,int oy)1577 void objects_44D8C5(int ot, int v2, int ox, int oy)
1578 {
1579 int oi;
1580
1581 if (nobjects >= MAXOBJECTS)
1582 return;
1583
1584 oi = objectavail[0];
1585 objectavail[0] = objectavail[MAXOBJECTS - 1 - nobjects];
1586 objectactive[nobjects] = oi;
1587 dObject[ox][oy] = oi + 1;
1588 SetupObject(oi, ox, oy, ot);
1589 objects_44DA68(oi, v2);
1590 object[oi]._oAnimWidth2 = (object[oi]._oAnimWidth - 64) >> 1;
1591 nobjects++;
1592 }
1593
objects_44DA68(int i,int a2)1594 void objects_44DA68(int i, int a2)
1595 {
1596 int v8, v9;
1597 if (a2 > 5) {
1598 object[i]._oVar8 = a2;
1599 switch (a2) {
1600 case 6:
1601 if (plr[myplr]._pClass == PC_WARRIOR) {
1602 object[i]._oVar2 = TEXT_BOOKA;
1603 } else if (plr[myplr]._pClass == PC_ROGUE) {
1604 object[i]._oVar2 = TEXT_RBOOKA;
1605 } else if (plr[myplr]._pClass == PC_SORCERER) {
1606 object[i]._oVar2 = TEXT_MBOOKA;
1607 } else if (plr[myplr]._pClass == PC_MONK) {
1608 object[i]._oVar2 = TEXT_OBOOKA;
1609 } else if (plr[myplr]._pClass == PC_BARD) {
1610 object[i]._oVar2 = TEXT_BBOOKA;
1611 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
1612 object[i]._oVar2 = TEXT_BOOKA;
1613 }
1614 break;
1615 case 7:
1616 if (plr[myplr]._pClass == PC_WARRIOR) {
1617 object[i]._oVar2 = TEXT_BOOKB;
1618 } else if (plr[myplr]._pClass == PC_ROGUE) {
1619 object[i]._oVar2 = TEXT_RBOOKB;
1620 } else if (plr[myplr]._pClass == PC_SORCERER) {
1621 object[i]._oVar2 = TEXT_MBOOKB;
1622 } else if (plr[myplr]._pClass == PC_MONK) {
1623 object[i]._oVar2 = TEXT_OBOOKB;
1624 } else if (plr[myplr]._pClass == PC_BARD) {
1625 object[i]._oVar2 = TEXT_BBOOKB;
1626 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
1627 object[i]._oVar2 = TEXT_BOOKB;
1628 }
1629 break;
1630 case 8:
1631 if (plr[myplr]._pClass == PC_WARRIOR) {
1632 object[i]._oVar2 = TEXT_BOOKC;
1633 } else if (plr[myplr]._pClass == PC_ROGUE) {
1634 object[i]._oVar2 = TEXT_RBOOKC;
1635 } else if (plr[myplr]._pClass == PC_SORCERER) {
1636 object[i]._oVar2 = TEXT_MBOOKC;
1637 } else if (plr[myplr]._pClass == PC_MONK) {
1638 object[i]._oVar2 = TEXT_OBOOKC;
1639 } else if (plr[myplr]._pClass == PC_BARD) {
1640 object[i]._oVar2 = TEXT_BBOOKC;
1641 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
1642 object[i]._oVar2 = TEXT_BOOKC;
1643 }
1644 break;
1645 }
1646 object[i]._oVar1 = 1;
1647 object[i]._oVar3 = 15;
1648 v8 = 2 * object[i]._oVar1;
1649 object[i]._oAnimFrame = 5 - v8;
1650 object[i]._oVar4 = object[i]._oAnimFrame + 1;
1651 } else {
1652
1653 object[i]._oVar1 = 1;
1654 object[i]._oVar2 = a2 + TEXT_SKLJRN;
1655 object[i]._oVar3 = a2 + 9;
1656 v9 = 2 * object[i]._oVar1;
1657 object[i]._oAnimFrame = 5 - v9;
1658 object[i]._oVar4 = object[i]._oAnimFrame + 1;
1659 object[i]._oVar8 = 0;
1660 }
1661 }
1662
AddObject(int ot,int ox,int oy)1663 void AddObject(int ot, int ox, int oy)
1664 {
1665 int oi;
1666
1667 if (nobjects >= MAXOBJECTS)
1668 return;
1669
1670 oi = objectavail[0];
1671 objectavail[0] = objectavail[MAXOBJECTS - 1 - nobjects];
1672 objectactive[nobjects] = oi;
1673 dObject[ox][oy] = oi + 1;
1674 SetupObject(oi, ox, oy, ot);
1675 switch (ot) {
1676 case OBJ_L1LIGHT:
1677 AddObjLight(oi, 5);
1678 break;
1679 case OBJ_SKFIRE:
1680 case OBJ_CANDLE1:
1681 case OBJ_CANDLE2:
1682 case OBJ_BOOKCANDLE:
1683 AddObjLight(oi, 5);
1684 break;
1685 case OBJ_STORYCANDLE:
1686 AddObjLight(oi, 3);
1687 break;
1688 case OBJ_TORCHL:
1689 case OBJ_TORCHR:
1690 case OBJ_TORCHL2:
1691 case OBJ_TORCHR2:
1692 AddObjLight(oi, 8);
1693 break;
1694 case OBJ_L1LDOOR:
1695 case OBJ_L1RDOOR:
1696 AddL1Door(oi, ox, oy, ot);
1697 break;
1698 case OBJ_L2LDOOR:
1699 case OBJ_L2RDOOR:
1700 AddL2Door(oi, ox, oy, ot);
1701 break;
1702 case OBJ_L3LDOOR:
1703 case OBJ_L3RDOOR:
1704 AddL3Door(oi, ox, oy, ot);
1705 break;
1706 case OBJ_BOOK2R:
1707 AddSCambBook(oi);
1708 break;
1709 case OBJ_CHEST1:
1710 case OBJ_CHEST2:
1711 case OBJ_CHEST3:
1712 AddChest(oi, ot);
1713 break;
1714 case OBJ_TCHEST1:
1715 case OBJ_TCHEST2:
1716 case OBJ_TCHEST3:
1717 AddChest(oi, ot);
1718 object[oi]._oTrapFlag = TRUE;
1719 if (leveltype == DTYPE_CATACOMBS) {
1720 object[oi]._oVar4 = random_(0, 2);
1721 } else {
1722 object[oi]._oVar4 = random_(0, 3);
1723 }
1724 break;
1725 case OBJ_SARC:
1726 AddSarc(oi);
1727 break;
1728 case OBJ_FLAMEHOLE:
1729 AddFlameTrap(oi);
1730 break;
1731 case OBJ_FLAMELVR:
1732 AddFlameLvr(oi);
1733 break;
1734 case OBJ_WATER:
1735 object[oi]._oAnimFrame = 1;
1736 break;
1737 case OBJ_TRAPL:
1738 case OBJ_TRAPR:
1739 AddTrap(oi, ot);
1740 break;
1741 case OBJ_BARREL:
1742 case OBJ_BARRELEX:
1743 AddBarrel(oi, ot);
1744 break;
1745 case OBJ_SHRINEL:
1746 case OBJ_SHRINER:
1747 AddShrine(oi);
1748 break;
1749 case OBJ_BOOKCASEL:
1750 case OBJ_BOOKCASER:
1751 AddBookcase(oi);
1752 break;
1753 case OBJ_SKELBOOK:
1754 case OBJ_BOOKSTAND:
1755 AddBookstand(oi);
1756 break;
1757 case OBJ_BLOODFTN:
1758 AddBloodFtn(oi);
1759 break;
1760 case OBJ_DECAP:
1761 AddDecap(oi);
1762 break;
1763 case OBJ_PURIFYINGFTN:
1764 AddPurifyingFountain(oi);
1765 break;
1766 case OBJ_ARMORSTAND:
1767 case OBJ_WARARMOR:
1768 AddArmorStand(oi);
1769 break;
1770 case OBJ_GOATSHRINE:
1771 AddGoatShrine(oi);
1772 break;
1773 case OBJ_CAULDRON:
1774 AddCauldron(oi);
1775 break;
1776 case OBJ_MURKYFTN:
1777 AddMurkyFountain(oi);
1778 break;
1779 case OBJ_TEARFTN:
1780 AddTearFountain(oi);
1781 break;
1782 case OBJ_BOOK2L:
1783 AddVilebook(oi);
1784 break;
1785 case OBJ_MCIRCLE1:
1786 case OBJ_MCIRCLE2:
1787 AddMagicCircle(oi);
1788 break;
1789 case OBJ_STORYBOOK:
1790 AddStoryBook(oi);
1791 break;
1792 case OBJ_BCROSS:
1793 case OBJ_TBCROSS:
1794 AddBrnCross(oi);
1795 AddObjLight(oi, 5);
1796 break;
1797 case OBJ_PEDISTAL:
1798 AddPedistal(oi);
1799 break;
1800 case OBJ_WARWEAP:
1801 case OBJ_WEAPONRACK:
1802 AddWeaponRack(oi);
1803 break;
1804 case OBJ_TNUDEM2:
1805 AddTorturedBody(oi);
1806 break;
1807 }
1808 object[oi]._oAnimWidth2 = (object[oi]._oAnimWidth - 64) >> 1;
1809 nobjects++;
1810 }
1811
Obj_Light(int i,int lr)1812 void Obj_Light(int i, int lr)
1813 {
1814 int ox, oy, dx, dy, p, tr;
1815 bool turnon;
1816
1817 turnon = FALSE;
1818 if (object[i]._oVar1 != -1) {
1819 ox = object[i]._ox;
1820 oy = object[i]._oy;
1821 tr = lr + 10;
1822 if (!lightflag) {
1823 for (p = 0; p < MAX_PLRS && !turnon; p++) {
1824 if (plr[p].plractive) {
1825 if (currlevel == plr[p].plrlevel) {
1826 dx = abs(plr[p]._px - ox);
1827 dy = abs(plr[p]._py - oy);
1828 if (dx < tr && dy < tr)
1829 turnon = TRUE;
1830 }
1831 }
1832 }
1833 }
1834 if (turnon) {
1835 if (object[i]._oVar1 == 0)
1836 object[i]._olid = AddLight(ox, oy, lr);
1837 object[i]._oVar1 = 1;
1838 } else {
1839 if (object[i]._oVar1 == 1)
1840 AddUnLight(object[i]._olid);
1841 object[i]._oVar1 = 0;
1842 }
1843 }
1844 }
1845
Obj_Circle(int i)1846 void Obj_Circle(int i)
1847 {
1848 int ox, oy, wx, wy;
1849
1850 ox = object[i]._ox;
1851 oy = object[i]._oy;
1852 wx = plr[myplr]._px;
1853 wy = plr[myplr]._py;
1854 if (wx == ox && wy == oy) {
1855 if (object[i]._otype == OBJ_MCIRCLE1)
1856 object[i]._oAnimFrame = 2;
1857 if (object[i]._otype == OBJ_MCIRCLE2)
1858 object[i]._oAnimFrame = 4;
1859 if (ox == 45 && oy == 47) {
1860 object[i]._oVar6 = 2;
1861 } else if (ox == 26 && oy == 46) {
1862 object[i]._oVar6 = 1;
1863 } else {
1864 object[i]._oVar6 = 0;
1865 }
1866 if (ox == 35 && oy == 36 && object[i]._oVar5 == 3) {
1867 object[i]._oVar6 = 4;
1868 ObjChangeMapResync(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
1869 if (quests[Q_BETRAYER]._qactive == QUEST_ACTIVE && quests[Q_BETRAYER]._qvar1 <= 4) // BUGFIX stepping on the circle again will break the quest state (fixed)
1870 quests[Q_BETRAYER]._qvar1 = 4;
1871 AddMissile(plr[myplr]._px, plr[myplr]._py, 35, 46, plr[myplr]._pdir, MIS_RNDTELEPORT, TARGET_MONSTERS, myplr, 0, 0);
1872 track_repeat_walk(FALSE);
1873 sgbMouseDown = CLICK_NONE;
1874 ClrPlrPath(myplr);
1875 StartStand(myplr, DIR_S);
1876 }
1877 } else {
1878 if (object[i]._otype == OBJ_MCIRCLE1)
1879 object[i]._oAnimFrame = 1;
1880 if (object[i]._otype == OBJ_MCIRCLE2)
1881 object[i]._oAnimFrame = 3;
1882 object[i]._oVar6 = 0;
1883 }
1884 }
1885
Obj_StopAnim(int i)1886 void Obj_StopAnim(int i)
1887 {
1888 if (object[i]._oAnimFrame == object[i]._oAnimLen) {
1889 object[i]._oAnimCnt = 0;
1890 object[i]._oAnimDelay = 1000;
1891 }
1892 }
1893
Obj_Door(int i)1894 void Obj_Door(int i)
1895 {
1896 int dx, dy;
1897 bool dok;
1898
1899 if (object[i]._oVar4 == 0) {
1900 object[i]._oSelFlag = 3;
1901 object[i]._oMissFlag = FALSE;
1902 } else {
1903 dx = object[i]._ox;
1904 dy = object[i]._oy;
1905 dok = dMonster[dx][dy] == 0;
1906 dok = dok && dItem[dx][dy] == 0;
1907 dok = dok && dDead[dx][dy] == 0;
1908 dok = dok && dPlayer[dx][dy] == 0;
1909 object[i]._oSelFlag = 2;
1910 object[i]._oVar4 = dok ? 1 : 2;
1911 object[i]._oMissFlag = TRUE;
1912 }
1913 }
1914
Obj_Sarc(int i)1915 void Obj_Sarc(int i)
1916 {
1917 if (object[i]._oAnimFrame == object[i]._oAnimLen)
1918 object[i]._oAnimFlag = 0;
1919 }
1920
ActivateTrapLine(int ttype,int tid)1921 void ActivateTrapLine(int ttype, int tid)
1922 {
1923 int i, oi;
1924
1925 for (i = 0; i < nobjects; i++) {
1926 oi = objectactive[i];
1927 if (object[oi]._otype == ttype && object[oi]._oVar1 == tid) {
1928 object[oi]._oVar4 = 1;
1929 object[oi]._oAnimFlag = 1;
1930 object[oi]._oAnimDelay = 1;
1931 object[oi]._olid = AddLight(object[oi]._ox, object[oi]._oy, 1);
1932 }
1933 }
1934 }
1935
Obj_FlameTrap(int i)1936 void Obj_FlameTrap(int i)
1937 {
1938 int x, y;
1939 int j, k;
1940
1941 if (object[i]._oVar2 != 0) {
1942 if (object[i]._oVar4 != 0) {
1943 object[i]._oAnimFrame--;
1944 if (object[i]._oAnimFrame == 1) {
1945 object[i]._oVar4 = 0;
1946 AddUnLight(object[i]._olid);
1947 } else if (object[i]._oAnimFrame <= 4) {
1948 ChangeLightRadius(object[i]._olid, object[i]._oAnimFrame);
1949 }
1950 }
1951 } else if (object[i]._oVar4 == 0) {
1952 if (object[i]._oVar3 == 2) {
1953 x = object[i]._ox - 2;
1954 y = object[i]._oy;
1955 for (j = 0; j < 5; j++) {
1956 if (dPlayer[x][y] != 0 || dMonster[x][y] != 0)
1957 object[i]._oVar4 = 1;
1958 x++;
1959 }
1960 } else {
1961 x = object[i]._ox;
1962 y = object[i]._oy - 2;
1963 for (k = 0; k < 5; k++) {
1964 if (dPlayer[x][y] != 0 || dMonster[x][y] != 0)
1965 object[i]._oVar4 = 1;
1966 y++;
1967 }
1968 }
1969 if (object[i]._oVar4 != 0)
1970 ActivateTrapLine(object[i]._otype, object[i]._oVar1);
1971 } else {
1972 int damage[4] = { 6, 8, 10, 12 };
1973
1974 int mindam = damage[leveltype - 1];
1975 int maxdam = mindam * 2;
1976
1977 x = object[i]._ox;
1978 y = object[i]._oy;
1979 if (dMonster[x][y] > 0)
1980 MonsterTrapHit(dMonster[x][y] - 1, mindam / 2, maxdam / 2, 0, MIS_FIREWALLC, FALSE);
1981 if (dPlayer[x][y] > 0) {
1982 BOOLEAN unused;
1983 PlayerMHit(dPlayer[x][y] - 1, -1, 0, mindam, maxdam, MIS_FIREWALLC, FALSE, 0, &unused);
1984 }
1985
1986 if (object[i]._oAnimFrame == object[i]._oAnimLen)
1987 object[i]._oAnimFrame = 11;
1988 if (object[i]._oAnimFrame <= 5)
1989 ChangeLightRadius(object[i]._olid, object[i]._oAnimFrame);
1990 }
1991 }
1992
Obj_Trap(int i)1993 void Obj_Trap(int i)
1994 {
1995 int oti, dir;
1996 BOOLEAN otrig;
1997 int sx, sy, dx, dy, x, y;
1998
1999 otrig = FALSE;
2000 if (object[i]._oVar4 == 0) {
2001 oti = dObject[object[i]._oVar1][object[i]._oVar2] - 1;
2002 switch (object[oti]._otype) {
2003 case OBJ_L1LDOOR:
2004 case OBJ_L1RDOOR:
2005 case OBJ_L2LDOOR:
2006 case OBJ_L2RDOOR:
2007 case OBJ_L3LDOOR:
2008 case OBJ_L3RDOOR:
2009 if (object[oti]._oVar4 != 0)
2010 otrig = TRUE;
2011 break;
2012 case OBJ_LEVER:
2013 case OBJ_CHEST1:
2014 case OBJ_CHEST2:
2015 case OBJ_CHEST3:
2016 case OBJ_SWITCHSKL:
2017 case OBJ_SARC:
2018 if (object[oti]._oSelFlag == 0)
2019 otrig = TRUE;
2020 break;
2021 }
2022 if (otrig) {
2023 object[i]._oVar4 = 1;
2024 sx = object[i]._ox;
2025 sy = object[i]._oy;
2026 dx = object[oti]._ox;
2027 dy = object[oti]._oy;
2028 for (y = dy - 1; y <= object[oti]._oy + 1; y++) {
2029 for (x = object[oti]._ox - 1; x <= object[oti]._ox + 1; x++) {
2030 if (dPlayer[x][y] != 0) {
2031 dx = x;
2032 dy = y;
2033 }
2034 }
2035 }
2036 if (!deltaload) {
2037 dir = GetDirection(sx, sy, dx, dy);
2038 AddMissile(sx, sy, dx, dy, dir, object[i]._oVar3, TARGET_PLAYERS, -1, 0, 0);
2039 PlaySfxLoc(IS_TRAP, object[oti]._ox, object[oti]._oy);
2040 }
2041 object[oti]._oTrapFlag = FALSE;
2042 }
2043 }
2044 }
2045
Obj_BCrossDamage(int i)2046 void Obj_BCrossDamage(int i)
2047 {
2048 int fire_resist;
2049 int damage[4] = { 6, 8, 10, 12 };
2050
2051 if (plr[myplr]._pmode == PM_DEATH)
2052 return;
2053
2054 fire_resist = plr[myplr]._pFireResist;
2055 if (fire_resist > 0)
2056 damage[leveltype - 1] -= fire_resist * damage[leveltype - 1] / 100;
2057
2058 if (plr[myplr]._px != object[i]._ox || plr[myplr]._py != object[i]._oy - 1)
2059 return;
2060
2061 plr[myplr]._pHitPoints -= damage[leveltype - 1];
2062 plr[myplr]._pHPBase -= damage[leveltype - 1];
2063 if (plr[myplr]._pHitPoints >> 6 <= 0) {
2064 SyncPlrKill(myplr, 0);
2065 } else {
2066 if (plr[myplr]._pClass == PC_WARRIOR) {
2067 PlaySfxLoc(PS_WARR68, plr[myplr]._px, plr[myplr]._py);
2068 } else if (plr[myplr]._pClass == PC_ROGUE) {
2069 PlaySfxLoc(PS_ROGUE68, plr[myplr]._px, plr[myplr]._py);
2070 } else if (plr[myplr]._pClass == PC_SORCERER) {
2071 PlaySfxLoc(PS_MAGE68, plr[myplr]._px, plr[myplr]._py);
2072 } else if (plr[myplr]._pClass == PC_MONK) {
2073 PlaySfxLoc(PS_MONK68, plr[myplr]._px, plr[myplr]._py);
2074 } else if (plr[myplr]._pClass == PC_BARD) {
2075 PlaySfxLoc(PS_ROGUE68, plr[myplr]._px, plr[myplr]._py);
2076 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
2077 PlaySfxLoc(PS_WARR68, plr[myplr]._px, plr[myplr]._py);
2078 }
2079 }
2080 drawhpflag = TRUE;
2081 }
2082
ProcessObjects()2083 void ProcessObjects()
2084 {
2085 int oi;
2086 int i;
2087
2088 for (i = 0; i < nobjects; ++i) {
2089 oi = objectactive[i];
2090 switch (object[oi]._otype) {
2091 case OBJ_L1LIGHT:
2092 Obj_Light(oi, 10);
2093 break;
2094 case OBJ_SKFIRE:
2095 case OBJ_CANDLE2:
2096 case OBJ_BOOKCANDLE:
2097 Obj_Light(oi, 5);
2098 break;
2099 case OBJ_STORYCANDLE:
2100 Obj_Light(oi, 3);
2101 break;
2102 case OBJ_CRUX1:
2103 case OBJ_CRUX2:
2104 case OBJ_CRUX3:
2105 case OBJ_BARREL:
2106 case OBJ_BARRELEX:
2107 case OBJ_SHRINEL:
2108 case OBJ_SHRINER:
2109 Obj_StopAnim(oi);
2110 break;
2111 case OBJ_L1LDOOR:
2112 case OBJ_L1RDOOR:
2113 case OBJ_L2LDOOR:
2114 case OBJ_L2RDOOR:
2115 case OBJ_L3LDOOR:
2116 case OBJ_L3RDOOR:
2117 Obj_Door(oi);
2118 break;
2119 case OBJ_TORCHL:
2120 case OBJ_TORCHR:
2121 case OBJ_TORCHL2:
2122 case OBJ_TORCHR2:
2123 Obj_Light(oi, 8);
2124 break;
2125 case OBJ_SARC:
2126 Obj_Sarc(oi);
2127 break;
2128 case OBJ_FLAMEHOLE:
2129 Obj_FlameTrap(oi);
2130 break;
2131 case OBJ_TRAPL:
2132 case OBJ_TRAPR:
2133 Obj_Trap(oi);
2134 break;
2135 case OBJ_MCIRCLE1:
2136 case OBJ_MCIRCLE2:
2137 Obj_Circle(oi);
2138 break;
2139 case OBJ_BCROSS:
2140 case OBJ_TBCROSS:
2141 Obj_Light(oi, 10);
2142 Obj_BCrossDamage(oi);
2143 break;
2144 }
2145 if (object[oi]._oAnimFlag == 0)
2146 continue;
2147
2148 object[oi]._oAnimCnt++;
2149
2150 if (object[oi]._oAnimCnt < object[oi]._oAnimDelay)
2151 continue;
2152
2153 object[oi]._oAnimCnt = 0;
2154 object[oi]._oAnimFrame++;
2155 if (object[oi]._oAnimFrame > object[oi]._oAnimLen)
2156 object[oi]._oAnimFrame = 1;
2157 }
2158 i = 0;
2159 while (i < nobjects) {
2160 oi = objectactive[i];
2161 if (object[oi]._oDelFlag) {
2162 DeleteObject_(oi, i);
2163 i = 0;
2164 } else {
2165 i++;
2166 }
2167 }
2168 }
2169
ObjSetMicro(int dx,int dy,int pn)2170 void ObjSetMicro(int dx, int dy, int pn)
2171 {
2172 WORD *v;
2173 MICROS *defs;
2174 int i;
2175
2176 dPiece[dx][dy] = pn;
2177 pn--;
2178 defs = &dpiece_defs_map_2[dx][dy];
2179 if (leveltype != DTYPE_HELL) {
2180 v = (WORD *)pLevelPieces + 10 * pn;
2181 for (i = 0; i < 10; i++) {
2182 defs->mt[i] = SDL_SwapLE16(v[(i & 1) - (i & 0xE) + 8]);
2183 }
2184 } else {
2185 v = (WORD *)pLevelPieces + 16 * pn;
2186 for (i = 0; i < 16; i++) {
2187 defs->mt[i] = SDL_SwapLE16(v[(i & 1) - (i & 0xE) + 14]);
2188 }
2189 }
2190 }
2191
objects_set_door_piece(int x,int y)2192 void objects_set_door_piece(int x, int y)
2193 {
2194 int pn;
2195 long v1, v2;
2196
2197 pn = dPiece[x][y] - 1;
2198
2199 v1 = *((WORD *)pLevelPieces + 10 * pn + 8);
2200 v2 = *((WORD *)pLevelPieces + 10 * pn + 9);
2201 dpiece_defs_map_2[x][y].mt[0] = SDL_SwapLE16(v1);
2202 dpiece_defs_map_2[x][y].mt[1] = SDL_SwapLE16(v2);
2203 }
2204
ObjSetMini(int x,int y,int v)2205 void ObjSetMini(int x, int y, int v)
2206 {
2207 int xx, yy;
2208 long v1, v2, v3, v4;
2209 WORD *MegaTiles;
2210
2211 MegaTiles = (WORD *)&pMegaTiles[((WORD)v - 1) * 8];
2212 v1 = SDL_SwapLE16(*(MegaTiles + 0)) + 1;
2213 v2 = SDL_SwapLE16(*(MegaTiles + 1)) + 1;
2214 v3 = SDL_SwapLE16(*(MegaTiles + 2)) + 1;
2215 v4 = SDL_SwapLE16(*(MegaTiles + 3)) + 1;
2216
2217 xx = 2 * x + 16;
2218 yy = 2 * y + 16;
2219 ObjSetMicro(xx, yy, v1);
2220 ObjSetMicro(xx + 1, yy, v2);
2221 ObjSetMicro(xx, yy + 1, v3);
2222 ObjSetMicro(xx + 1, yy + 1, v4);
2223 }
2224
ObjL1Special(int x1,int y1,int x2,int y2)2225 void ObjL1Special(int x1, int y1, int x2, int y2)
2226 {
2227 int i, j;
2228
2229 for (i = y1; i <= y2; ++i) {
2230 for (j = x1; j <= x2; ++j) {
2231 dSpecial[j][i] = 0;
2232 if (dPiece[j][i] == 12)
2233 dSpecial[j][i] = 1;
2234 if (dPiece[j][i] == 11)
2235 dSpecial[j][i] = 2;
2236 if (dPiece[j][i] == 71)
2237 dSpecial[j][i] = 1;
2238 if (dPiece[j][i] == 253)
2239 dSpecial[j][i] = 3;
2240 if (dPiece[j][i] == 267)
2241 dSpecial[j][i] = 6;
2242 if (dPiece[j][i] == 259)
2243 dSpecial[j][i] = 5;
2244 if (dPiece[j][i] == 249)
2245 dSpecial[j][i] = 2;
2246 if (dPiece[j][i] == 325)
2247 dSpecial[j][i] = 2;
2248 if (dPiece[j][i] == 321)
2249 dSpecial[j][i] = 1;
2250 if (dPiece[j][i] == 255)
2251 dSpecial[j][i] = 4;
2252 if (dPiece[j][i] == 211)
2253 dSpecial[j][i] = 1;
2254 if (dPiece[j][i] == 344)
2255 dSpecial[j][i] = 2;
2256 if (dPiece[j][i] == 341)
2257 dSpecial[j][i] = 1;
2258 if (dPiece[j][i] == 331)
2259 dSpecial[j][i] = 2;
2260 if (dPiece[j][i] == 418)
2261 dSpecial[j][i] = 1;
2262 if (dPiece[j][i] == 421)
2263 dSpecial[j][i] = 2;
2264 }
2265 }
2266 }
2267
ObjL2Special(int x1,int y1,int x2,int y2)2268 void ObjL2Special(int x1, int y1, int x2, int y2)
2269 {
2270 int i, j;
2271
2272 for (j = y1; j <= y2; j++) {
2273 for (i = x1; i <= x2; i++) {
2274 dSpecial[i][j] = 0;
2275 if (dPiece[i][j] == 541)
2276 dSpecial[i][j] = 5;
2277 if (dPiece[i][j] == 178)
2278 dSpecial[i][j] = 5;
2279 if (dPiece[i][j] == 551)
2280 dSpecial[i][j] = 5;
2281 if (dPiece[i][j] == 542)
2282 dSpecial[i][j] = 6;
2283 if (dPiece[i][j] == 553)
2284 dSpecial[i][j] = 6;
2285 }
2286 }
2287 for (j = y1; j <= y2; j++) {
2288 for (i = x1; i <= x2; i++) {
2289 if (dPiece[i][j] == 132) {
2290 dSpecial[i][j + 1] = 2;
2291 dSpecial[i][j + 2] = 1;
2292 }
2293 if (dPiece[i][j] == 135 || dPiece[i][j] == 139) {
2294 dSpecial[i + 1][j] = 3;
2295 dSpecial[i + 2][j] = 4;
2296 }
2297 }
2298 }
2299 }
2300
DoorSet(int oi,int dx,int dy)2301 void DoorSet(int oi, int dx, int dy)
2302 {
2303 int pn;
2304
2305 pn = dPiece[dx][dy];
2306 if (currlevel < 17) {
2307 if (pn == 43)
2308 ObjSetMicro(dx, dy, 392);
2309 if (pn == 45)
2310 ObjSetMicro(dx, dy, 394);
2311 if (pn == 50 && object[oi]._otype == OBJ_L1LDOOR)
2312 ObjSetMicro(dx, dy, 411);
2313 if (pn == 50 && object[oi]._otype == OBJ_L1RDOOR)
2314 ObjSetMicro(dx, dy, 412);
2315 if (pn == 54)
2316 ObjSetMicro(dx, dy, 397);
2317 if (pn == 55)
2318 ObjSetMicro(dx, dy, 398);
2319 if (pn == 61)
2320 ObjSetMicro(dx, dy, 399);
2321 if (pn == 67)
2322 ObjSetMicro(dx, dy, 400);
2323 if (pn == 68)
2324 ObjSetMicro(dx, dy, 401);
2325 if (pn == 69)
2326 ObjSetMicro(dx, dy, 403);
2327 if (pn == 70)
2328 ObjSetMicro(dx, dy, 404);
2329 if (pn == 72)
2330 ObjSetMicro(dx, dy, 406);
2331 if (pn == 212)
2332 ObjSetMicro(dx, dy, 407);
2333 if (pn == 354)
2334 ObjSetMicro(dx, dy, 409);
2335 if (pn == 355)
2336 ObjSetMicro(dx, dy, 410);
2337 if (pn == 411)
2338 ObjSetMicro(dx, dy, 396);
2339 if (pn == 412)
2340 ObjSetMicro(dx, dy, 396);
2341 } else {
2342 if (pn == 75)
2343 ObjSetMicro(dx, dy, 204);
2344 if (pn == 79)
2345 ObjSetMicro(dx, dy, 208);
2346 if (pn == 86 && object[oi]._otype == OBJ_L1LDOOR) {
2347 ObjSetMicro(dx, dy, 232);
2348 }
2349 if (pn == 86 && object[oi]._otype == OBJ_L1RDOOR) {
2350 ObjSetMicro(dx, dy, 234);
2351 }
2352 if (pn == 91)
2353 ObjSetMicro(dx, dy, 215);
2354 if (pn == 93)
2355 ObjSetMicro(dx, dy, 218);
2356 if (pn == 99)
2357 ObjSetMicro(dx, dy, 220);
2358 if (pn == 111)
2359 ObjSetMicro(dx, dy, 222);
2360 if (pn == 113)
2361 ObjSetMicro(dx, dy, 224);
2362 if (pn == 115)
2363 ObjSetMicro(dx, dy, 226);
2364 if (pn == 117)
2365 ObjSetMicro(dx, dy, 228);
2366 if (pn == 119)
2367 ObjSetMicro(dx, dy, 230);
2368 if (pn == 232)
2369 ObjSetMicro(dx, dy, 212);
2370 if (pn == 234)
2371 ObjSetMicro(dx, dy, 212);
2372 }
2373 }
2374
RedoPlayerVision()2375 void RedoPlayerVision()
2376 {
2377 int p;
2378
2379 for (p = 0; p < MAX_PLRS; p++) {
2380 if (plr[p].plractive && currlevel == plr[p].plrlevel) {
2381 ChangeVisionXY(plr[p]._pvid, plr[p]._px, plr[p]._py);
2382 }
2383 }
2384 }
2385
OperateL1RDoor(int pnum,int oi,bool sendflag)2386 void OperateL1RDoor(int pnum, int oi, bool sendflag)
2387 {
2388 int xp, yp;
2389
2390 if (object[oi]._oVar4 == 2) {
2391 if (!deltaload)
2392 PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
2393 return;
2394 }
2395
2396 xp = object[oi]._ox;
2397 yp = object[oi]._oy;
2398 if (object[oi]._oVar4 == 0) {
2399 if (pnum == myplr && sendflag)
2400 NetSendCmdParam1(TRUE, CMD_OPENDOOR, oi);
2401 if (currlevel < 21) {
2402 if (!deltaload)
2403 PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy);
2404 ObjSetMicro(xp, yp, 395);
2405 } else {
2406 if (!deltaload)
2407 PlaySfxLoc(IS_CROPEN, object[oi]._ox, object[oi]._oy);
2408 ObjSetMicro(xp, yp, 209);
2409 }
2410 if (currlevel < 17) {
2411 dSpecial[xp][yp] = 8;
2412 } else {
2413 dSpecial[xp][yp] = 2;
2414 }
2415 objects_set_door_piece(xp, yp - 1);
2416 object[oi]._oAnimFrame += 2;
2417 object[oi]._oPreFlag = TRUE;
2418 DoorSet(oi, xp - 1, yp);
2419 object[oi]._oVar4 = 1;
2420 object[oi]._oSelFlag = 2;
2421 RedoPlayerVision();
2422 return;
2423 }
2424
2425 if (currlevel < 21) {
2426 if (!deltaload)
2427 PlaySfxLoc(IS_DOORCLOS, xp, object[oi]._oy);
2428 } else {
2429 if (!deltaload)
2430 PlaySfxLoc(IS_CRCLOS, xp, object[oi]._oy);
2431 }
2432 if (!deltaload && dDead[xp][yp] == 0 && dMonster[xp][yp] == 0 && dItem[xp][yp] == 0) {
2433 if (pnum == myplr && sendflag)
2434 NetSendCmdParam1(TRUE, CMD_CLOSEDOOR, oi);
2435 object[oi]._oVar4 = 0;
2436 object[oi]._oSelFlag = 3;
2437 ObjSetMicro(xp, yp, object[oi]._oVar1);
2438 if (currlevel < 17) {
2439 if (object[oi]._oVar2 != 50) {
2440 ObjSetMicro(xp - 1, yp, object[oi]._oVar2);
2441 } else {
2442 if (dPiece[xp - 1][yp] == 396)
2443 ObjSetMicro(xp - 1, yp, 411);
2444 else
2445 ObjSetMicro(xp - 1, yp, 50);
2446 }
2447 } else {
2448 if (object[oi]._oVar2 != 86) {
2449 ObjSetMicro(xp - 1, yp, object[oi]._oVar2);
2450 } else {
2451 if (dPiece[xp - 1][yp] == 210)
2452 ObjSetMicro(xp - 1, yp, 232);
2453 else
2454 ObjSetMicro(xp - 1, yp, 86);
2455 }
2456 }
2457 dSpecial[xp][yp] = 0;
2458 object[oi]._oAnimFrame -= 2;
2459 object[oi]._oPreFlag = FALSE;
2460 RedoPlayerVision();
2461 } else {
2462 object[oi]._oVar4 = 2;
2463 }
2464 }
2465
OperateL1LDoor(int pnum,int oi,bool sendflag)2466 void OperateL1LDoor(int pnum, int oi, bool sendflag)
2467 {
2468 int xp, yp;
2469
2470 if (object[oi]._oVar4 == 2) {
2471 if (!deltaload)
2472 PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
2473 return;
2474 }
2475
2476 xp = object[oi]._ox;
2477 yp = object[oi]._oy;
2478 if (object[oi]._oVar4 == 0) {
2479 if (pnum == myplr && sendflag)
2480 NetSendCmdParam1(TRUE, CMD_OPENDOOR, oi);
2481 if (currlevel < 21) {
2482 if (!deltaload)
2483 PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy);
2484 if (object[oi]._oVar1 == 214)
2485 ObjSetMicro(xp, yp, 408);
2486 else
2487 ObjSetMicro(xp, yp, 393);
2488 } else {
2489 if (!deltaload)
2490 PlaySfxLoc(IS_CROPEN, object[oi]._ox, object[oi]._oy);
2491 ObjSetMicro(xp, yp, 206);
2492 }
2493 if (currlevel < 17) {
2494 dSpecial[xp][yp] = 7;
2495 } else {
2496 dSpecial[xp][yp] = 1;
2497 }
2498 objects_set_door_piece(xp - 1, yp);
2499 object[oi]._oAnimFrame += 2;
2500 object[oi]._oPreFlag = TRUE;
2501 DoorSet(oi, xp, yp - 1);
2502 object[oi]._oVar4 = 1;
2503 object[oi]._oSelFlag = 2;
2504 RedoPlayerVision();
2505 return;
2506 }
2507
2508 if (currlevel < 21) {
2509 if (!deltaload)
2510 PlaySfxLoc(IS_DOORCLOS, xp, object[oi]._oy);
2511 } else {
2512 if (!deltaload)
2513 PlaySfxLoc(IS_CRCLOS, xp, object[oi]._oy);
2514 }
2515 if (dDead[xp][yp] == 0 && dMonster[xp][yp] == 0 && dItem[xp][yp] == 0) {
2516 if (pnum == myplr && sendflag)
2517 NetSendCmdParam1(TRUE, CMD_CLOSEDOOR, oi);
2518 object[oi]._oVar4 = 0;
2519 object[oi]._oSelFlag = 3;
2520 ObjSetMicro(xp, yp, object[oi]._oVar1);
2521 if (currlevel < 17) {
2522 if (object[oi]._oVar2 != 50) {
2523 ObjSetMicro(xp, yp - 1, object[oi]._oVar2);
2524 } else {
2525 if (dPiece[xp][yp - 1] == 396)
2526 ObjSetMicro(xp, yp - 1, 412);
2527 else
2528 ObjSetMicro(xp, yp - 1, 50);
2529 }
2530 } else {
2531 if (object[oi]._oVar2 != 86) {
2532 ObjSetMicro(xp, yp - 1, object[oi]._oVar2);
2533 } else {
2534 if (dPiece[xp][yp - 1] == 210)
2535 ObjSetMicro(xp, yp - 1, 234);
2536 else
2537 ObjSetMicro(xp, yp - 1, 86);
2538 }
2539 }
2540 dSpecial[xp][yp] = 0;
2541 object[oi]._oAnimFrame -= 2;
2542 object[oi]._oPreFlag = FALSE;
2543 RedoPlayerVision();
2544 } else {
2545 object[oi]._oVar4 = 2;
2546 }
2547 }
2548
OperateL2RDoor(int pnum,int oi,bool sendflag)2549 void OperateL2RDoor(int pnum, int oi, bool sendflag)
2550 {
2551 int xp, yp;
2552 bool dok;
2553
2554 if (object[oi]._oVar4 == 2) {
2555 if (!deltaload)
2556 PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
2557 return;
2558 }
2559 xp = object[oi]._ox;
2560 yp = object[oi]._oy;
2561 if (object[oi]._oVar4 == 0) {
2562 if (pnum == myplr && sendflag)
2563 NetSendCmdParam1(TRUE, CMD_OPENDOOR, oi);
2564 if (!deltaload)
2565 PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy);
2566 ObjSetMicro(xp, yp, 17);
2567 dSpecial[xp][yp] = 6;
2568 object[oi]._oAnimFrame += 2;
2569 object[oi]._oPreFlag = TRUE;
2570 object[oi]._oVar4 = 1;
2571 object[oi]._oSelFlag = 2;
2572 RedoPlayerVision();
2573 return;
2574 }
2575
2576 if (!deltaload)
2577 PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, yp);
2578 dok = dMonster[xp][yp] == 0;
2579 dok = dok && dItem[xp][yp] == 0;
2580 dok = dok && dDead[xp][yp] == 0;
2581 if (dok) {
2582 if (pnum == myplr && sendflag)
2583 NetSendCmdParam1(TRUE, CMD_CLOSEDOOR, oi);
2584 object[oi]._oVar4 = 0;
2585 object[oi]._oSelFlag = 3;
2586 ObjSetMicro(xp, yp, 540);
2587 dSpecial[xp][yp] = 0;
2588 object[oi]._oAnimFrame -= 2;
2589 object[oi]._oPreFlag = FALSE;
2590 RedoPlayerVision();
2591 } else {
2592 object[oi]._oVar4 = 2;
2593 }
2594 }
2595
OperateL2LDoor(int pnum,int oi,BOOL sendflag)2596 void OperateL2LDoor(int pnum, int oi, BOOL sendflag)
2597 {
2598 int xp, yp;
2599 bool dok;
2600
2601 if (object[oi]._oVar4 == 2) {
2602 if (!deltaload)
2603 PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
2604 return;
2605 }
2606 xp = object[oi]._ox;
2607 yp = object[oi]._oy;
2608 if (object[oi]._oVar4 == 0) {
2609 if (pnum == myplr && sendflag)
2610 NetSendCmdParam1(TRUE, CMD_OPENDOOR, oi);
2611 if (!deltaload)
2612 PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy);
2613 ObjSetMicro(xp, yp, 13);
2614 dSpecial[xp][yp] = 5;
2615 object[oi]._oAnimFrame += 2;
2616 object[oi]._oPreFlag = TRUE;
2617 object[oi]._oVar4 = 1;
2618 object[oi]._oSelFlag = 2;
2619 RedoPlayerVision();
2620 return;
2621 }
2622
2623 if (!deltaload)
2624 PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, yp);
2625 dok = dMonster[xp][yp] == 0;
2626 dok = dok && dItem[xp][yp] == 0;
2627 dok = dok && dDead[xp][yp] == 0;
2628 if (dok) {
2629 if (pnum == myplr && sendflag)
2630 NetSendCmdParam1(TRUE, CMD_CLOSEDOOR, oi);
2631 object[oi]._oVar4 = 0;
2632 object[oi]._oSelFlag = 3;
2633 ObjSetMicro(xp, yp, 538);
2634 dSpecial[xp][yp] = 0;
2635 object[oi]._oAnimFrame -= 2;
2636 object[oi]._oPreFlag = FALSE;
2637 RedoPlayerVision();
2638 } else {
2639 object[oi]._oVar4 = 2;
2640 }
2641 }
2642
OperateL3RDoor(int pnum,int oi,bool sendflag)2643 void OperateL3RDoor(int pnum, int oi, bool sendflag)
2644 {
2645 int xp, yp;
2646 bool dok;
2647
2648 if (object[oi]._oVar4 == 2) {
2649 if (!deltaload)
2650 PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
2651 return;
2652 }
2653
2654 xp = object[oi]._ox;
2655 yp = object[oi]._oy;
2656 if (object[oi]._oVar4 == 0) {
2657 if (pnum == myplr && sendflag)
2658 NetSendCmdParam1(TRUE, CMD_OPENDOOR, oi);
2659 if (!deltaload)
2660 PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy);
2661 ObjSetMicro(xp, yp, 541);
2662 object[oi]._oAnimFrame += 2;
2663 object[oi]._oPreFlag = TRUE;
2664 object[oi]._oVar4 = 1;
2665 object[oi]._oSelFlag = 2;
2666 RedoPlayerVision();
2667 return;
2668 }
2669
2670 if (!deltaload)
2671 PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, yp);
2672 dok = dMonster[xp][yp] == 0;
2673 dok = dok && dItem[xp][yp] == 0;
2674 dok = dok && dDead[xp][yp] == 0;
2675 if (dok) {
2676 if (pnum == myplr && sendflag)
2677 NetSendCmdParam1(TRUE, CMD_CLOSEDOOR, oi);
2678 object[oi]._oVar4 = 0;
2679 object[oi]._oSelFlag = 3;
2680 ObjSetMicro(xp, yp, 534);
2681 object[oi]._oAnimFrame -= 2;
2682 object[oi]._oPreFlag = FALSE;
2683 RedoPlayerVision();
2684 } else {
2685 object[oi]._oVar4 = 2;
2686 }
2687 }
2688
OperateL3LDoor(int pnum,int oi,bool sendflag)2689 void OperateL3LDoor(int pnum, int oi, bool sendflag)
2690 {
2691 int xp, yp;
2692 bool dok;
2693
2694 if (object[oi]._oVar4 == 2) {
2695 if (!deltaload)
2696 PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
2697 return;
2698 }
2699
2700 xp = object[oi]._ox;
2701 yp = object[oi]._oy;
2702 if (object[oi]._oVar4 == 0) {
2703 if (pnum == myplr && sendflag)
2704 NetSendCmdParam1(TRUE, CMD_OPENDOOR, oi);
2705 if (!deltaload)
2706 PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy);
2707 ObjSetMicro(xp, yp, 538);
2708 object[oi]._oAnimFrame += 2;
2709 object[oi]._oPreFlag = TRUE;
2710 object[oi]._oVar4 = 1;
2711 object[oi]._oSelFlag = 2;
2712 RedoPlayerVision();
2713 return;
2714 }
2715
2716 if (!deltaload)
2717 PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, yp);
2718 dok = dMonster[xp][yp] == 0;
2719 dok = dok && dItem[xp][yp] == 0;
2720 dok = dok && dDead[xp][yp] == 0;
2721 if (dok) {
2722 if (pnum == myplr && sendflag)
2723 NetSendCmdParam1(TRUE, CMD_CLOSEDOOR, oi);
2724 object[oi]._oVar4 = 0;
2725 object[oi]._oSelFlag = 3;
2726 ObjSetMicro(xp, yp, 531);
2727 object[oi]._oAnimFrame -= 2;
2728 object[oi]._oPreFlag = FALSE;
2729 RedoPlayerVision();
2730 } else {
2731 object[oi]._oVar4 = 2;
2732 }
2733 }
2734
MonstCheckDoors(int m)2735 void MonstCheckDoors(int m)
2736 {
2737 int i, oi;
2738 int dpx, dpy, mx, my;
2739
2740 mx = monster[m]._mx;
2741 my = monster[m]._my;
2742 if (dObject[mx - 1][my - 1] != 0
2743 || dObject[mx][my - 1] != 0
2744 || dObject[mx + 1][my - 1] != 0
2745 || dObject[mx - 1][my] != 0
2746 || dObject[mx + 1][my] != 0
2747 || dObject[mx - 1][my + 1] != 0
2748 || dObject[mx][my + 1] != 0
2749 || dObject[mx + 1][my + 1] != 0) {
2750 for (i = 0; i < nobjects; ++i) {
2751 oi = objectactive[i];
2752 if ((object[oi]._otype == OBJ_L1LDOOR || object[oi]._otype == OBJ_L1RDOOR) && object[oi]._oVar4 == 0) {
2753 dpx = abs(object[oi]._ox - mx);
2754 dpy = abs(object[oi]._oy - my);
2755 if (dpx == 1 && dpy <= 1 && object[oi]._otype == OBJ_L1LDOOR)
2756 OperateL1LDoor(myplr, oi, TRUE);
2757 if (dpx <= 1 && dpy == 1 && object[oi]._otype == OBJ_L1RDOOR)
2758 OperateL1RDoor(myplr, oi, TRUE);
2759 }
2760 if ((object[oi]._otype == OBJ_L2LDOOR || object[oi]._otype == OBJ_L2RDOOR) && object[oi]._oVar4 == 0) {
2761 dpx = abs(object[oi]._ox - mx);
2762 dpy = abs(object[oi]._oy - my);
2763 if (dpx == 1 && dpy <= 1 && object[oi]._otype == OBJ_L2LDOOR)
2764 OperateL2LDoor(myplr, oi, TRUE);
2765 if (dpx <= 1 && dpy == 1 && object[oi]._otype == OBJ_L2RDOOR)
2766 OperateL2RDoor(myplr, oi, TRUE);
2767 }
2768 if ((object[oi]._otype == OBJ_L3LDOOR || object[oi]._otype == OBJ_L3RDOOR) && object[oi]._oVar4 == 0) {
2769 dpx = abs(object[oi]._ox - mx);
2770 dpy = abs(object[oi]._oy - my);
2771 if (dpx == 1 && dpy <= 1 && object[oi]._otype == OBJ_L3RDOOR)
2772 OperateL3RDoor(myplr, oi, TRUE);
2773 if (dpx <= 1 && dpy == 1 && object[oi]._otype == OBJ_L3LDOOR)
2774 OperateL3LDoor(myplr, oi, TRUE);
2775 }
2776 }
2777 }
2778 }
2779
ObjChangeMap(int x1,int y1,int x2,int y2)2780 void ObjChangeMap(int x1, int y1, int x2, int y2)
2781 {
2782 int i, j;
2783
2784 for (j = y1; j <= y2; j++) {
2785 for (i = x1; i <= x2; i++) {
2786 ObjSetMini(i, j, pdungeon[i][j]);
2787 dungeon[i][j] = pdungeon[i][j];
2788 }
2789 }
2790 if (leveltype == DTYPE_CATHEDRAL && currlevel < 17) {
2791 ObjL1Special(2 * x1 + 16, 2 * y1 + 16, 2 * x2 + 17, 2 * y2 + 17);
2792 AddL1Objs(2 * x1 + 16, 2 * y1 + 16, 2 * x2 + 17, 2 * y2 + 17);
2793 }
2794 if (leveltype == DTYPE_CATACOMBS) {
2795 ObjL2Special(2 * x1 + 16, 2 * y1 + 16, 2 * x2 + 17, 2 * y2 + 17);
2796 AddL2Objs(2 * x1 + 16, 2 * y1 + 16, 2 * x2 + 17, 2 * y2 + 17);
2797 }
2798 }
2799
ObjChangeMapResync(int x1,int y1,int x2,int y2)2800 void ObjChangeMapResync(int x1, int y1, int x2, int y2)
2801 {
2802 int i, j;
2803
2804 for (j = y1; j <= y2; j++) {
2805 for (i = x1; i <= x2; i++) {
2806 ObjSetMini(i, j, pdungeon[i][j]);
2807 dungeon[i][j] = pdungeon[i][j];
2808 }
2809 }
2810 if (leveltype == DTYPE_CATHEDRAL && currlevel < 17) {
2811 ObjL1Special(2 * x1 + 16, 2 * y1 + 16, 2 * x2 + 17, 2 * y2 + 17);
2812 }
2813 if (leveltype == DTYPE_CATACOMBS) {
2814 ObjL2Special(2 * x1 + 16, 2 * y1 + 16, 2 * x2 + 17, 2 * y2 + 17);
2815 }
2816 }
2817
OperateL1Door(int pnum,int i,bool sendflag)2818 void OperateL1Door(int pnum, int i, bool sendflag)
2819 {
2820 int dpx, dpy;
2821
2822 dpx = abs(object[i]._ox - plr[pnum]._px);
2823 dpy = abs(object[i]._oy - plr[pnum]._py);
2824 if (dpx == 1 && dpy <= 1 && object[i]._otype == OBJ_L1LDOOR)
2825 OperateL1LDoor(pnum, i, sendflag);
2826 if (dpx <= 1 && dpy == 1 && object[i]._otype == OBJ_L1RDOOR)
2827 OperateL1RDoor(pnum, i, sendflag);
2828 }
2829
OperateLever(int pnum,int i)2830 void OperateLever(int pnum, int i)
2831 {
2832 int j, oi;
2833 bool mapflag;
2834
2835 if (object[i]._oSelFlag != 0) {
2836 if (!deltaload)
2837 PlaySfxLoc(IS_LEVER, object[i]._ox, object[i]._oy);
2838 object[i]._oSelFlag = 0;
2839 object[i]._oAnimFrame++;
2840 mapflag = TRUE;
2841 if (currlevel == 16) {
2842 for (j = 0; j < nobjects; j++) {
2843 oi = objectactive[j];
2844 if (object[oi]._otype == OBJ_SWITCHSKL
2845 && object[i]._oVar8 == object[oi]._oVar8
2846 && object[oi]._oSelFlag != 0) {
2847 mapflag = FALSE;
2848 }
2849 }
2850 }
2851 if (currlevel == 24) {
2852 operate_lv24_lever();
2853 IsUberLeverActivated = 1;
2854 mapflag = FALSE;
2855 quests[Q_NAKRUL]._qactive = 3;
2856 }
2857 if (mapflag)
2858 ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
2859 if (pnum == myplr)
2860 NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i);
2861 }
2862 }
2863
OperateBook(int pnum,int i)2864 void OperateBook(int pnum, int i)
2865 {
2866 int j, oi;
2867 int dx, dy;
2868 int otype;
2869 bool do_add_missile, missile_added;
2870
2871 if (object[i]._oSelFlag == 0)
2872 return;
2873 if (setlevel && setlvlnum == SL_VILEBETRAYER) {
2874 do_add_missile = FALSE;
2875 missile_added = FALSE;
2876 for (j = 0; j < nobjects; j++) {
2877 oi = objectactive[j];
2878 otype = object[oi]._otype;
2879 if (otype == OBJ_MCIRCLE2 && object[oi]._oVar6 == 1) {
2880 dx = 27;
2881 dy = 29;
2882 object[oi]._oVar6 = 4;
2883 do_add_missile = TRUE;
2884 }
2885 if (otype == OBJ_MCIRCLE2 && object[oi]._oVar6 == 2) {
2886 dx = 43;
2887 dy = 29;
2888 object[oi]._oVar6 = 4;
2889 do_add_missile = TRUE;
2890 }
2891 if (do_add_missile) {
2892 object[dObject[35][36] - 1]._oVar5++;
2893 AddMissile(plr[pnum]._px, plr[pnum]._py, dx, dy, plr[pnum]._pdir, MIS_RNDTELEPORT, TARGET_MONSTERS, pnum, 0, 0);
2894 missile_added = TRUE;
2895 do_add_missile = FALSE;
2896 }
2897 }
2898 if (!missile_added)
2899 return;
2900 }
2901 object[i]._oSelFlag = 0;
2902 object[i]._oAnimFrame++;
2903 if (!setlevel)
2904 return;
2905
2906 if (setlvlnum == SL_BONECHAMB) {
2907 plr[pnum]._pMemSpells |= GetSpellBitmask(SPL_GUARDIAN);
2908 if (plr[pnum]._pSplLvl[SPL_GUARDIAN] < MAX_SPELL_LEVEL)
2909 plr[pnum]._pSplLvl[SPL_GUARDIAN]++;
2910 quests[Q_SCHAMB]._qactive = QUEST_DONE;
2911 if (!deltaload)
2912 PlaySfxLoc(IS_QUESTDN, object[i]._ox, object[i]._oy);
2913 InitDiabloMsg(EMSG_BONECHAMB);
2914 AddMissile(
2915 plr[pnum]._px,
2916 plr[pnum]._py,
2917 object[i]._ox - 2,
2918 object[i]._oy - 4,
2919 plr[pnum]._pdir,
2920 MIS_GUARDIAN,
2921 TARGET_MONSTERS,
2922 pnum,
2923 0,
2924 0);
2925 }
2926 if (setlvlnum == SL_VILEBETRAYER) {
2927 ObjChangeMapResync(
2928 object[i]._oVar1,
2929 object[i]._oVar2,
2930 object[i]._oVar3,
2931 object[i]._oVar4);
2932 for (j = 0; j < nobjects; j++)
2933 SyncObjectAnim(objectactive[j]);
2934 }
2935 }
2936
OperateBookLever(int pnum,int i)2937 void OperateBookLever(int pnum, int i)
2938 {
2939 int x, y, tren;
2940
2941 x = 2 * setpc_x + 16;
2942 y = 2 * setpc_y + 16;
2943 if (numitems >= MAXITEMS) {
2944 return;
2945 }
2946 if (object[i]._oSelFlag != 0 && !qtextflag) {
2947 if (object[i]._otype == OBJ_BLINDBOOK && quests[Q_BLIND]._qvar1 == 0) {
2948 quests[Q_BLIND]._qactive = QUEST_ACTIVE;
2949 quests[Q_BLIND]._qlog = TRUE;
2950 quests[Q_BLIND]._qvar1 = 1;
2951 }
2952 if (object[i]._otype == OBJ_BLOODBOOK && quests[Q_BLOOD]._qvar1 == 0) {
2953 quests[Q_BLOOD]._qactive = QUEST_ACTIVE;
2954 quests[Q_BLOOD]._qlog = TRUE;
2955 quests[Q_BLOOD]._qvar1 = 1;
2956 SpawnQuestItem(IDI_BLDSTONE, 2 * setpc_x + 25, 2 * setpc_y + 33, 0, 1);
2957 }
2958 object[i]._otype = object[i]._otype;
2959 if (object[i]._otype == OBJ_STEELTOME && quests[Q_WARLORD]._qvar1 == 0) {
2960 quests[Q_WARLORD]._qactive = QUEST_ACTIVE;
2961 quests[Q_WARLORD]._qlog = TRUE;
2962 quests[Q_WARLORD]._qvar1 = 1;
2963 }
2964 if (object[i]._oAnimFrame != object[i]._oVar6) {
2965 if (object[i]._otype != OBJ_BLOODBOOK)
2966 ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
2967 if (object[i]._otype == OBJ_BLINDBOOK) {
2968 SpawnUnique(UITEM_OPTAMULET, x + 5, y + 5);
2969 tren = TransVal;
2970 TransVal = 9;
2971 DRLG_MRectTrans(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
2972 TransVal = tren;
2973 }
2974 }
2975 object[i]._oAnimFrame = object[i]._oVar6;
2976 InitQTextMsg(object[i]._oVar7);
2977 if (pnum == myplr)
2978 NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i);
2979 }
2980 }
2981
OperateSChambBk(int pnum,int i)2982 void OperateSChambBk(int pnum, int i)
2983 {
2984 int j, textdef;
2985
2986 if (object[i]._oSelFlag != 0 && !qtextflag) {
2987 if (object[i]._oAnimFrame != object[i]._oVar6) {
2988 ObjChangeMapResync(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
2989 for (j = 0; j < nobjects; j++)
2990 SyncObjectAnim(objectactive[j]);
2991 }
2992 object[i]._oAnimFrame = object[i]._oVar6;
2993 if (quests[Q_SCHAMB]._qactive == QUEST_INIT) {
2994 quests[Q_SCHAMB]._qactive = QUEST_ACTIVE;
2995 quests[Q_SCHAMB]._qlog = TRUE;
2996 }
2997 if (plr[myplr]._pClass == PC_WARRIOR) {
2998 textdef = TEXT_BONER;
2999 } else if (plr[myplr]._pClass == PC_ROGUE) {
3000 textdef = TEXT_RBONER;
3001 } else if (plr[myplr]._pClass == PC_SORCERER) {
3002 textdef = TEXT_MBONER;
3003 } else if (plr[myplr]._pClass == PC_MONK) {
3004 textdef = TEXT_HBONER;
3005 } else if (plr[myplr]._pClass == PC_BARD) {
3006 textdef = TEXT_BBONER;
3007 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
3008 textdef = TEXT_BONER;
3009 }
3010 quests[Q_SCHAMB]._qmsg = textdef;
3011 InitQTextMsg(textdef);
3012 }
3013 }
3014
OperateChest(int pnum,int i,bool sendmsg)3015 void OperateChest(int pnum, int i, bool sendmsg)
3016 {
3017 int j, mdir, mtype;
3018
3019 if (object[i]._oSelFlag != 0) {
3020 if (!deltaload)
3021 PlaySfxLoc(IS_CHEST, object[i]._ox, object[i]._oy);
3022 object[i]._oSelFlag = 0;
3023 object[i]._oAnimFrame += 2;
3024 if (!deltaload) {
3025 SetRndSeed(object[i]._oRndSeed);
3026 if (setlevel) {
3027 for (j = 0; j < object[i]._oVar1; j++) {
3028 CreateRndItem(object[i]._ox, object[i]._oy, TRUE, sendmsg, FALSE);
3029 }
3030 } else {
3031 for (j = 0; j < object[i]._oVar1; j++) {
3032 if (object[i]._oVar2 != 0)
3033 CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE);
3034 else
3035 CreateRndUseful(pnum, object[i]._ox, object[i]._oy, sendmsg);
3036 }
3037 }
3038 if (object[i]._oTrapFlag && object[i]._otype >= OBJ_TCHEST1 && object[i]._otype <= OBJ_TCHEST3) {
3039 mdir = GetDirection(object[i]._ox, object[i]._oy, plr[pnum]._px, plr[pnum]._py);
3040 switch (object[i]._oVar4) {
3041 case 0:
3042 mtype = MIS_ARROW;
3043 break;
3044 case 1:
3045 mtype = MIS_FARROW;
3046 break;
3047 case 2:
3048 mtype = MIS_NOVA;
3049 break;
3050 case 3:
3051 mtype = MIS_FIRERING;
3052 break;
3053 case 4:
3054 mtype = MIS_STEALPOTS;
3055 break;
3056 case 5:
3057 mtype = MIS_MANATRAP;
3058 break;
3059 default:
3060 mtype = MIS_ARROW;
3061 }
3062 AddMissile(object[i]._ox, object[i]._oy, plr[pnum]._px, plr[pnum]._py, mdir, mtype, TARGET_PLAYERS, -1, 0, 0);
3063 object[i]._oTrapFlag = FALSE;
3064 }
3065 if (pnum == myplr)
3066 NetSendCmdParam2(FALSE, CMD_PLROPOBJ, pnum, i);
3067 return;
3068 }
3069 }
3070 }
3071
OperateMushPatch(int pnum,int i)3072 void OperateMushPatch(int pnum, int i)
3073 {
3074 int x, y;
3075
3076 if (numitems >= MAXITEMS) {
3077 return;
3078 }
3079
3080 if (quests[Q_MUSHROOM]._qactive != QUEST_ACTIVE || quests[Q_MUSHROOM]._qvar1 < QS_TOMEGIVEN) {
3081 if (!deltaload && pnum == myplr) {
3082 if (plr[myplr]._pClass == PC_WARRIOR) {
3083 PlaySFX(PS_WARR13);
3084 } else if (plr[myplr]._pClass == PC_ROGUE) {
3085 PlaySFX(PS_ROGUE13);
3086 } else if (plr[myplr]._pClass == PC_SORCERER) {
3087 PlaySFX(PS_MAGE13);
3088 } else if (plr[myplr]._pClass == PC_MONK) {
3089 PlaySFX(PS_MONK13);
3090 } else if (plr[myplr]._pClass == PC_BARD) {
3091 PlaySFX(PS_ROGUE13);
3092 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
3093 PlaySFX(PS_WARR13);
3094 }
3095 }
3096 } else {
3097 if (object[i]._oSelFlag != 0) {
3098 if (!deltaload)
3099 PlaySfxLoc(IS_CHEST, object[i]._ox, object[i]._oy);
3100 object[i]._oSelFlag = 0;
3101 object[i]._oAnimFrame++;
3102 if (!deltaload) {
3103 GetSuperItemLoc(object[i]._ox, object[i]._oy, &x, &y);
3104 SpawnQuestItem(IDI_MUSHROOM, x, y, 0, 0);
3105 quests[Q_MUSHROOM]._qvar1 = QS_MUSHSPAWNED;
3106 }
3107 }
3108 }
3109 }
3110
OperateInnSignChest(int pnum,int i)3111 void OperateInnSignChest(int pnum, int i)
3112 {
3113 int x, y;
3114
3115 if (numitems >= MAXITEMS) {
3116 return;
3117 }
3118
3119 if (quests[Q_LTBANNER]._qvar1 != 2) {
3120 if (!deltaload && pnum == myplr) {
3121 if (plr[myplr]._pClass == PC_WARRIOR) {
3122 PlaySFX(PS_WARR24);
3123 } else if (plr[myplr]._pClass == PC_ROGUE) {
3124 PlaySFX(PS_ROGUE24);
3125 } else if (plr[myplr]._pClass == PC_SORCERER) {
3126 PlaySFX(PS_MAGE24);
3127 } else if (plr[myplr]._pClass == PC_MONK) {
3128 PlaySFX(PS_MONK24);
3129 } else if (plr[myplr]._pClass == PC_BARD) {
3130 PlaySFX(PS_ROGUE24);
3131 } else if (plr[myplr]._pClass == PC_BARBARIAN) {
3132 PlaySFX(PS_WARR24);
3133 }
3134 }
3135 } else {
3136 if (object[i]._oSelFlag != 0) {
3137 if (!deltaload)
3138 PlaySfxLoc(IS_CHEST, object[i]._ox, object[i]._oy);
3139 object[i]._oSelFlag = 0;
3140 object[i]._oAnimFrame += 2;
3141 if (!deltaload) {
3142 GetSuperItemLoc(object[i]._ox, object[i]._oy, &x, &y);
3143 SpawnQuestItem(IDI_BANNER, x, y, 0, 0);
3144 }
3145 }
3146 }
3147 }
3148
OperateSlainHero(int pnum,int i,bool sendmsg)3149 void OperateSlainHero(int pnum, int i, bool sendmsg)
3150 {
3151 if (object[i]._oSelFlag != 0) {
3152 object[i]._oSelFlag = 0;
3153 if (!deltaload) {
3154 if (plr[pnum]._pClass == PC_WARRIOR) {
3155 CreateMagicArmor(object[i]._ox, object[i]._oy, ITYPE_HARMOR, ICURS_BREAST_PLATE, FALSE, TRUE);
3156 PlaySfxLoc(PS_WARR9, plr[myplr]._px, plr[myplr]._py);
3157 } else if (plr[pnum]._pClass == PC_ROGUE) {
3158 CreateMagicWeapon(object[i]._ox, object[i]._oy, ITYPE_BOW, ICURS_LONG_WAR_BOW, FALSE, TRUE);
3159 PlaySfxLoc(PS_ROGUE9, plr[myplr]._px, plr[myplr]._py);
3160 } else if (plr[pnum]._pClass == PC_SORCERER) {
3161 CreateSpellBook(object[i]._ox, object[i]._oy, SPL_LIGHTNING, FALSE, TRUE);
3162 PlaySfxLoc(PS_MAGE9, plr[myplr]._px, plr[myplr]._py);
3163 } else if (plr[pnum]._pClass == PC_MONK) {
3164 CreateMagicWeapon(object[i]._ox, object[i]._oy, ITYPE_STAFF, ICURS_WAR_STAFF, FALSE, TRUE);
3165 PlaySfxLoc(PS_MONK9, plr[myplr]._px, plr[myplr]._py);
3166 } else if (plr[pnum]._pClass == PC_BARD) {
3167 CreateMagicWeapon(object[i]._ox, object[i]._oy, ITYPE_SWORD, ICURS_BASTARD_SWORD, FALSE, TRUE);
3168 PlaySfxLoc(PS_ROGUE9, plr[myplr]._px, plr[myplr]._py);
3169 } else if (plr[pnum]._pClass == PC_BARBARIAN) {
3170 CreateMagicWeapon(object[i]._ox, object[i]._oy, ITYPE_AXE, ICURS_BATTLE_AXE, FALSE, TRUE);
3171 PlaySfxLoc(PS_WARR9, plr[myplr]._px, plr[myplr]._py);
3172 }
3173 if (pnum == myplr)
3174 NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i);
3175 }
3176 }
3177 }
3178
OperateTrapLvr(int i)3179 void OperateTrapLvr(int i)
3180 {
3181 int frame, j, oi;
3182
3183 frame = object[i]._oAnimFrame;
3184 j = 0;
3185
3186 if (!deltaload)
3187 PlaySfxLoc(IS_LEVER, object[i]._ox, object[i]._oy);
3188
3189 if (frame == 1) {
3190 object[i]._oAnimFrame = 2;
3191 for (; j < nobjects; j++) {
3192 oi = objectactive[j];
3193 if (object[oi]._otype == object[i]._oVar2 && object[oi]._oVar1 == object[i]._oVar1) {
3194 object[oi]._oVar2 = 1;
3195 object[oi]._oAnimFlag = 0;
3196 }
3197 }
3198 return;
3199 }
3200
3201 object[i]._oAnimFrame = frame - 1;
3202 for (; j < nobjects; j++) {
3203 oi = objectactive[j];
3204 if (object[oi]._otype == object[i]._oVar2 && object[oi]._oVar1 == object[i]._oVar1) {
3205 object[oi]._oVar2 = 0;
3206 if (object[oi]._oVar4 != 0)
3207 object[oi]._oAnimFlag = 1;
3208 }
3209 }
3210 }
3211
OperateSarc(int pnum,int i,bool sendmsg)3212 void OperateSarc(int pnum, int i, bool sendmsg)
3213 {
3214 if (object[i]._oSelFlag != 0) {
3215 if (!deltaload)
3216 PlaySfxLoc(IS_SARC, object[i]._ox, object[i]._oy);
3217 object[i]._oSelFlag = 0;
3218 if (deltaload) {
3219 object[i]._oAnimFrame = object[i]._oAnimLen;
3220 } else {
3221 object[i]._oAnimFlag = 1;
3222 object[i]._oAnimDelay = 3;
3223 SetRndSeed(object[i]._oRndSeed);
3224 if (object[i]._oVar1 <= 2)
3225 CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE);
3226 if (object[i]._oVar1 >= 8)
3227 SpawnSkeleton(object[i]._oVar2, object[i]._ox, object[i]._oy);
3228 if (pnum == myplr)
3229 NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i);
3230 }
3231 }
3232 }
3233
OperateL2Door(int pnum,int i,bool sendflag)3234 void OperateL2Door(int pnum, int i, bool sendflag)
3235 {
3236 int dpx, dpy;
3237
3238 dpx = abs(object[i]._ox - plr[pnum]._px);
3239 dpy = abs(object[i]._oy - plr[pnum]._py);
3240 if (dpx == 1 && dpy <= 1 && object[i]._otype == OBJ_L2LDOOR)
3241 OperateL2LDoor(pnum, i, sendflag);
3242 if (dpx <= 1 && dpy == 1 && object[i]._otype == OBJ_L2RDOOR)
3243 OperateL2RDoor(pnum, i, sendflag);
3244 }
3245
OperateL3Door(int pnum,int i,bool sendflag)3246 void OperateL3Door(int pnum, int i, bool sendflag)
3247 {
3248 int dpx, dpy;
3249
3250 dpx = abs(object[i]._ox - plr[pnum]._px);
3251 dpy = abs(object[i]._oy - plr[pnum]._py);
3252 if (dpx == 1 && dpy <= 1 && object[i]._otype == OBJ_L3RDOOR)
3253 OperateL3RDoor(pnum, i, sendflag);
3254 if (dpx <= 1 && dpy == 1 && object[i]._otype == OBJ_L3LDOOR)
3255 OperateL3LDoor(pnum, i, sendflag);
3256 }
3257
OperatePedistal(int pnum,int i)3258 void OperatePedistal(int pnum, int i)
3259 {
3260 BYTE *mem;
3261 int iv;
3262
3263 if (numitems >= MAXITEMS) {
3264 return;
3265 }
3266
3267 if (object[i]._oVar6 != 3 && PlrHasItem(pnum, IDI_BLDSTONE, &iv) != NULL) {
3268 RemoveInvItem(pnum, iv);
3269 object[i]._oAnimFrame++;
3270 object[i]._oVar6++;
3271 if (object[i]._oVar6 == 1) {
3272 if (!deltaload)
3273 PlaySfxLoc(LS_PUDDLE, object[i]._ox, object[i]._oy);
3274 ObjChangeMap(setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7);
3275 SpawnQuestItem(IDI_BLDSTONE, 2 * setpc_x + 19, 2 * setpc_y + 26, 0, 1);
3276 }
3277 if (object[i]._oVar6 == 2) {
3278 if (!deltaload)
3279 PlaySfxLoc(LS_PUDDLE, object[i]._ox, object[i]._oy);
3280 ObjChangeMap(setpc_x + 6, setpc_y + 3, setpc_x + setpc_w, setpc_y + 7);
3281 SpawnQuestItem(IDI_BLDSTONE, 2 * setpc_x + 31, 2 * setpc_y + 26, 0, 1);
3282 }
3283 if (object[i]._oVar6 == 3) {
3284 if (!deltaload)
3285 PlaySfxLoc(LS_BLODSTAR, object[i]._ox, object[i]._oy);
3286 ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
3287 mem = LoadFileInMem("Levels\\L2Data\\Blood2.DUN", NULL);
3288 LoadMapObjs(mem, 2 * setpc_x, 2 * setpc_y);
3289 mem_free_dbg(mem);
3290 SpawnUnique(UITEM_ARMOFVAL, 2 * setpc_x + 25, 2 * setpc_y + 19);
3291 object[i]._oSelFlag = 0;
3292 }
3293 }
3294 }
3295
TryDisarm(int pnum,int i)3296 void TryDisarm(int pnum, int i)
3297 {
3298 int j, oi, oti, trapdisper;
3299 bool checkflag;
3300
3301 if (pnum == myplr)
3302 SetCursor_(CURSOR_HAND);
3303 if (object[i]._oTrapFlag) {
3304 trapdisper = 2 * plr[pnum]._pDexterity - 5 * currlevel;
3305 if (random_(154, 100) <= trapdisper) {
3306 for (j = 0; j < nobjects; j++) {
3307 checkflag = FALSE;
3308 oi = objectactive[j];
3309 oti = object[oi]._otype;
3310 if (oti == OBJ_TRAPL)
3311 checkflag = TRUE;
3312 if (oti == OBJ_TRAPR)
3313 checkflag = TRUE;
3314 if (checkflag && dObject[object[oi]._oVar1][object[oi]._oVar2] - 1 == i) {
3315 object[oi]._oVar4 = 1;
3316 object[i]._oTrapFlag = FALSE;
3317 }
3318 }
3319 oti = object[i]._otype;
3320 if (oti >= OBJ_TCHEST1 && oti <= OBJ_TCHEST3)
3321 object[i]._oTrapFlag = FALSE;
3322 }
3323 }
3324 }
3325
ItemMiscIdIdx(item_misc_id imiscid)3326 int ItemMiscIdIdx(item_misc_id imiscid)
3327 {
3328 int i;
3329
3330 i = IDI_GOLD;
3331 while (AllItemsList[i].iRnd == IDROP_NEVER || AllItemsList[i].iMiscId != imiscid) {
3332 i++;
3333 }
3334
3335 return i;
3336 }
3337
OperateShrine(int pnum,int i,int sType)3338 void OperateShrine(int pnum, int i, int sType)
3339 {
3340 int cnt;
3341 int r, j;
3342 DWORD lv, t;
3343 int xx, yy;
3344 int v1, v2, v3, v4;
3345
3346 if (dropGoldFlag) {
3347 dropGoldFlag = FALSE;
3348 dropGoldValue = 0;
3349 }
3350
3351 assert((DWORD)i < MAXOBJECTS);
3352
3353 if (object[i]._oSelFlag == 0)
3354 return;
3355
3356 SetRndSeed(object[i]._oRndSeed);
3357 object[i]._oSelFlag = 0;
3358
3359 if (!deltaload) {
3360 PlaySfxLoc(sType, object[i]._ox, object[i]._oy);
3361 object[i]._oAnimFlag = 1;
3362 object[i]._oAnimDelay = 1;
3363 } else {
3364 object[i]._oAnimFrame = object[i]._oAnimLen;
3365 object[i]._oAnimFlag = 0;
3366 }
3367 switch (object[i]._oVar1) {
3368 case SHRINE_MYSTERIOUS:
3369 if (deltaload)
3370 return;
3371 if (pnum != myplr)
3372 return;
3373 ModifyPlrStr(pnum, -1);
3374 ModifyPlrMag(pnum, -1);
3375 ModifyPlrDex(pnum, -1);
3376 ModifyPlrVit(pnum, -1);
3377 switch (random_(0, 4)) {
3378 case 0:
3379 ModifyPlrStr(pnum, 6);
3380 break;
3381 case 1:
3382 ModifyPlrMag(pnum, 6);
3383 break;
3384 case 2:
3385 ModifyPlrDex(pnum, 6);
3386 break;
3387 case 3:
3388 ModifyPlrVit(pnum, 6);
3389 break;
3390 }
3391 CheckStats(pnum);
3392 InitDiabloMsg(EMSG_SHRINE_MYSTERIOUS);
3393 break;
3394 case SHRINE_HIDDEN:
3395 cnt = 0;
3396 if (deltaload)
3397 return;
3398 if (pnum != myplr)
3399 return;
3400 for (j = 0; j < NUM_INVLOC; j++) {
3401 if (!plr[pnum].InvBody[j].isEmpty())
3402 cnt++;
3403 }
3404 if (cnt > 0) {
3405 for (j = 0; j < NUM_INVLOC; j++) {
3406 if (!plr[pnum].InvBody[j].isEmpty()
3407 && plr[pnum].InvBody[j]._iMaxDur != DUR_INDESTRUCTIBLE
3408 && plr[pnum].InvBody[j]._iMaxDur != 0) {
3409 plr[pnum].InvBody[j]._iDurability += 10;
3410 plr[pnum].InvBody[j]._iMaxDur += 10;
3411 if (plr[pnum].InvBody[j]._iDurability > plr[pnum].InvBody[j]._iMaxDur)
3412 plr[pnum].InvBody[j]._iDurability = plr[pnum].InvBody[j]._iMaxDur;
3413 }
3414 }
3415 while (TRUE) {
3416 cnt = 0;
3417 for (j = 0; j < NUM_INVLOC; j++) {
3418 if (!plr[pnum].InvBody[j].isEmpty())
3419 if (plr[pnum].InvBody[j]._iMaxDur != DUR_INDESTRUCTIBLE
3420 && plr[pnum].InvBody[j]._iMaxDur != 0)
3421 cnt++;
3422 }
3423 if (cnt == 0)
3424 break;
3425 r = random_(0, NUM_INVLOC);
3426 if (plr[pnum].InvBody[r].isEmpty() || plr[pnum].InvBody[r]._iMaxDur == DUR_INDESTRUCTIBLE || plr[pnum].InvBody[r]._iMaxDur == 0)
3427 continue;
3428
3429 plr[pnum].InvBody[r]._iDurability -= 20;
3430 plr[pnum].InvBody[r]._iMaxDur -= 20;
3431 if (plr[pnum].InvBody[r]._iDurability <= 0)
3432 plr[pnum].InvBody[r]._iDurability = 1;
3433 if (plr[pnum].InvBody[r]._iMaxDur <= 0)
3434 plr[pnum].InvBody[r]._iMaxDur = 1;
3435 break;
3436 }
3437 }
3438 InitDiabloMsg(EMSG_SHRINE_HIDDEN);
3439 break;
3440 case SHRINE_GLOOMY:
3441 if (deltaload)
3442 return;
3443 if (pnum != myplr)
3444 break;
3445 if (!plr[pnum].InvBody[INVLOC_HEAD].isEmpty())
3446 plr[pnum].InvBody[INVLOC_HEAD]._iAC += 2;
3447 if (!plr[pnum].InvBody[INVLOC_CHEST].isEmpty())
3448 plr[pnum].InvBody[INVLOC_CHEST]._iAC += 2;
3449 if (!plr[pnum].InvBody[INVLOC_HAND_LEFT].isEmpty()) {
3450 if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype == ITYPE_SHIELD) {
3451 plr[pnum].InvBody[INVLOC_HAND_LEFT]._iAC += 2;
3452 } else {
3453 plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMaxDam--;
3454 if (plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMaxDam < plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMinDam)
3455 plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMaxDam = plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMinDam;
3456 }
3457 }
3458 if (!plr[pnum].InvBody[INVLOC_HAND_RIGHT].isEmpty()) {
3459 if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype == ITYPE_SHIELD) {
3460 plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iAC += 2;
3461 } else {
3462 plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iMaxDam--;
3463 if (plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iMaxDam < plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iMinDam)
3464 plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iMaxDam = plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iMinDam;
3465 }
3466 }
3467 for (j = 0; j < plr[pnum]._pNumInv; j++) {
3468 switch (plr[pnum].InvList[j]._itype) {
3469 case ITYPE_SWORD:
3470 case ITYPE_AXE:
3471 case ITYPE_BOW:
3472 case ITYPE_MACE:
3473 case ITYPE_STAFF:
3474 plr[pnum].InvList[j]._iMaxDam--;
3475 if (plr[pnum].InvList[j]._iMaxDam < plr[pnum].InvList[j]._iMinDam)
3476 plr[pnum].InvList[j]._iMaxDam = plr[pnum].InvList[j]._iMinDam;
3477 break;
3478 case ITYPE_SHIELD:
3479 case ITYPE_HELM:
3480 case ITYPE_LARMOR:
3481 case ITYPE_MARMOR:
3482 case ITYPE_HARMOR:
3483 plr[pnum].InvList[j]._iAC += 2;
3484 break;
3485 default:
3486 break;
3487 }
3488 }
3489 InitDiabloMsg(EMSG_SHRINE_GLOOMY);
3490 break;
3491 case SHRINE_WEIRD:
3492 if (deltaload)
3493 return;
3494 if (pnum != myplr)
3495 break;
3496
3497 if (!plr[pnum].InvBody[INVLOC_HAND_LEFT].isEmpty() && plr[pnum].InvBody[INVLOC_HAND_LEFT]._itype != ITYPE_SHIELD)
3498 plr[pnum].InvBody[INVLOC_HAND_LEFT]._iMaxDam++;
3499 if (!plr[pnum].InvBody[INVLOC_HAND_RIGHT].isEmpty() && plr[pnum].InvBody[INVLOC_HAND_RIGHT]._itype != ITYPE_SHIELD)
3500 plr[pnum].InvBody[INVLOC_HAND_RIGHT]._iMaxDam++;
3501 for (j = 0; j < plr[pnum]._pNumInv; j++) {
3502 switch (plr[pnum].InvList[j]._itype) {
3503 case ITYPE_SWORD:
3504 case ITYPE_AXE:
3505 case ITYPE_BOW:
3506 case ITYPE_MACE:
3507 case ITYPE_STAFF:
3508 plr[pnum].InvList[j]._iMaxDam++;
3509 break;
3510 default:
3511 break;
3512 }
3513 }
3514 InitDiabloMsg(EMSG_SHRINE_WEIRD);
3515 break;
3516 case SHRINE_MAGICAL:
3517
3518 case SHRINE_MAGICAL2:
3519 if (deltaload)
3520 return;
3521 AddMissile(
3522 plr[pnum]._px,
3523 plr[pnum]._py,
3524 plr[pnum]._px,
3525 plr[pnum]._py,
3526 plr[pnum]._pdir,
3527 MIS_MANASHIELD,
3528 -1,
3529 pnum,
3530 0,
3531 2 * leveltype);
3532 if (pnum != myplr)
3533 return;
3534 InitDiabloMsg(EMSG_SHRINE_MAGICAL);
3535 break;
3536 case SHRINE_STONE:
3537 if (deltaload)
3538 return;
3539 if (pnum != myplr)
3540 break;
3541
3542 for (j = 0; j < NUM_INVLOC; j++) {
3543 if (plr[pnum].InvBody[j]._itype == ITYPE_STAFF)
3544 plr[pnum].InvBody[j]._iCharges = plr[pnum].InvBody[j]._iMaxCharges;
3545 }
3546 for (j = 0; j < plr[pnum]._pNumInv; j++) {
3547 if (plr[pnum].InvList[j]._itype == ITYPE_STAFF)
3548 plr[pnum].InvList[j]._iCharges = plr[pnum].InvList[j]._iMaxCharges;
3549 }
3550 for (j = 0; j < MAXBELTITEMS; j++) {
3551 if (plr[pnum].SpdList[j]._itype == ITYPE_STAFF)
3552 plr[pnum].SpdList[j]._iCharges = plr[pnum].SpdList[j]._iMaxCharges; // belt items don't have charges?
3553 }
3554 InitDiabloMsg(EMSG_SHRINE_STONE);
3555 break;
3556 case SHRINE_RELIGIOUS:
3557 if (deltaload)
3558 return;
3559 if (pnum != myplr)
3560 break;
3561
3562 for (j = 0; j < NUM_INVLOC; j++)
3563 plr[pnum].InvBody[j]._iDurability = plr[pnum].InvBody[j]._iMaxDur;
3564 for (j = 0; j < plr[pnum]._pNumInv; j++)
3565 plr[pnum].InvList[j]._iDurability = plr[pnum].InvList[j]._iMaxDur;
3566 for (j = 0; j < MAXBELTITEMS; j++)
3567 plr[pnum].SpdList[j]._iDurability = plr[pnum].SpdList[j]._iMaxDur; // belt items don't have durability?
3568 InitDiabloMsg(EMSG_SHRINE_RELIGIOUS);
3569 break;
3570 case SHRINE_ENCHANTED: {
3571 if (deltaload)
3572 return;
3573 if (pnum != myplr)
3574 return;
3575 cnt = 0;
3576 Uint64 spell = 1;
3577 int maxSpells = gbIsHellfire ? MAX_SPELLS : 37;
3578 Uint64 spells = plr[pnum]._pMemSpells;
3579 for (j = 0; j < maxSpells; j++) {
3580 if (spell & spells)
3581 cnt++;
3582 spell <<= 1;
3583 }
3584 if (cnt > 1) {
3585 spell = 1;
3586 for (j = SPL_FIREBOLT; j < maxSpells; j++) { // BUGFIX: < MAX_SPELLS, there is no spell with MAX_SPELLS index (fixed)
3587 if (plr[pnum]._pMemSpells & spell) {
3588 if (plr[pnum]._pSplLvl[j] < MAX_SPELL_LEVEL)
3589 plr[pnum]._pSplLvl[j]++;
3590 }
3591 spell <<= 1;
3592 }
3593 do {
3594 r = random_(0, maxSpells);
3595 } while (!(plr[pnum]._pMemSpells & GetSpellBitmask(r + 1)));
3596 if (plr[pnum]._pSplLvl[r + 1] >= 2)
3597 plr[pnum]._pSplLvl[r + 1] -= 2;
3598 else
3599 plr[pnum]._pSplLvl[r + 1] = 0;
3600 }
3601 InitDiabloMsg(EMSG_SHRINE_ENCHANTED);
3602 break;
3603 }
3604 case SHRINE_THAUMATURGIC:
3605 for (j = 0; j < nobjects; j++) {
3606 v1 = objectactive[j];
3607 assert((DWORD)v1 < MAXOBJECTS);
3608 if ((object[v1]._otype == OBJ_CHEST1
3609 || object[v1]._otype == OBJ_CHEST2
3610 || object[v1]._otype == OBJ_CHEST3)
3611 && object[v1]._oSelFlag == 0) {
3612 object[v1]._oRndSeed = AdvanceRndSeed();
3613 object[v1]._oSelFlag = 1;
3614 object[v1]._oAnimFrame -= 2;
3615 }
3616 }
3617 if (deltaload)
3618 return;
3619 if (pnum == myplr)
3620 InitDiabloMsg(EMSG_SHRINE_THAUMATURGIC);
3621 break;
3622 case SHRINE_FASCINATING:
3623 if (deltaload)
3624 return;
3625 if (pnum != myplr)
3626 return;
3627 plr[pnum]._pMemSpells |= GetSpellBitmask(SPL_FIREBOLT);
3628 if (plr[pnum]._pSplLvl[SPL_FIREBOLT] < MAX_SPELL_LEVEL)
3629 plr[pnum]._pSplLvl[SPL_FIREBOLT]++;
3630 if (plr[pnum]._pSplLvl[SPL_FIREBOLT] < MAX_SPELL_LEVEL)
3631 plr[pnum]._pSplLvl[SPL_FIREBOLT]++;
3632 t = plr[pnum]._pMaxManaBase / 10;
3633 v1 = plr[pnum]._pMana - plr[pnum]._pManaBase;
3634 v2 = plr[pnum]._pMaxMana - plr[pnum]._pMaxManaBase;
3635
3636 plr[pnum]._pManaBase -= t;
3637 plr[pnum]._pMana -= t;
3638 plr[pnum]._pMaxMana -= t;
3639 plr[pnum]._pMaxManaBase -= t;
3640 if (plr[pnum]._pMana >> 6 <= 0) {
3641 plr[pnum]._pMana = v1;
3642 plr[pnum]._pManaBase = 0;
3643 }
3644 if (plr[pnum]._pMaxMana >> 6 <= 0) {
3645 plr[pnum]._pMaxMana = v2;
3646 plr[pnum]._pMaxManaBase = 0;
3647 }
3648 InitDiabloMsg(EMSG_SHRINE_FASCINATING);
3649 break;
3650 case SHRINE_CRYPTIC:
3651 if (deltaload)
3652 return;
3653 AddMissile(
3654 plr[pnum]._px,
3655 plr[pnum]._py,
3656 plr[pnum]._px,
3657 plr[pnum]._py,
3658 plr[pnum]._pdir,
3659 MIS_NOVA,
3660 -1,
3661 pnum,
3662 0,
3663 2 * leveltype);
3664 if (pnum != myplr)
3665 return;
3666 plr[pnum]._pMana = plr[pnum]._pMaxMana;
3667 plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase;
3668 InitDiabloMsg(EMSG_SHRINE_CRYPTIC);
3669 break;
3670 case SHRINE_ELDRITCH: /// BUGFIX: change `plr[pnum].HoldItem` to use a temporary buffer to prevent deleting item in hand
3671 if (deltaload)
3672 return;
3673 if (pnum != myplr)
3674 break;
3675 for (j = 0; j < plr[pnum]._pNumInv; j++) {
3676 if (plr[pnum].InvList[j]._itype == ITYPE_MISC) {
3677 if (plr[pnum].InvList[j]._iMiscId == IMISC_HEAL
3678 || plr[pnum].InvList[j]._iMiscId == IMISC_MANA) {
3679 SetPlrHandItem(&plr[pnum].HoldItem, ItemMiscIdIdx(IMISC_REJUV));
3680 GetPlrHandSeed(&plr[pnum].HoldItem);
3681 plr[pnum].HoldItem._iStatFlag = TRUE;
3682 plr[pnum].InvList[j] = plr[pnum].HoldItem;
3683 }
3684 if (plr[pnum].InvList[j]._iMiscId == IMISC_FULLHEAL
3685 || plr[pnum].InvList[j]._iMiscId == IMISC_FULLMANA) {
3686 SetPlrHandItem(&plr[pnum].HoldItem, ItemMiscIdIdx(IMISC_FULLREJUV));
3687 GetPlrHandSeed(&plr[pnum].HoldItem);
3688 plr[pnum].HoldItem._iStatFlag = TRUE;
3689 plr[pnum].InvList[j] = plr[pnum].HoldItem;
3690 }
3691 }
3692 }
3693 for (j = 0; j < MAXBELTITEMS; j++) {
3694 if (plr[pnum].SpdList[j]._itype == ITYPE_MISC) {
3695 if (plr[pnum].SpdList[j]._iMiscId == IMISC_HEAL
3696 || plr[pnum].SpdList[j]._iMiscId == IMISC_MANA) {
3697 SetPlrHandItem(&plr[pnum].HoldItem, ItemMiscIdIdx(IMISC_REJUV));
3698 GetPlrHandSeed(&plr[pnum].HoldItem);
3699 plr[pnum].HoldItem._iStatFlag = TRUE;
3700 plr[pnum].SpdList[j] = plr[pnum].HoldItem;
3701 }
3702 if (plr[pnum].SpdList[j]._iMiscId == IMISC_FULLHEAL
3703 || plr[pnum].SpdList[j]._iMiscId == IMISC_FULLMANA) {
3704 SetPlrHandItem(&plr[pnum].HoldItem, ItemMiscIdIdx(IMISC_FULLREJUV));
3705 GetPlrHandSeed(&plr[pnum].HoldItem);
3706 plr[pnum].HoldItem._iStatFlag = TRUE;
3707 plr[pnum].SpdList[j] = plr[pnum].HoldItem;
3708 }
3709 }
3710 }
3711 InitDiabloMsg(EMSG_SHRINE_ELDRITCH);
3712 break;
3713 case SHRINE_EERIE:
3714 if (deltaload)
3715 return;
3716 if (pnum != myplr)
3717 return;
3718 ModifyPlrMag(pnum, 2);
3719 CheckStats(pnum);
3720 InitDiabloMsg(EMSG_SHRINE_EERIE);
3721 break;
3722 case SHRINE_DIVINE:
3723 if (deltaload)
3724 return;
3725 if (pnum != myplr)
3726 return;
3727 if (2 * currlevel < 7) {
3728 CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLMANA, FALSE, TRUE);
3729 CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLHEAL, FALSE, TRUE);
3730 } else {
3731 CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLREJUV, FALSE, TRUE);
3732 CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_FULLREJUV, FALSE, TRUE);
3733 }
3734 plr[pnum]._pMana = plr[pnum]._pMaxMana;
3735 plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase;
3736 plr[pnum]._pHitPoints = plr[pnum]._pMaxHP;
3737 plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase;
3738 InitDiabloMsg(EMSG_SHRINE_DIVINE);
3739 break;
3740 case SHRINE_HOLY:
3741 if (deltaload)
3742 return;
3743 j = 0;
3744 do {
3745 xx = random_(159, MAXDUNX);
3746 yy = random_(159, MAXDUNY);
3747 lv = dPiece[xx][yy];
3748 j++;
3749 if (j > MAXDUNX * MAXDUNY)
3750 break;
3751 } while (nSolidTable[lv] || dObject[xx][yy] != 0 || dMonster[xx][yy] != 0);
3752 AddMissile(plr[pnum]._px, plr[pnum]._py, xx, yy, plr[pnum]._pdir, MIS_RNDTELEPORT, -1, pnum, 0, 2 * leveltype);
3753 if (pnum != myplr)
3754 return;
3755 InitDiabloMsg(EMSG_SHRINE_HOLY);
3756 break;
3757 case SHRINE_SACRED:
3758 if (deltaload || pnum != myplr)
3759 return;
3760 plr[pnum]._pMemSpells |= GetSpellBitmask(SPL_CBOLT);
3761 if (plr[pnum]._pSplLvl[SPL_CBOLT] < MAX_SPELL_LEVEL)
3762 plr[pnum]._pSplLvl[SPL_CBOLT]++;
3763 if (plr[pnum]._pSplLvl[SPL_CBOLT] < MAX_SPELL_LEVEL)
3764 plr[pnum]._pSplLvl[SPL_CBOLT]++;
3765 t = plr[pnum]._pMaxManaBase / 10;
3766 v1 = plr[pnum]._pMana - plr[pnum]._pManaBase;
3767 v2 = plr[pnum]._pMaxMana - plr[pnum]._pMaxManaBase;
3768 plr[pnum]._pManaBase -= t;
3769 plr[pnum]._pMana -= t;
3770 plr[pnum]._pMaxMana -= t;
3771 plr[pnum]._pMaxManaBase -= t;
3772 if (plr[pnum]._pMana >> 6 <= 0) {
3773 plr[pnum]._pMana = v1;
3774 plr[pnum]._pManaBase = 0;
3775 }
3776 if (plr[pnum]._pMaxMana >> 6 <= 0) {
3777 plr[pnum]._pMaxMana = v2;
3778 plr[pnum]._pMaxManaBase = 0;
3779 }
3780 InitDiabloMsg(EMSG_SHRINE_SACRED);
3781 break;
3782 case SHRINE_SPIRITUAL:
3783 if (deltaload)
3784 return;
3785 if (pnum != myplr)
3786 return;
3787 for (j = 0; j < NUM_INV_GRID_ELEM; j++) {
3788 if (plr[pnum].InvGrid[j] == 0) {
3789 r = 5 * leveltype + random_(160, 10 * leveltype);
3790 t = plr[pnum]._pNumInv; // check
3791 plr[pnum].InvList[t] = golditem;
3792 plr[pnum].InvList[t]._iSeed = AdvanceRndSeed();
3793 plr[pnum]._pNumInv++;
3794 plr[pnum].InvGrid[j] = plr[pnum]._pNumInv;
3795 plr[pnum].InvList[t]._ivalue = r;
3796 plr[pnum]._pGold += r;
3797 SetGoldCurs(pnum, t);
3798 }
3799 }
3800 InitDiabloMsg(EMSG_SHRINE_SPIRITUAL);
3801 break;
3802 case SHRINE_SPOOKY:
3803 if (deltaload)
3804 return;
3805 if (pnum == myplr) {
3806 InitDiabloMsg(EMSG_SHRINE_SPOOKY1);
3807 } else {
3808 InitDiabloMsg(EMSG_SHRINE_SPOOKY2);
3809 plr[myplr]._pHitPoints = plr[myplr]._pMaxHP;
3810 plr[myplr]._pHPBase = plr[myplr]._pMaxHPBase;
3811 plr[myplr]._pMana = plr[myplr]._pMaxMana;
3812 plr[myplr]._pManaBase = plr[myplr]._pMaxManaBase;
3813 }
3814 break;
3815 case SHRINE_ABANDONED:
3816 if (deltaload)
3817 return;
3818 if (pnum != myplr)
3819 return;
3820 ModifyPlrDex(pnum, 2);
3821 CheckStats(pnum);
3822 if (pnum == myplr)
3823 InitDiabloMsg(EMSG_SHRINE_ABANDONED);
3824 break;
3825 case SHRINE_CREEPY:
3826 if (deltaload)
3827 return;
3828 if (pnum != myplr)
3829 return;
3830 ModifyPlrStr(pnum, 2);
3831 CheckStats(pnum);
3832 if (pnum == myplr)
3833 InitDiabloMsg(EMSG_SHRINE_CREEPY);
3834 break;
3835 case SHRINE_QUIET:
3836 if (deltaload)
3837 return;
3838 if (pnum != myplr)
3839 return;
3840 ModifyPlrVit(pnum, 2);
3841 CheckStats(pnum);
3842 if (pnum == myplr)
3843 InitDiabloMsg(EMSG_SHRINE_QUIET);
3844 break;
3845 case SHRINE_SECLUDED:
3846 if (deltaload)
3847 return;
3848 if (pnum != myplr)
3849 break;
3850
3851 for (yy = 0; yy < DMAXY; yy++) {
3852 for (xx = 0; xx < DMAXX; xx++) {
3853 automapview[xx][yy] = TRUE;
3854 }
3855 }
3856 InitDiabloMsg(EMSG_SHRINE_SECLUDED);
3857 break;
3858 case SHRINE_ORNATE:
3859 if (deltaload)
3860 return;
3861 if (pnum != myplr)
3862 return;
3863 plr[pnum]._pMemSpells |= GetSpellBitmask(SPL_HBOLT);
3864 if (plr[pnum]._pSplLvl[SPL_HBOLT] < MAX_SPELL_LEVEL)
3865 plr[pnum]._pSplLvl[SPL_HBOLT]++;
3866 if (plr[pnum]._pSplLvl[SPL_HBOLT] < MAX_SPELL_LEVEL)
3867 plr[pnum]._pSplLvl[SPL_HBOLT]++;
3868 t = plr[pnum]._pMaxManaBase / 10;
3869 v1 = plr[pnum]._pMana - plr[pnum]._pManaBase;
3870 v2 = plr[pnum]._pMaxMana - plr[pnum]._pMaxManaBase;
3871 plr[pnum]._pManaBase -= t;
3872 plr[pnum]._pMana -= t;
3873 plr[pnum]._pMaxMana -= t;
3874 plr[pnum]._pMaxManaBase -= t;
3875 if (plr[pnum]._pMana >> 6 <= 0) {
3876 plr[pnum]._pMana = v1;
3877 plr[pnum]._pManaBase = 0;
3878 }
3879 if (plr[pnum]._pMaxMana >> 6 <= 0) {
3880 plr[pnum]._pMaxMana = v2;
3881 plr[pnum]._pMaxManaBase = 0;
3882 }
3883 InitDiabloMsg(EMSG_SHRINE_ORNATE);
3884 break;
3885 case SHRINE_GLIMMERING:
3886 if (deltaload)
3887 return;
3888 if (pnum != myplr)
3889 return;
3890 for (j = 0; j < NUM_INVLOC; j++) {
3891 if (plr[pnum].InvBody[j]._iMagical && !plr[pnum].InvBody[j]._iIdentified)
3892 plr[pnum].InvBody[j]._iIdentified = TRUE;
3893 }
3894 for (j = 0; j < plr[pnum]._pNumInv; j++) {
3895 if (plr[pnum].InvList[j]._iMagical && !plr[pnum].InvList[j]._iIdentified)
3896 plr[pnum].InvList[j]._iIdentified = TRUE;
3897 }
3898 for (j = 0; j < MAXBELTITEMS; j++) {
3899 if (plr[pnum].SpdList[j]._iMagical && !plr[pnum].SpdList[j]._iIdentified)
3900 plr[pnum].SpdList[j]._iIdentified = TRUE; // belt items can't be magical?
3901 }
3902 InitDiabloMsg(EMSG_SHRINE_GLIMMERING);
3903 break;
3904 case SHRINE_TAINTED:
3905 if (deltaload)
3906 return;
3907 if (pnum == myplr) {
3908 InitDiabloMsg(EMSG_SHRINE_TAINTED1);
3909 } else {
3910 InitDiabloMsg(EMSG_SHRINE_TAINTED2);
3911 r = random_(155, 4);
3912
3913 if (r != 0)
3914 v1 = -1;
3915 else
3916 v1 = 1;
3917 if (r != 1)
3918 v2 = -1;
3919 else
3920 v2 = 1;
3921 if (r == 2)
3922 v3 = 1;
3923 else
3924 v3 = -1;
3925 if (r == 3)
3926 v4 = 1;
3927 else
3928 v4 = -1;
3929
3930 ModifyPlrStr(myplr, v1);
3931 ModifyPlrMag(myplr, v2);
3932 ModifyPlrDex(myplr, v3);
3933 ModifyPlrVit(myplr, v4);
3934
3935 CheckStats(myplr);
3936 }
3937 break;
3938 case SHRINE_OILY:
3939 if (deltaload)
3940 return;
3941 if (pnum != myplr)
3942 return;
3943 InitDiabloMsg(EMSG_SHRINE_OILY);
3944
3945 switch (plr[myplr]._pClass) {
3946 case PC_WARRIOR:
3947 ModifyPlrStr(myplr, 2);
3948 break;
3949 case PC_ROGUE:
3950 ModifyPlrDex(myplr, 2);
3951 break;
3952 case PC_SORCERER:
3953 ModifyPlrMag(myplr, 2);
3954 break;
3955 case PC_BARBARIAN:
3956 ModifyPlrVit(myplr, 2);
3957 break;
3958 case PC_MONK:
3959 ModifyPlrStr(myplr, 1);
3960 ModifyPlrDex(myplr, 1);
3961 break;
3962 case PC_BARD:
3963 ModifyPlrDex(myplr, 1);
3964 ModifyPlrMag(myplr, 1);
3965 break;
3966 case NUM_CLASSES:
3967 break;
3968 }
3969 CheckStats(pnum);
3970 AddMissile(
3971 object[i]._ox,
3972 object[i]._oy,
3973 plr[myplr]._px,
3974 plr[myplr]._py,
3975 plr[myplr]._pdir,
3976 MIS_FIREWALL,
3977 TARGET_PLAYERS,
3978 -1,
3979 2 * currlevel + 2,
3980 0);
3981 break;
3982
3983 case SHRINE_GLOWING: {
3984 if (deltaload)
3985 return;
3986 if (pnum != myplr)
3987 return;
3988 InitDiabloMsg(EMSG_SHRINE_GLOWING);
3989 int playerXP = plr[myplr]._pExperience;
3990 Sint32 xpLoss, magicGain;
3991 if (playerXP > 5000) {
3992 magicGain = 5;
3993 xpLoss = ((double)playerXP * 0.95);
3994 } else {
3995 magicGain = playerXP / 1000;
3996 xpLoss = 0;
3997 }
3998 ModifyPlrMag(myplr, magicGain);
3999 plr[myplr]._pExperience = xpLoss;
4000 if (sgOptions.Gameplay.bExperienceBar) {
4001 force_redraw = 255;
4002 }
4003 CheckStats(pnum);
4004 } break;
4005
4006 case SHRINE_MENDICANT: {
4007 if (deltaload)
4008 return;
4009 if (pnum != myplr)
4010 return;
4011 InitDiabloMsg(EMSG_SHRINE_MENDICANT);
4012 int gold = plr[myplr]._pGold / 2;
4013 AddPlrExperience(myplr, plr[myplr]._pLevel, gold);
4014 TakePlrsMoney(gold);
4015 CheckStats(pnum);
4016 } break;
4017 case SHRINE_SPARKLING:
4018 if (deltaload)
4019 return;
4020 if (pnum != myplr)
4021 return;
4022 InitDiabloMsg(EMSG_SHRINE_SPARKLING);
4023 AddPlrExperience(myplr, plr[myplr]._pLevel, 1000 * currlevel);
4024 AddMissile(
4025 object[i]._ox,
4026 object[i]._oy,
4027 plr[myplr]._px,
4028 plr[myplr]._py,
4029 plr[myplr]._pdir,
4030 MIS_FLASH,
4031 TARGET_PLAYERS,
4032 -1,
4033 3 * currlevel + 2,
4034 0);
4035 CheckStats(pnum);
4036 break;
4037 case SHRINE_TOWN:
4038 if (deltaload)
4039 return;
4040 if (pnum != myplr)
4041 return;
4042 InitDiabloMsg(EMSG_SHRINE_TOWN);
4043 AddMissile(
4044 object[i]._ox,
4045 object[i]._oy,
4046 plr[myplr]._px,
4047 plr[myplr]._py,
4048 plr[myplr]._pdir,
4049 MIS_TOWN,
4050 TARGET_PLAYERS,
4051 pnum,
4052 0,
4053 0);
4054 break;
4055 case SHRINE_SHIMMERING:
4056 if (deltaload)
4057 return;
4058 if (pnum != myplr)
4059 return;
4060 InitDiabloMsg(EMSG_SHRINE_SHIMMERING);
4061 plr[pnum]._pMana = plr[pnum]._pMaxMana;
4062 plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase;
4063 break;
4064
4065 case SHRINE_SOLAR: {
4066 if (deltaload)
4067 return;
4068 if (pnum != myplr)
4069 return;
4070 time_t tm = time(0);
4071 int hour = localtime(&tm)->tm_hour;
4072 if (hour > 20 || hour < 4) {
4073 InitDiabloMsg(EMSG_SHRINE_SOLAR4);
4074 ModifyPlrVit(myplr, 2);
4075 } else if (hour > 18) {
4076 InitDiabloMsg(EMSG_SHRINE_SOLAR3);
4077 ModifyPlrMag(myplr, 2);
4078 } else if (hour > 12) {
4079 InitDiabloMsg(EMSG_SHRINE_SOLAR2);
4080 ModifyPlrStr(myplr, 2);
4081 } else if (hour > 4) {
4082 InitDiabloMsg(EMSG_SHRINE_SOLAR1);
4083 ModifyPlrDex(myplr, 2);
4084 }
4085 CheckStats(pnum);
4086 } break;
4087
4088 case SHRINE_MURPHYS:
4089 if (deltaload)
4090 return;
4091 if (pnum != myplr)
4092 return;
4093 InitDiabloMsg(EMSG_SHRINE_MURPHYS);
4094 BOOL broke = FALSE;
4095 for (int j = 0; j < NUM_INVLOC; j++) {
4096 ItemStruct *item = &plr[myplr].InvBody[j];
4097 if (!item->isEmpty() && random_(0, 3) == 0) {
4098 if (item->_iDurability != DUR_INDESTRUCTIBLE) {
4099 if (item->_iDurability) {
4100 item->_iDurability /= 2;
4101 broke = TRUE;
4102 break;
4103 }
4104 }
4105 }
4106 }
4107 if (!broke) {
4108 TakePlrsMoney(plr[myplr]._pGold / 3);
4109 }
4110 break;
4111 }
4112
4113 CalcPlrInv(pnum, TRUE);
4114 force_redraw = 255;
4115
4116 if (pnum == myplr)
4117 NetSendCmdParam2(FALSE, CMD_PLROPOBJ, pnum, i);
4118 }
4119
OperateSkelBook(int pnum,int i,bool sendmsg)4120 void OperateSkelBook(int pnum, int i, bool sendmsg)
4121 {
4122 if (object[i]._oSelFlag != 0) {
4123 if (!deltaload)
4124 PlaySfxLoc(IS_ISCROL, object[i]._ox, object[i]._oy);
4125 object[i]._oSelFlag = 0;
4126 object[i]._oAnimFrame += 2;
4127 if (!deltaload) {
4128 SetRndSeed(object[i]._oRndSeed);
4129 if (random_(161, 5) != 0)
4130 CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_SCROLL, sendmsg, FALSE);
4131 else
4132 CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_BOOK, sendmsg, FALSE);
4133 if (pnum == myplr)
4134 NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i);
4135 }
4136 }
4137 }
4138
OperateBookCase(int pnum,int i,bool sendmsg)4139 void OperateBookCase(int pnum, int i, bool sendmsg)
4140 {
4141 if (object[i]._oSelFlag != 0) {
4142 if (!deltaload)
4143 PlaySfxLoc(IS_ISCROL, object[i]._ox, object[i]._oy);
4144 object[i]._oSelFlag = 0;
4145 object[i]._oAnimFrame -= 2;
4146 if (!deltaload) {
4147 SetRndSeed(object[i]._oRndSeed);
4148 CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_MISC, IMISC_BOOK, sendmsg, FALSE);
4149 if (QuestStatus(Q_ZHAR)
4150 && monster[MAX_PLRS]._uniqtype - 1 == UMT_ZHAR
4151 && monster[MAX_PLRS]._msquelch == UCHAR_MAX
4152 && monster[MAX_PLRS]._mhitpoints) {
4153 monster[MAX_PLRS].mtalkmsg = TEXT_ZHAR2;
4154 M_StartStand(0, monster[MAX_PLRS]._mdir);
4155 monster[MAX_PLRS]._mgoal = MGOAL_ATTACK2;
4156 monster[MAX_PLRS]._mmode = MM_TALK;
4157 }
4158 if (pnum == myplr)
4159 NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i);
4160 }
4161 }
4162 }
4163
OperateDecap(int pnum,int i,bool sendmsg)4164 void OperateDecap(int pnum, int i, bool sendmsg)
4165 {
4166 if (object[i]._oSelFlag != 0) {
4167 object[i]._oSelFlag = 0;
4168 if (!deltaload) {
4169 SetRndSeed(object[i]._oRndSeed);
4170 CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE);
4171 if (pnum == myplr)
4172 NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i);
4173 }
4174 }
4175 }
4176
OperateArmorStand(int pnum,int i,bool sendmsg)4177 void OperateArmorStand(int pnum, int i, bool sendmsg)
4178 {
4179 BOOL uniqueRnd;
4180
4181 if (object[i]._oSelFlag != 0) {
4182 object[i]._oSelFlag = 0;
4183 object[i]._oAnimFrame++;
4184 if (!deltaload) {
4185 SetRndSeed(object[i]._oRndSeed);
4186 uniqueRnd = random_(0, 2);
4187 if (currlevel <= 5) {
4188 CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, ITYPE_LARMOR, IMISC_NONE, sendmsg, FALSE);
4189 } else if (currlevel >= 6 && currlevel <= 9) {
4190 CreateTypeItem(object[i]._ox, object[i]._oy, uniqueRnd, ITYPE_MARMOR, IMISC_NONE, sendmsg, FALSE);
4191 } else if (currlevel >= 10 && currlevel <= 12) {
4192 CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, ITYPE_HARMOR, IMISC_NONE, sendmsg, FALSE);
4193 } else if (currlevel >= 13 && currlevel <= 16) {
4194 CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, ITYPE_HARMOR, IMISC_NONE, sendmsg, FALSE);
4195 } else if (currlevel >= 17) {
4196 CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, ITYPE_HARMOR, IMISC_NONE, sendmsg, FALSE);
4197 }
4198 if (pnum == myplr)
4199 NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i);
4200 return;
4201 }
4202 }
4203 }
4204
FindValidShrine(int i)4205 int FindValidShrine(int i)
4206 {
4207 int rv;
4208 bool done;
4209
4210 done = FALSE;
4211 do {
4212 rv = random_(0, gbIsHellfire ? NUM_SHRINETYPE : 26);
4213 if (currlevel >= shrinemin[rv] && currlevel <= shrinemax[rv] && rv != SHRINE_THAUMATURGIC) {
4214 done = TRUE;
4215 }
4216 if (done) {
4217 if (gbIsMultiplayer) {
4218 if (shrineavail[rv] == 1) {
4219 done = FALSE;
4220 continue;
4221 }
4222 }
4223 if (!gbIsMultiplayer) {
4224 if (shrineavail[rv] == 2) {
4225 done = FALSE;
4226 continue;
4227 }
4228 }
4229 done = TRUE;
4230 }
4231 } while (!done);
4232 return rv;
4233 }
4234
OperateGoatShrine(int pnum,int i,int sType)4235 void OperateGoatShrine(int pnum, int i, int sType)
4236 {
4237 SetRndSeed(object[i]._oRndSeed);
4238 object[i]._oVar1 = FindValidShrine(i);
4239 OperateShrine(pnum, i, sType);
4240 object[i]._oAnimDelay = 2;
4241 force_redraw = 255;
4242 }
4243
OperateCauldron(int pnum,int i,int sType)4244 void OperateCauldron(int pnum, int i, int sType)
4245 {
4246 SetRndSeed(object[i]._oRndSeed);
4247 object[i]._oVar1 = FindValidShrine(i);
4248 OperateShrine(pnum, i, sType);
4249 object[i]._oAnimFrame = 3;
4250 object[i]._oAnimFlag = 0;
4251 force_redraw = 255;
4252 }
4253
OperateFountains(int pnum,int i)4254 bool OperateFountains(int pnum, int i)
4255 {
4256 int prev, add, rnd, cnt;
4257 bool applied;
4258 BOOL done;
4259
4260 applied = FALSE;
4261 SetRndSeed(object[i]._oRndSeed);
4262 switch (object[i]._otype) {
4263 case OBJ_BLOODFTN:
4264 if (deltaload)
4265 return FALSE;
4266 if (pnum != myplr)
4267 return FALSE;
4268
4269 if (plr[pnum]._pHitPoints < plr[pnum]._pMaxHP) {
4270 PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy);
4271 plr[pnum]._pHitPoints += 64;
4272 plr[pnum]._pHPBase += 64;
4273 if (plr[pnum]._pHitPoints > plr[pnum]._pMaxHP) {
4274 plr[pnum]._pHitPoints = plr[pnum]._pMaxHP;
4275 plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase;
4276 }
4277 applied = TRUE;
4278 } else
4279 PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy);
4280 break;
4281 case OBJ_PURIFYINGFTN:
4282 if (deltaload)
4283 return FALSE;
4284 if (pnum != myplr)
4285 return FALSE;
4286
4287 if (plr[pnum]._pMana < plr[pnum]._pMaxMana) {
4288 PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy);
4289
4290 plr[pnum]._pMana += 64;
4291 plr[pnum]._pManaBase += 64;
4292 if (plr[pnum]._pMana > plr[pnum]._pMaxMana) {
4293 plr[pnum]._pMana = plr[pnum]._pMaxMana;
4294 plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase;
4295 }
4296
4297 applied = TRUE;
4298 } else
4299 PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy);
4300 break;
4301 case OBJ_MURKYFTN:
4302 if (object[i]._oSelFlag == 0)
4303 break;
4304 if (!deltaload)
4305 PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy);
4306 object[i]._oSelFlag = 0;
4307 if (deltaload)
4308 return FALSE;
4309 AddMissile(
4310 plr[pnum]._px,
4311 plr[pnum]._py,
4312 plr[pnum]._px,
4313 plr[pnum]._py,
4314 plr[pnum]._pdir,
4315 MIS_INFRA,
4316 -1,
4317 pnum,
4318 0,
4319 2 * leveltype);
4320 applied = TRUE;
4321 if (pnum == myplr)
4322 NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i);
4323 break;
4324 case OBJ_TEARFTN:
4325 if (object[i]._oSelFlag == 0)
4326 break;
4327 prev = -1;
4328 add = -1;
4329 done = FALSE;
4330 cnt = 0;
4331 if (!deltaload)
4332 PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy);
4333 object[i]._oSelFlag = 0;
4334 if (deltaload)
4335 return FALSE;
4336 if (pnum != myplr)
4337 return FALSE;
4338 while (!done) {
4339 rnd = random_(0, 4);
4340 if (rnd != prev) {
4341 switch (rnd) {
4342 case 0:
4343 ModifyPlrStr(pnum, add);
4344 break;
4345 case 1:
4346 ModifyPlrMag(pnum, add);
4347 break;
4348 case 2:
4349 ModifyPlrDex(pnum, add);
4350 break;
4351 case 3:
4352 ModifyPlrVit(pnum, add);
4353 break;
4354 }
4355 prev = rnd;
4356 add = 1;
4357 cnt++;
4358 }
4359 if (cnt <= 1)
4360 continue;
4361
4362 done = TRUE;
4363 }
4364 CheckStats(pnum);
4365 applied = TRUE;
4366 if (pnum == myplr)
4367 NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i);
4368 break;
4369 }
4370 force_redraw = 255;
4371 return applied;
4372 }
4373
OperateWeaponRack(int pnum,int i,bool sendmsg)4374 void OperateWeaponRack(int pnum, int i, bool sendmsg)
4375 {
4376 int weaponType;
4377
4378 if (object[i]._oSelFlag == 0)
4379 return;
4380 SetRndSeed(object[i]._oRndSeed);
4381
4382 switch (random_(0, 4) + ITYPE_SWORD) {
4383 case ITYPE_SWORD:
4384 weaponType = ITYPE_SWORD;
4385 break;
4386 case ITYPE_AXE:
4387 weaponType = ITYPE_AXE;
4388 break;
4389 case ITYPE_BOW:
4390 weaponType = ITYPE_BOW;
4391 break;
4392 case ITYPE_MACE:
4393 weaponType = ITYPE_MACE;
4394 break;
4395 }
4396
4397 object[i]._oSelFlag = 0;
4398 object[i]._oAnimFrame++;
4399 if (deltaload)
4400 return;
4401
4402 CreateTypeItem(object[i]._ox, object[i]._oy, leveltype > 1, weaponType, IMISC_NONE, sendmsg, FALSE);
4403
4404 if (pnum == myplr)
4405 NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i);
4406 }
4407
OperateStoryBook(int pnum,int i)4408 void OperateStoryBook(int pnum, int i)
4409 {
4410 if (object[i]._oSelFlag != 0 && !deltaload && !qtextflag && pnum == myplr) {
4411 object[i]._oAnimFrame = object[i]._oVar4;
4412 PlaySfxLoc(IS_ISCROL, object[i]._ox, object[i]._oy);
4413 if (object[i]._oVar8 != 0 && currlevel == 24) {
4414 if (IsUberLeverActivated != 1 && quests[Q_NAKRUL]._qactive != 3 && objects_lv_24_454B04(object[i]._oVar8)) {
4415 NetSendCmd(FALSE, CMD_NAKRUL);
4416 return;
4417 }
4418 } else if (currlevel >= 21) {
4419 quests[Q_NAKRUL]._qactive = 2;
4420 quests[Q_NAKRUL]._qlog = 1;
4421 quests[Q_NAKRUL]._qmsg = object[i]._oVar2;
4422 }
4423 InitQTextMsg(object[i]._oVar2);
4424 NetSendCmdParam1(FALSE, CMD_OPERATEOBJ, i);
4425 }
4426 }
4427
OperateLazStand(int pnum,int i)4428 void OperateLazStand(int pnum, int i)
4429 {
4430 int xx, yy;
4431
4432 if (numitems >= MAXITEMS) {
4433 return;
4434 }
4435
4436 if (object[i]._oSelFlag != 0 && !deltaload && !qtextflag && pnum == myplr) {
4437 object[i]._oAnimFrame++;
4438 object[i]._oSelFlag = 0;
4439 GetSuperItemLoc(object[i]._ox, object[i]._oy, &xx, &yy);
4440 SpawnQuestItem(IDI_LAZSTAFF, xx, yy, 0, 0);
4441 }
4442 }
4443
OperateObject(int pnum,int i,BOOL TeleFlag)4444 void OperateObject(int pnum, int i, BOOL TeleFlag)
4445 {
4446 BOOL sendmsg;
4447
4448 sendmsg = (pnum == myplr);
4449 switch (object[i]._otype) {
4450 case OBJ_L1LDOOR:
4451 case OBJ_L1RDOOR:
4452 if (TeleFlag) {
4453 if (object[i]._otype == OBJ_L1LDOOR)
4454 OperateL1LDoor(pnum, i, TRUE);
4455 if (object[i]._otype == OBJ_L1RDOOR)
4456 OperateL1RDoor(pnum, i, TRUE);
4457 break;
4458 }
4459 if (pnum == myplr)
4460 OperateL1Door(pnum, i, TRUE);
4461 break;
4462 case OBJ_L2LDOOR:
4463 case OBJ_L2RDOOR:
4464 if (TeleFlag) {
4465 if (object[i]._otype == OBJ_L2LDOOR)
4466 OperateL2LDoor(pnum, i, TRUE);
4467 if (object[i]._otype == OBJ_L2RDOOR)
4468 OperateL2RDoor(pnum, i, TRUE);
4469 break;
4470 }
4471 if (pnum == myplr)
4472 OperateL2Door(pnum, i, TRUE);
4473 break;
4474 case OBJ_L3LDOOR:
4475 case OBJ_L3RDOOR:
4476 if (TeleFlag) {
4477 if (object[i]._otype == OBJ_L3LDOOR)
4478 OperateL3LDoor(pnum, i, TRUE);
4479 if (object[i]._otype == OBJ_L3RDOOR)
4480 OperateL3RDoor(pnum, i, TRUE);
4481 break;
4482 }
4483 if (pnum == myplr)
4484 OperateL3Door(pnum, i, TRUE);
4485 break;
4486 case OBJ_LEVER:
4487 case OBJ_SWITCHSKL:
4488 OperateLever(pnum, i);
4489 break;
4490 case OBJ_BOOK2L:
4491 OperateBook(pnum, i);
4492 break;
4493 case OBJ_BOOK2R:
4494 OperateSChambBk(pnum, i);
4495 break;
4496 case OBJ_CHEST1:
4497 case OBJ_CHEST2:
4498 case OBJ_CHEST3:
4499 case OBJ_TCHEST1:
4500 case OBJ_TCHEST2:
4501 case OBJ_TCHEST3:
4502 OperateChest(pnum, i, sendmsg);
4503 break;
4504 case OBJ_SARC:
4505 OperateSarc(pnum, i, sendmsg);
4506 break;
4507 case OBJ_FLAMELVR:
4508 OperateTrapLvr(i);
4509 break;
4510 case OBJ_BLINDBOOK:
4511 case OBJ_BLOODBOOK:
4512 case OBJ_STEELTOME:
4513 OperateBookLever(pnum, i);
4514 break;
4515 case OBJ_SHRINEL:
4516 case OBJ_SHRINER:
4517 OperateShrine(pnum, i, IS_MAGIC);
4518 break;
4519 case OBJ_SKELBOOK:
4520 case OBJ_BOOKSTAND:
4521 OperateSkelBook(pnum, i, sendmsg);
4522 break;
4523 case OBJ_BOOKCASEL:
4524 case OBJ_BOOKCASER:
4525 OperateBookCase(pnum, i, sendmsg);
4526 break;
4527 case OBJ_DECAP:
4528 OperateDecap(pnum, i, sendmsg);
4529 break;
4530 case OBJ_ARMORSTAND:
4531 case OBJ_WARARMOR:
4532 OperateArmorStand(pnum, i, sendmsg);
4533 break;
4534 case OBJ_GOATSHRINE:
4535 OperateGoatShrine(pnum, i, LS_GSHRINE);
4536 break;
4537 case OBJ_CAULDRON:
4538 OperateCauldron(pnum, i, LS_CALDRON);
4539 break;
4540 case OBJ_BLOODFTN:
4541 case OBJ_PURIFYINGFTN:
4542 case OBJ_MURKYFTN:
4543 case OBJ_TEARFTN:
4544 OperateFountains(pnum, i);
4545 break;
4546 case OBJ_STORYBOOK:
4547 OperateStoryBook(pnum, i);
4548 break;
4549 case OBJ_PEDISTAL:
4550 OperatePedistal(pnum, i);
4551 break;
4552 case OBJ_WARWEAP:
4553 case OBJ_WEAPONRACK:
4554 OperateWeaponRack(pnum, i, sendmsg);
4555 break;
4556 case OBJ_MUSHPATCH:
4557 OperateMushPatch(pnum, i);
4558 break;
4559 case OBJ_LAZSTAND:
4560 OperateLazStand(pnum, i);
4561 break;
4562 case OBJ_SLAINHERO:
4563 OperateSlainHero(pnum, i, sendmsg);
4564 break;
4565 case OBJ_SIGNCHEST:
4566 OperateInnSignChest(pnum, i);
4567 break;
4568 }
4569 }
4570
SyncOpL1Door(int pnum,int cmd,int i)4571 void SyncOpL1Door(int pnum, int cmd, int i)
4572 {
4573 bool do_sync;
4574
4575 if (pnum == myplr)
4576 return;
4577
4578 do_sync = FALSE;
4579 if (cmd == CMD_OPENDOOR && object[i]._oVar4 == 0) {
4580 do_sync = TRUE;
4581 }
4582 if (cmd == CMD_CLOSEDOOR && object[i]._oVar4 == 1)
4583 do_sync = TRUE;
4584 if (do_sync) {
4585 if (object[i]._otype == OBJ_L1LDOOR)
4586 OperateL1LDoor(-1, i, FALSE);
4587 if (object[i]._otype == OBJ_L1RDOOR)
4588 OperateL1RDoor(-1, i, FALSE);
4589 }
4590 }
4591
SyncOpL2Door(int pnum,int cmd,int i)4592 void SyncOpL2Door(int pnum, int cmd, int i)
4593 {
4594 bool do_sync;
4595
4596 if (pnum == myplr)
4597 return;
4598
4599 do_sync = FALSE;
4600 if (cmd == CMD_OPENDOOR && object[i]._oVar4 == 0) {
4601 do_sync = TRUE;
4602 }
4603 if (cmd == CMD_CLOSEDOOR && object[i]._oVar4 == 1)
4604 do_sync = TRUE;
4605 if (do_sync) {
4606 if (object[i]._otype == OBJ_L2LDOOR)
4607 OperateL2LDoor(-1, i, FALSE);
4608 if (object[i]._otype == OBJ_L2RDOOR)
4609 OperateL2RDoor(-1, i, FALSE);
4610 }
4611 }
4612
SyncOpL3Door(int pnum,int cmd,int i)4613 void SyncOpL3Door(int pnum, int cmd, int i)
4614 {
4615 bool do_sync;
4616
4617 if (pnum == myplr)
4618 return;
4619
4620 do_sync = FALSE;
4621 if (cmd == CMD_OPENDOOR && object[i]._oVar4 == 0) {
4622 do_sync = TRUE;
4623 }
4624 if (cmd == CMD_CLOSEDOOR && object[i]._oVar4 == 1)
4625 do_sync = TRUE;
4626 if (do_sync) {
4627 if (object[i]._otype == OBJ_L3LDOOR)
4628 OperateL3LDoor(-1, i, FALSE);
4629 if (object[i]._otype == OBJ_L3RDOOR)
4630 OperateL3RDoor(-1, i, FALSE);
4631 }
4632 }
4633
SyncOpObject(int pnum,int cmd,int i)4634 void SyncOpObject(int pnum, int cmd, int i)
4635 {
4636 switch (object[i]._otype) {
4637 case OBJ_L1LDOOR:
4638 case OBJ_L1RDOOR:
4639 SyncOpL1Door(pnum, cmd, i);
4640 break;
4641 case OBJ_L2LDOOR:
4642 case OBJ_L2RDOOR:
4643 SyncOpL2Door(pnum, cmd, i);
4644 break;
4645 case OBJ_L3LDOOR:
4646 case OBJ_L3RDOOR:
4647 SyncOpL3Door(pnum, cmd, i);
4648 break;
4649 case OBJ_LEVER:
4650 case OBJ_SWITCHSKL:
4651 OperateLever(pnum, i);
4652 break;
4653 case OBJ_CHEST1:
4654 case OBJ_CHEST2:
4655 case OBJ_CHEST3:
4656 case OBJ_TCHEST1:
4657 case OBJ_TCHEST2:
4658 case OBJ_TCHEST3:
4659 OperateChest(pnum, i, FALSE);
4660 break;
4661 case OBJ_SARC:
4662 OperateSarc(pnum, i, FALSE);
4663 break;
4664 case OBJ_BLINDBOOK:
4665 case OBJ_BLOODBOOK:
4666 case OBJ_STEELTOME:
4667 OperateBookLever(pnum, i);
4668 break;
4669 case OBJ_SHRINEL:
4670 case OBJ_SHRINER:
4671 OperateShrine(pnum, i, IS_MAGIC);
4672 break;
4673 case OBJ_SKELBOOK:
4674 case OBJ_BOOKSTAND:
4675 OperateSkelBook(pnum, i, FALSE);
4676 break;
4677 case OBJ_BOOKCASEL:
4678 case OBJ_BOOKCASER:
4679 OperateBookCase(pnum, i, FALSE);
4680 break;
4681 case OBJ_DECAP:
4682 OperateDecap(pnum, i, FALSE);
4683 break;
4684 case OBJ_ARMORSTAND:
4685 case OBJ_WARARMOR:
4686 OperateArmorStand(pnum, i, FALSE);
4687 break;
4688 case OBJ_GOATSHRINE:
4689 OperateGoatShrine(pnum, i, LS_GSHRINE);
4690 break;
4691 case OBJ_CAULDRON:
4692 OperateCauldron(pnum, i, LS_CALDRON);
4693 break;
4694 case OBJ_MURKYFTN:
4695 case OBJ_TEARFTN:
4696 OperateFountains(pnum, i);
4697 break;
4698 case OBJ_STORYBOOK:
4699 OperateStoryBook(pnum, i);
4700 break;
4701 case OBJ_PEDISTAL:
4702 OperatePedistal(pnum, i);
4703 break;
4704 case OBJ_WARWEAP:
4705 case OBJ_WEAPONRACK:
4706 OperateWeaponRack(pnum, i, FALSE);
4707 break;
4708 case OBJ_MUSHPATCH:
4709 OperateMushPatch(pnum, i);
4710 break;
4711 case OBJ_SLAINHERO:
4712 OperateSlainHero(pnum, i, FALSE);
4713 break;
4714 case OBJ_SIGNCHEST:
4715 OperateInnSignChest(pnum, i);
4716 break;
4717 }
4718 }
4719
BreakCrux(int i)4720 void BreakCrux(int i)
4721 {
4722 int j, oi;
4723 bool triggered;
4724
4725 object[i]._oAnimFlag = 1;
4726 object[i]._oAnimFrame = 1;
4727 object[i]._oAnimDelay = 1;
4728 object[i]._oSolidFlag = TRUE;
4729 object[i]._oMissFlag = TRUE;
4730 object[i]._oBreak = -1;
4731 object[i]._oSelFlag = 0;
4732 triggered = TRUE;
4733 for (j = 0; j < nobjects; j++) {
4734 oi = objectactive[j];
4735 if (object[oi]._otype != OBJ_CRUX1 && object[oi]._otype != OBJ_CRUX2 && object[oi]._otype != OBJ_CRUX3)
4736 continue;
4737 if (object[i]._oVar8 != object[oi]._oVar8 || object[oi]._oBreak == -1)
4738 continue;
4739 triggered = FALSE;
4740 }
4741 if (!triggered)
4742 return;
4743 if (!deltaload)
4744 PlaySfxLoc(IS_LEVER, object[i]._ox, object[i]._oy);
4745 ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
4746 }
4747
BreakBarrel(int pnum,int i,int dam,BOOL forcebreak,BOOL sendmsg)4748 void BreakBarrel(int pnum, int i, int dam, BOOL forcebreak, BOOL sendmsg)
4749 {
4750 int oi;
4751 int xp, yp;
4752
4753 if (object[i]._oSelFlag == 0)
4754 return;
4755 if (forcebreak) {
4756 object[i]._oVar1 = 0;
4757 } else {
4758 object[i]._oVar1 -= dam;
4759 if (pnum != myplr && object[i]._oVar1 <= 0)
4760 object[i]._oVar1 = 1;
4761 }
4762 if (object[i]._oVar1 > 0) {
4763 if (deltaload)
4764 return;
4765
4766 PlaySfxLoc(IS_IBOW, object[i]._ox, object[i]._oy);
4767 return;
4768 }
4769
4770 object[i]._oVar1 = 0;
4771 object[i]._oAnimFlag = 1;
4772 object[i]._oAnimFrame = 1;
4773 object[i]._oAnimDelay = 1;
4774 object[i]._oSolidFlag = FALSE;
4775 object[i]._oMissFlag = TRUE;
4776 object[i]._oBreak = -1;
4777 object[i]._oSelFlag = 0;
4778 object[i]._oPreFlag = TRUE;
4779 if (deltaload) {
4780 object[i]._oAnimFrame = object[i]._oAnimLen;
4781 object[i]._oAnimCnt = 0;
4782 object[i]._oAnimDelay = 1000;
4783 return;
4784 }
4785
4786 if (object[i]._otype == OBJ_BARRELEX) {
4787 if (currlevel >= 21 && currlevel <= 24)
4788 PlaySfxLoc(IS_POPPOP3, object[i]._ox, object[i]._oy);
4789 else if (currlevel >= 17 && currlevel <= 20)
4790 PlaySfxLoc(IS_POPPOP8, object[i]._ox, object[i]._oy);
4791 else
4792 PlaySfxLoc(IS_BARLFIRE, object[i]._ox, object[i]._oy);
4793 for (yp = object[i]._oy - 1; yp <= object[i]._oy + 1; yp++) {
4794 for (xp = object[i]._ox - 1; xp <= object[i]._ox + 1; xp++) {
4795 if (dMonster[xp][yp] > 0)
4796 MonsterTrapHit(dMonster[xp][yp] - 1, 1, 4, 0, MIS_FIREBOLT, FALSE);
4797 BOOLEAN unused;
4798 if (dPlayer[xp][yp] > 0)
4799 PlayerMHit(dPlayer[xp][yp] - 1, -1, 0, 8, 16, MIS_FIREBOLT, FALSE, 0, &unused);
4800 if (dObject[xp][yp] > 0) {
4801 oi = dObject[xp][yp] - 1;
4802 if (object[oi]._otype == OBJ_BARRELEX && object[oi]._oBreak != -1)
4803 BreakBarrel(pnum, oi, dam, TRUE, sendmsg);
4804 }
4805 }
4806 }
4807 } else {
4808 if (currlevel >= 21 && currlevel <= 24)
4809 PlaySfxLoc(IS_POPPOP2, object[i]._ox, object[i]._oy);
4810 else if (currlevel >= 17 && currlevel <= 20)
4811 PlaySfxLoc(IS_POPPOP5, object[i]._ox, object[i]._oy);
4812 else
4813 PlaySfxLoc(IS_BARREL, object[i]._ox, object[i]._oy);
4814 SetRndSeed(object[i]._oRndSeed);
4815 if (object[i]._oVar2 <= 1) {
4816 if (object[i]._oVar3 == 0)
4817 CreateRndUseful(pnum, object[i]._ox, object[i]._oy, sendmsg);
4818 else
4819 CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE);
4820 }
4821 if (object[i]._oVar2 >= 8)
4822 SpawnSkeleton(object[i]._oVar4, object[i]._ox, object[i]._oy);
4823 }
4824 if (pnum == myplr)
4825 NetSendCmdParam2(FALSE, CMD_BREAKOBJ, pnum, i);
4826 }
4827
BreakObject(int pnum,int oi)4828 void BreakObject(int pnum, int oi)
4829 {
4830 int objdam, mind, maxd;
4831
4832 if (pnum != -1) {
4833 mind = plr[pnum]._pIMinDam;
4834 maxd = plr[pnum]._pIMaxDam;
4835 objdam = random_(163, maxd - mind + 1) + mind;
4836 objdam += plr[pnum]._pDamageMod + plr[pnum]._pIBonusDamMod + objdam * plr[pnum]._pIBonusDam / 100;
4837 } else {
4838 objdam = 10;
4839 }
4840 switch (object[oi]._otype) {
4841 case OBJ_CRUX1:
4842 case OBJ_CRUX2:
4843 case OBJ_CRUX3:
4844 BreakCrux(oi);
4845 break;
4846 case OBJ_BARREL:
4847 case OBJ_BARRELEX:
4848 BreakBarrel(pnum, oi, objdam, FALSE, TRUE);
4849 break;
4850 }
4851 }
4852
SyncBreakObj(int pnum,int oi)4853 void SyncBreakObj(int pnum, int oi)
4854 {
4855 if (object[oi]._otype >= OBJ_BARREL && object[oi]._otype <= OBJ_BARRELEX)
4856 BreakBarrel(pnum, oi, 0, TRUE, FALSE);
4857 }
4858
SyncL1Doors(int i)4859 void SyncL1Doors(int i)
4860 {
4861 int x, y;
4862
4863 if (object[i]._oVar4 == 0) {
4864 object[i]._oMissFlag = FALSE;
4865 return;
4866 }
4867
4868 object[i]._oMissFlag = TRUE;
4869
4870 x = object[i]._ox;
4871 y = object[i]._oy;
4872 object[i]._oSelFlag = 2;
4873 if (currlevel < 17) {
4874 if (object[i]._otype == OBJ_L1LDOOR) {
4875 if (object[i]._oVar1 == 214)
4876 ObjSetMicro(x, y, 408);
4877 else
4878 ObjSetMicro(x, y, 393);
4879 dSpecial[x][y] = 7;
4880 objects_set_door_piece(x - 1, y);
4881 y--;
4882 } else {
4883 ObjSetMicro(x, y, 395);
4884 dSpecial[x][y] = 8;
4885 objects_set_door_piece(x, y - 1);
4886 x--;
4887 }
4888 } else {
4889 if (object[i]._otype == OBJ_L1LDOOR) {
4890 ObjSetMicro(x, y, 206);
4891 dSpecial[x][y] = 1;
4892 objects_set_door_piece(x - 1, y);
4893 y--;
4894 } else {
4895 ObjSetMicro(x, y, 209);
4896 dSpecial[x][y] = 2;
4897 objects_set_door_piece(x, y - 1);
4898 x--;
4899 }
4900 }
4901 DoorSet(i, x, y);
4902 }
4903
SyncCrux(int i)4904 void SyncCrux(int i)
4905 {
4906 bool found;
4907 int j, oi, type;
4908
4909 found = TRUE;
4910 for (j = 0; j < nobjects; j++) {
4911 oi = objectactive[j];
4912 type = object[oi]._otype;
4913 if (type != OBJ_CRUX1 && type != OBJ_CRUX2 && type != OBJ_CRUX3)
4914 continue;
4915 if (object[i]._oVar8 != object[oi]._oVar8 || object[oi]._oBreak == -1)
4916 continue;
4917 found = FALSE;
4918 }
4919 if (found)
4920 ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
4921 }
4922
SyncLever(int i)4923 void SyncLever(int i)
4924 {
4925 if (object[i]._oSelFlag == 0)
4926 ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
4927 }
4928
SyncQSTLever(int i)4929 void SyncQSTLever(int i)
4930 {
4931 int tren;
4932
4933 if (object[i]._oAnimFrame == object[i]._oVar6) {
4934 ObjChangeMapResync(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
4935 if (object[i]._otype == OBJ_BLINDBOOK) {
4936 tren = TransVal;
4937 TransVal = 9;
4938 DRLG_MRectTrans(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
4939 TransVal = tren;
4940 }
4941 }
4942 }
4943
SyncPedistal(int i)4944 void SyncPedistal(int i)
4945 {
4946 BYTE *setp;
4947
4948 if (object[i]._oVar6 == 1)
4949 ObjChangeMapResync(setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7);
4950 if (object[i]._oVar6 == 2) {
4951 ObjChangeMapResync(setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7);
4952 ObjChangeMapResync(setpc_x + 6, setpc_y + 3, setpc_x + setpc_w, setpc_y + 7);
4953 }
4954 if (object[i]._oVar6 == 3) {
4955 ObjChangeMapResync(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
4956 setp = LoadFileInMem("Levels\\L2Data\\Blood2.DUN", NULL);
4957 LoadMapObjs(setp, 2 * setpc_x, 2 * setpc_y);
4958 mem_free_dbg(setp);
4959 }
4960 }
4961
SyncL2Doors(int i)4962 void SyncL2Doors(int i)
4963 {
4964 int x, y;
4965
4966 if (object[i]._oVar4 == 0)
4967 object[i]._oMissFlag = FALSE;
4968 else
4969 object[i]._oMissFlag = TRUE;
4970 x = object[i]._ox;
4971 y = object[i]._oy;
4972 object[i]._oSelFlag = 2;
4973 if (object[i]._otype == OBJ_L2LDOOR && object[i]._oVar4 == 0) {
4974 ObjSetMicro(x, y, 538);
4975 dSpecial[x][y] = 0;
4976 } else if (object[i]._otype == OBJ_L2LDOOR && (object[i]._oVar4 == 1 || object[i]._oVar4 == 2)) {
4977 ObjSetMicro(x, y, 13);
4978 dSpecial[x][y] = 5;
4979 } else if (object[i]._otype == OBJ_L2RDOOR && object[i]._oVar4 == 0) {
4980 ObjSetMicro(x, y, 540);
4981 dSpecial[x][y] = 0;
4982 } else if (object[i]._otype == OBJ_L2RDOOR && (object[i]._oVar4 == 1 || object[i]._oVar4 == 2)) {
4983 ObjSetMicro(x, y, 17);
4984 dSpecial[x][y] = 6;
4985 }
4986 }
4987
SyncL3Doors(int i)4988 void SyncL3Doors(int i)
4989 {
4990 int x, y;
4991
4992 object[i]._oMissFlag = TRUE;
4993 x = object[i]._ox;
4994 y = object[i]._oy;
4995 object[i]._oSelFlag = 2;
4996 if (object[i]._otype == OBJ_L3LDOOR && object[i]._oVar4 == 0) {
4997 ObjSetMicro(x, y, 531);
4998 } else if (object[i]._otype == OBJ_L3LDOOR && (object[i]._oVar4 == 1 || object[i]._oVar4 == 2)) {
4999 ObjSetMicro(x, y, 538);
5000 } else if (object[i]._otype == OBJ_L3RDOOR && object[i]._oVar4 == 0) {
5001 ObjSetMicro(x, y, 534);
5002 } else if (object[i]._otype == OBJ_L3RDOOR && (object[i]._oVar4 == 1 || object[i]._oVar4 == 2)) {
5003 ObjSetMicro(x, y, 541);
5004 }
5005 }
5006
SyncObjectAnim(int o)5007 void SyncObjectAnim(int o)
5008 {
5009 int i, index;
5010
5011 index = AllObjects[object[o]._otype].ofindex;
5012 i = 0;
5013 while (ObjFileList[i] != index) {
5014 i++;
5015 }
5016
5017 object[o]._oAnimData = pObjCels[i];
5018 switch (object[o]._otype) {
5019 case OBJ_L1LDOOR:
5020 case OBJ_L1RDOOR:
5021 SyncL1Doors(o);
5022 break;
5023 case OBJ_L2LDOOR:
5024 case OBJ_L2RDOOR:
5025 SyncL2Doors(o);
5026 break;
5027 case OBJ_L3LDOOR:
5028 case OBJ_L3RDOOR:
5029 SyncL3Doors(o);
5030 break;
5031 case OBJ_CRUX1:
5032 case OBJ_CRUX2:
5033 case OBJ_CRUX3:
5034 SyncCrux(o);
5035 break;
5036 case OBJ_LEVER:
5037 case OBJ_BOOK2L:
5038 case OBJ_SWITCHSKL:
5039 SyncLever(o);
5040 break;
5041 case OBJ_BOOK2R:
5042 case OBJ_BLINDBOOK:
5043 case OBJ_STEELTOME:
5044 SyncQSTLever(o);
5045 break;
5046 case OBJ_PEDISTAL:
5047 SyncPedistal(o);
5048 break;
5049 }
5050 }
5051
GetObjectStr(int i)5052 void GetObjectStr(int i)
5053 {
5054 switch (object[i]._otype) {
5055 case OBJ_CRUX1:
5056 case OBJ_CRUX2:
5057 case OBJ_CRUX3:
5058 strcpy(infostr, "Crucified Skeleton");
5059 break;
5060 case OBJ_LEVER:
5061 case OBJ_FLAMELVR:
5062 strcpy(infostr, "Lever");
5063 break;
5064 case OBJ_L1LDOOR:
5065 case OBJ_L1RDOOR:
5066 case OBJ_L2LDOOR:
5067 case OBJ_L2RDOOR:
5068 case OBJ_L3LDOOR:
5069 case OBJ_L3RDOOR:
5070 if (object[i]._oVar4 == 1)
5071 strcpy(infostr, "Open Door");
5072 if (object[i]._oVar4 == 0)
5073 strcpy(infostr, "Closed Door");
5074 if (object[i]._oVar4 == 2)
5075 strcpy(infostr, "Blocked Door");
5076 break;
5077 case OBJ_BOOK2L:
5078 if (setlevel) {
5079 if (setlvlnum == SL_BONECHAMB) {
5080 strcpy(infostr, "Ancient Tome");
5081 } else if (setlvlnum == SL_VILEBETRAYER) {
5082 strcpy(infostr, "Book of Vileness");
5083 }
5084 }
5085 break;
5086 case OBJ_SWITCHSKL:
5087 strcpy(infostr, "Skull Lever");
5088 break;
5089 case OBJ_BOOK2R:
5090 strcpy(infostr, "Mythical Book");
5091 break;
5092 case OBJ_CHEST1:
5093 case OBJ_TCHEST1:
5094 strcpy(infostr, "Small Chest");
5095 break;
5096 case OBJ_CHEST2:
5097 case OBJ_TCHEST2:
5098 strcpy(infostr, "Chest");
5099 break;
5100 case OBJ_CHEST3:
5101 case OBJ_TCHEST3:
5102 case OBJ_SIGNCHEST:
5103 strcpy(infostr, "Large Chest");
5104 break;
5105 case OBJ_SARC:
5106 strcpy(infostr, "Sarcophagus");
5107 break;
5108 case OBJ_BOOKSHELF:
5109 strcpy(infostr, "Bookshelf");
5110 break;
5111 case OBJ_BOOKCASEL:
5112 case OBJ_BOOKCASER:
5113 strcpy(infostr, "Bookcase");
5114 break;
5115 case OBJ_BARREL:
5116 case OBJ_BARRELEX:
5117 if (currlevel >= 17 && currlevel <= 20) // for hive levels
5118 strcpy(infostr, "Pod"); //Then a barrel is called a pod
5119 else if (currlevel >= 21 && currlevel <= 24) // for crypt levels
5120 strcpy(infostr, "Urn"); //Then a barrel is called an urn
5121 else
5122 strcpy(infostr, "Barrel");
5123 break;
5124 case OBJ_SHRINEL:
5125 case OBJ_SHRINER:
5126 sprintf(tempstr, "%s Shrine", shrinestrs[object[i]._oVar1]);
5127 strcpy(infostr, tempstr);
5128 break;
5129 case OBJ_SKELBOOK:
5130 strcpy(infostr, "Skeleton Tome");
5131 break;
5132 case OBJ_BOOKSTAND:
5133 strcpy(infostr, "Library Book");
5134 break;
5135 case OBJ_BLOODFTN:
5136 strcpy(infostr, "Blood Fountain");
5137 break;
5138 case OBJ_DECAP:
5139 strcpy(infostr, "Decapitated Body");
5140 break;
5141 case OBJ_BLINDBOOK:
5142 strcpy(infostr, "Book of the Blind");
5143 break;
5144 case OBJ_BLOODBOOK:
5145 strcpy(infostr, "Book of Blood");
5146 break;
5147 case OBJ_PURIFYINGFTN:
5148 strcpy(infostr, "Purifying Spring");
5149 break;
5150 case OBJ_ARMORSTAND:
5151 case OBJ_WARARMOR:
5152 strcpy(infostr, "Armor");
5153 break;
5154 case OBJ_WARWEAP:
5155 strcpy(infostr, "Weapon Rack");
5156 break;
5157 case OBJ_GOATSHRINE:
5158 strcpy(infostr, "Goat Shrine");
5159 break;
5160 case OBJ_CAULDRON:
5161 strcpy(infostr, "Cauldron");
5162 break;
5163 case OBJ_MURKYFTN:
5164 strcpy(infostr, "Murky Pool");
5165 break;
5166 case OBJ_TEARFTN:
5167 strcpy(infostr, "Fountain of Tears");
5168 break;
5169 case OBJ_STEELTOME:
5170 strcpy(infostr, "Steel Tome");
5171 break;
5172 case OBJ_PEDISTAL:
5173 strcpy(infostr, "Pedestal of Blood");
5174 break;
5175 case OBJ_STORYBOOK:
5176 strcpy(infostr, StoryBookName[object[i]._oVar3]);
5177 break;
5178 case OBJ_WEAPONRACK:
5179 strcpy(infostr, "Weapon Rack");
5180 break;
5181 case OBJ_MUSHPATCH:
5182 strcpy(infostr, "Mushroom Patch");
5183 break;
5184 case OBJ_LAZSTAND:
5185 strcpy(infostr, "Vile Stand");
5186 break;
5187 case OBJ_SLAINHERO:
5188 strcpy(infostr, "Slain Hero");
5189 break;
5190 }
5191 if (plr[myplr]._pClass == PC_ROGUE) {
5192 if (object[i]._oTrapFlag) {
5193 sprintf(tempstr, "Trapped %s", infostr);
5194 strcpy(infostr, tempstr);
5195 infoclr = COL_RED;
5196 }
5197 }
5198 }
5199
operate_lv24_lever()5200 void operate_lv24_lever()
5201 {
5202 if (currlevel == 24) {
5203 PlaySfxLoc(IS_CROPEN, UberRow, UberCol);
5204 //the part below is the same as objects_454BA8
5205 dPiece[UberRow][UberCol] = 298;
5206 dPiece[UberRow][UberCol - 1] = 301;
5207 dPiece[UberRow][UberCol - 2] = 300;
5208 dPiece[UberRow][UberCol + 1] = 299;
5209 SetDungeonMicros();
5210 }
5211 }
5212
objects_454BA8()5213 void objects_454BA8()
5214 {
5215 dPiece[UberRow][UberCol] = 298;
5216 dPiece[UberRow][UberCol - 1] = 301;
5217 dPiece[UberRow][UberCol - 2] = 300;
5218 dPiece[UberRow][UberCol + 1] = 299;
5219
5220 SetDungeonMicros();
5221 }
5222
objects_rnd_454BEA()5223 void objects_rnd_454BEA()
5224 {
5225 int xp, yp;
5226
5227 while (1) {
5228 xp = random_(141, 80) + 16;
5229 yp = random_(141, 80) + 16;
5230 if (RndLocOk(xp - 1, yp - 1)
5231 && RndLocOk(xp, yp - 1)
5232 && RndLocOk(xp + 1, yp - 1)
5233 && RndLocOk(xp - 1, yp)
5234 && RndLocOk(xp, yp)
5235 && RndLocOk(xp + 1, yp)
5236 && RndLocOk(xp - 1, yp + 1)
5237 && RndLocOk(xp, yp + 1)
5238 && RndLocOk(xp + 1, yp + 1)) {
5239 break;
5240 }
5241 }
5242 UberLeverRow = UberRow + 3;
5243 UberLeverCol = UberCol - 1;
5244 AddObject(OBJ_LEVER, UberRow + 3, UberCol - 1);
5245 }
5246
objects_lv_24_454B04(int s)5247 bool objects_lv_24_454B04(int s)
5248 {
5249 switch (s) {
5250 case 6:
5251 dword_6DE0E0 = 1;
5252 break;
5253 case 7:
5254 if (dword_6DE0E0 == 1) {
5255 dword_6DE0E0 = 2;
5256 } else {
5257 dword_6DE0E0 = 0;
5258 }
5259 break;
5260 case 8:
5261 if (dword_6DE0E0 == 2)
5262 return TRUE;
5263 dword_6DE0E0 = 0;
5264 break;
5265 }
5266 return FALSE;
5267 }
5268
5269 DEVILUTION_END_NAMESPACE
5270