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