Files
Justin Marshall 101266ab72 Initial commit.
2026-04-27 10:35:40 -07:00

5866 lines
165 KiB
C++

/*-----------------------------------------------------------------------**
** Diablo
**
** Objects file
**
** (C)1995 Condor, Inc. All rights reserved.
**
**-----------------------------------------------------------------------**
** $Header: /Diablo/OBJECTS.CPP 5 2/12/97 10:51a Dbrevik2 $
**-----------------------------------------------------------------------**
**
** File Routines
**-----------------------------------------------------------------------*/
#include <time.h>
#include "diablo.h"
#pragma hdrstop
#include "sound.h"
#include "objects.h"
#include "objdat.h"
#include "engine.h"
#include "gendung.h"
#include "lighting.h"
#include "items.h"
#include "player.h"
#include "monster.h"
#include "monstint.h"
#include "control.h"
#include "cursor.h"
#include "spells.h"
#include "minitext.h"
#include "textdat.h"
#include "quests.h"
#include "drlg_l1.h"
#include "missiles.h"
#include "misdat.h"
#include "effects.h"
#include "themes.h"
#include "itemdat.h"
#include "stores.h"
#include "monstdat.h"
#include "error.h"
#include "msg.h"
#include "multi.h"
#include "automap.h"
#include "drlg_l4.h"
#include "towners.h"
#include "inv.h"
#include "setmaps.h"
/*-----------------------------------------------------------------------*
** Externs
**-----------------------------------------------------------------------*/
int ObjIndex(int x, int y);
static bool OperateFountains(int, int);
/*-----------------------------------------------------------------------*
** Local Defines
**-----------------------------------------------------------------------*/
//#define NO_L5_DOORS // JKE just until I get doors.
#define DOOR_CLOSED 0
#define DOOR_OPEN 1
#define DOOR_BLOCKED 2
#define TRAP_NODIR 0
#define TRAP_HORIZ 1
#define TRAP_VERT 2
#define TOTAL_FOUNTAINS 4
/*-----------------------------------------------------------------------*
** Global Variables
**-----------------------------------------------------------------------*/
ObjectStruct object[MAXOBJECTS];
long numobjects;
static char ObjFileList[MAXLVLOBJS];
static int numobjfiles = 0;
static BYTE *pObjCels[MAXLVLOBJS];
int objectactive[MAXOBJECTS];
int objectavail[MAXOBJECTS];
static int trapid;
static int trapdir;
static int leverid;
BOOL InitObjFlag; //True while initing, false otherwise
static int const bxadd[] = { -1, 0, 1, -1, 1, -1, 0, 1 };
static int const byadd[] = { -1, -1, -1, 0, 0, 1, 1, 1 };
int SpellProgress;
#if CHEATS
extern BOOL itemcheat;
extern BOOL uniqcheat;
#endif
/*-----------------------------------------------------------------------*
** Function Prototypes
**-----------------------------------------------------------------------*/
void AddMushPatch();
void AddSlainHero();
void AddSkulkenObject(int, int, int, int);
static void AddNa_Krul_Stuff();
void OpenNaKrul();
static void AddNaKrulLeverObj();
static bool HCheckSpell(int);
/*-----------------------------------------------------------------------*/
// Shrine Data
// Shrine names
static char const * const shrinestrs[] = {
"Mysterious", // 0
"Hidden", // 1
"Gloomy", // 2
"Weird", // 3
"Magical", // 4
"Stone", // 5
"Religious", // 6
"Enchanted", // 7
"Thaumaturgic", // 8
"Fascinating", // 9
"Cryptic", // 10
"Magical", // 11
"Eldritch", // 12
"Eerie", // 13
"Divine", // 14
"Holy", // 15
"Sacred", // 16
"Spiritual", // 17
"Spooky", // 18
"Abandoned", // 19
"Creepy", // 20
"Quiet", // 21
"Secluded", // 22
"Ornate", // 23
"Glimmering", // 24
"Tainted", // 25
"Oily", // 26
"Glowing", // 27
"Mendicant's", // 28
"Sparkling", // 29
"Town", // 30
"Shimmering", // 31
"Solar", // 33
"Murphy's", // 34
};
#define NUMSHRINETYPES (sizeof(shrinestrs)/sizeof(char *))
// Shrine min level it can appear
static char const shrineminlvl[NUMSHRINETYPES] = {
1, // 0 Mysterious
1, // 1 Hidden
1, // 2 Gloomy
1, // 3 Weird
1, // 4 Magical
1, // 5 Stone
1, // 6 Religious
1, // 7 Enchanted
1, // 8 Thaumaturgic
1, // 9 Fascinating
1, // 10 Cryptic
1, // 11 Supernatural
1, // 12 Eldritch
1, // 13 Eerie
1, // 14 Divine
1, // 15 Holy
1, // 16 Sacred
1, // 17 Spiritual
1, // 18 Spooky
1, // 19 Abandoned
1, // 20 Creepy
1, // 21 Quiet
1, // 22 Secluded
1, // 23 Ornate
1, // 24 Glimmering
1, // 25 Tainted
1, // 26 Oily
1, // 27 Glowing
1, // 28 Mendicants
1, // 29 Edisons
1, // 30 Town
1, // 31 Energy
1, // 32 Solar
1, // 33 Murphy's
};
// Shrine max level it can appear
static char const shrinemaxlvl[NUMSHRINETYPES] = {
MAX_LEVELS, // 0 Mysterious
MAX_LEVELS, // 1 Hidden
MAX_LEVELS, // 2 Gloomy
MAX_LEVELS, // 3 Weird
MAX_LEVELS, // 4 Magical
MAX_LEVELS, // 5 Stone
MAX_LEVELS, // 6 Religious
8, // 7 Enchanted
MAX_LEVELS, // 8 Thaumaturgic
MAX_LEVELS, // 9 Fascinating
MAX_LEVELS, // 10 Cryptic
MAX_LEVELS, // 11 Supernatural
MAX_LEVELS, // 12 Eldritch
MAX_LEVELS, // 13 Eerie
MAX_LEVELS, // 14 Divine
MAX_LEVELS, // 15 Holy
MAX_LEVELS, // 16 Sacred
MAX_LEVELS, // 17 Spiritual
MAX_LEVELS, // 18 Spooky
MAX_LEVELS, // 19 Abandoned
MAX_LEVELS, // 20 Creepy
MAX_LEVELS, // 21 Quiet
MAX_LEVELS, // 22 Secluded
MAX_LEVELS, // 23 Ornate
MAX_LEVELS, // 24 Glimmering
MAX_LEVELS, // 25 Tainted
MAX_LEVELS, // 26 Oily
MAX_LEVELS, // 27 Glowing
MAX_LEVELS, // 28 Mendicants
MAX_LEVELS, // 29 Edisons
MAX_LEVELS, // 30 Town
MAX_LEVELS, // 31 Energy
MAX_LEVELS, // 32 Solar
MAX_LEVELS, // 33 Murphy's
};
#define SHRINE_ALL 0
#define SHRINE_SINGLE 1
#define SHRINE_MULTI 2
// Shrine available for either, single, or multiplayer?
static char const shrineavail[NUMSHRINETYPES] = {
SHRINE_ALL, // 0 Mysterious
SHRINE_ALL, // 1 Hidden
SHRINE_SINGLE, // 2 Gloomy
SHRINE_SINGLE, // 3 Weird
SHRINE_ALL, // 4 Magical
SHRINE_ALL, // 5 Stone
SHRINE_ALL, // 6 Religious
SHRINE_ALL, // 7 Enchanted
SHRINE_SINGLE, // 8 Thaumaturgic
SHRINE_ALL, // 9 Fascinating
SHRINE_ALL, // 10 Cryptic
SHRINE_ALL, // 11 Supernatural
SHRINE_ALL, // 12 Eldritch
SHRINE_ALL, // 13 Eerie
SHRINE_ALL, // 14 Divine
SHRINE_ALL, // 15 Holy
SHRINE_ALL, // 16 Sacred
SHRINE_ALL, // 17 Spiritual
SHRINE_MULTI, // 18 Spooky
SHRINE_ALL, // 19 Abandoned
SHRINE_ALL, // 20 Creepy
SHRINE_ALL, // 21 Quiet
SHRINE_ALL, // 22 Secluded
SHRINE_ALL, // 23 Ornate
SHRINE_ALL, // 24 Glimmering
SHRINE_MULTI, // 25 Tainted
SHRINE_ALL, // 26 Oily
SHRINE_ALL, // 27 Glowing
SHRINE_ALL, // 28 Mendicants
SHRINE_ALL, // 29 Edisons
SHRINE_ALL, // 30 Town
SHRINE_ALL, // 31 Energy
SHRINE_SINGLE, // 32 Solar
SHRINE_ALL, // 33 Murphy's
};
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static char const * const StoryBookName[] = {
// The Librium of the Horadrim (White Books)
"The Great Conflict",
"The Wages of Sin are War",
"The Tale of the Horadrim",
// Grimoire of the Burning Hells (Red Books)
"The Dark Exile",
"The Sin War",
"The Binding of the Three",
// The Journals of Lazarus the Betrayer (Normal Book Color)
"The Realms Beyond",
"Tale of the Three",
"The Black King",
// The Journals of Skulken the Necromancer JKE
"Journal: The Ensorcellment",
"Journal: The Meeting",
"Journal: The Tirade",
"Journal: His Power Grows",
"Journal: NA-KRUL",
"Journal: The End",
"A Spellbook"
};
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void InitObjectGFX() {
BYTE fileload[MAXOBJFILES];
int i,j,t;
int templevel; //JKE
ZeroMemory(fileload,sizeof(fileload));
// temp hack to get object art to appear. JKE
templevel = currlevel;
if ((currlevel >= CRYPTSTART) && (currlevel <= CRYPTEND))
templevel = templevel - CRYPTSTART + 1; // replace templevel with currlevel when done.
else if ((currlevel >= HIVESTART) && (currlevel <= HIVEEND))
templevel = templevel - HIVESTART + 9;
for (i = 0; AllObjects[i].oload != -1; ++i) {
if ((AllObjects[i].oload == OBJMUST)
&& (templevel >= AllObjects[i].ominlvl)
&& (templevel <= AllObjects[i].omaxlvl))
fileload[AllObjects[i].ofindex] = TRUE;
if (AllObjects[i].otheme != -1) {
for (t = 0; t < numthemes; ++t) {
if (theme[t].ttype == AllObjects[i].otheme)
fileload[AllObjects[i].ofindex] = TRUE;
}
}
if (AllObjects[i].oquest != -1) {
j = AllObjects[i].oquest;
if (QuestStatus(j))
fileload[AllObjects[i].ofindex] = TRUE;
}
}
app_assert(numobjfiles == 0);
for (i = 0; i < MAXOBJFILES; ++i) {
if (fileload[i]) {
char filestr[32];
ObjFileList[numobjfiles] = i;
sprintf(filestr, "Objects\\%s.CEL", ObjMasterFList[i]);
if ((currlevel >= HIVESTART) && (currlevel < CRYPTSTART)) //JKE OBJECTS
sprintf(filestr, "Objects\\%s.CEL", HObjMasterFList[i]);
else if (currlevel >= CRYPTSTART)
sprintf(filestr, "Objects\\%s.CEL", CObjMasterFList[i]);
app_assert(! pObjCels[numobjfiles]);
pObjCels[numobjfiles] = LoadFileInMemSig(filestr,NULL,'OGFX');
++numobjfiles;
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void FreeObjectGFX() {
for (int i = 0; i < numobjfiles; ++i) {
DiabloFreePtr(pObjCels[i]);
}
numobjfiles = 0;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static bool RndLocOk(int xp, int yp) {
if (dMonster[xp][yp] != 0) return FALSE;
if (dPlayer[xp][yp] != 0) return FALSE;
if (dObject[xp][yp] != 0) return FALSE;
if (dFlags[xp][yp] & BFLAG_SETPC) return FALSE;
if (nSolidTable[dPiece[xp][yp]]) return FALSE;
if (leveltype == 1) {
if ((dPiece[xp][yp] > 126) && (dPiece[xp][yp] < 144))
return false;
}
return true;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static bool TrapLocOk(int xp, int yp) {
if (dFlags[xp][yp] & BFLAG_SETPC) return false;
if (nSolidTable[dPiece[xp][yp]]) return false;
return true;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static bool RoomLocOk(int xp, int yp) {
if (dPlayer[xp][yp] != 0) return false;
if (dObject[xp][yp] != 0) return false;
if (dFlags[xp][yp] & BFLAG_SETPC) return false;
if (nSolidTable[dPiece[xp][yp]]) return false;
return true;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void InitRndLocObj(int min, int max, int objtype) {
int xp, yp;
int numobjs = random(139,max - min) + min;
for (int i = 0; i < numobjs; ++i) {
while (1) {
xp = random(139,DMAXX - DIRTEDGE) + (DIRTEDGED2);
yp = random(139,DMAXY - DIRTEDGE) + (DIRTEDGED2);
if (! RndLocOk(xp-1, yp-1)) continue;
if (! RndLocOk(xp+0, yp-1)) continue;
if (! RndLocOk(xp+1, yp-1)) continue;
if (! RndLocOk(xp-1, yp+0)) continue;
if (! RndLocOk(xp+0, yp+0)) continue;
if (! RndLocOk(xp+1, yp+0)) continue;
if (! RndLocOk(xp-1, yp+1)) continue;
if (! RndLocOk(xp+0, yp+1)) continue;
if (! RndLocOk(xp+1, yp+1)) continue;
break;
}
AddObject(objtype, xp, yp);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void InitRndLocBigObj(int min, int max, int objtype) {
int xp, yp;
int numobjs = random(140,max - min) + min;
for (int i = 0; i < numobjs; ++i) {
while (1) {
xp = random(140,DMAXX - DIRTEDGE) + (DIRTEDGED2);
yp = random(140,DMAXY - DIRTEDGE) + (DIRTEDGED2);
if (! RndLocOk(xp-1, yp-2)) continue;
if (! RndLocOk(xp+0, yp-2)) continue;
if (! RndLocOk(xp+1, yp-2)) continue;
if (! RndLocOk(xp-1, yp-1)) continue;
if (! RndLocOk(xp+0, yp-1)) continue;
if (! RndLocOk(xp+1, yp-1)) continue;
if (! RndLocOk(xp-1, yp+0)) continue;
if (! RndLocOk(xp+0, yp+0)) continue;
if (! RndLocOk(xp+1, yp+0)) continue;
if (! RndLocOk(xp-1, yp+1)) continue;
if (! RndLocOk(xp+0, yp+1)) continue;
if (! RndLocOk(xp+1, yp+1)) continue;
break;
}
AddObject(objtype, xp, yp);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void InitRndLocObj5x5(int min, int max, int objtype) {
int xp, yp, xx, yy, cnt;
bool done;
int numobjs = random(139,max - min) + min;
for (int i = 0; i < numobjs; ++i) {
cnt = 0;
done = false;
while (! done) {
done = true;
xp = random(139,DMAXX - DIRTEDGE) + (DIRTEDGED2);
yp = random(139,DMAXY - DIRTEDGE) + (DIRTEDGED2);
for (yy = -2; yy <= 2; ++yy) {
for (xx = -2; xx <= 2; ++xx) if (! RndLocOk(xp+xx,yp+yy)) done = FALSE;
}
if (!done) {
++cnt;
if (cnt > 20000) return;
}
}
AddObject(objtype, xp, yp);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void ClrAllObjects ()
{
int i;
#if 0
for (i = 0; i < MAXOBJECTS; ++i) {
object[i]._ox = 0;
object[i]._oy = 0;
object[i]._oAnimData = NULL;
object[i]._oAnimDelay = 0;
object[i]._oAnimCnt = 0;
object[i]._oAnimLen = 0;
object[i]._oAnimFrame = 0;
object[i]._oDelFlag = FALSE;
object[i]._oVar1 = 0;
object[i]._oVar2 = 0;
object[i]._oVar3 = 0;
object[i]._oVar4 = 0;
}
#else
memset(object, 0, sizeof(object));
#endif
numobjects = 0;
for (i = 0; i < MAXOBJECTS; ++i) {
objectavail[i] = i;
//objectactive[i] = 0;
}
memset(objectactive, 0, sizeof(objectactive));
trapid = 1;
trapdir = TRAP_NODIR;
leverid = 1;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddTortures()
{
int yp, xp;
for (yp = 0; yp < DMAXY; ++yp) {
for (xp = 0; xp < DMAXX; ++xp) {
if (dPiece[xp][yp] == 367) {
AddObject(OBJ_TORTURE1, xp, yp+1);
AddObject(OBJ_TORTURE3, xp+2, yp-1);
AddObject(OBJ_TORTURE2, xp, yp+3);
AddObject(OBJ_TORTURE4, xp+4, yp-1);
AddObject(OBJ_TORTURE5, xp, yp+5);
AddObject(OBJ_TNUDEM1, xp+1, yp+3);
AddObject(OBJ_TNUDEM2, xp+4, yp+5);
AddObject(OBJ_TNUDEM3, xp+2, yp);
AddObject(OBJ_TNUDEM4, xp+3, yp+2);
AddObject(OBJ_TNUDEW1, xp+2, yp+4);
AddObject(OBJ_TNUDEW2, xp+2, yp+1);
AddObject(OBJ_TNUDEW3, xp+4, yp+2);
}
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddCandles()
{
int const xp = quests[Q_PWATER]._qtx;
int const yp = quests[Q_PWATER]._qty;
AddObject(OBJ_STORYCANDLE, xp-2, yp+1);
AddObject(OBJ_STORYCANDLE, xp+3, yp+1);
AddObject(OBJ_STORYCANDLE, xp-1, yp+2);
AddObject(OBJ_STORYCANDLE, xp+2, yp+2);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddTrapLine(int min, int max, int tobjtype, int lobjtype)
{
int i, j, xp, yp, numobjs;
int sx, sy, xa, ya, t;
int lx1, ly1, lx2, ly2;
bool found;
numobjs = random(0,max - min) + min;
for (i = 0; i < numobjs; ++i) {
found = false;
while (!found) {
found = true;
xp = random(0,DMAXX - DIRTEDGE) + (DIRTEDGED2);
yp = random(0,DMAXY - DIRTEDGE) + (DIRTEDGED2);
if (random(0,2)) {
while (TrapLocOk(xp, yp-1)) --yp; // Go to bottom
sx = xp;
sy = yp;
xa = 0;
ya = 1;
t = 0;
while (TrapLocOk(xp, yp+1) && found) {
found = found && RndLocOk(xp-3, yp);
found = found && RndLocOk(xp-2, yp);
found = found && RndLocOk(xp-1, yp);
found = found && RndLocOk(xp, yp);
found = found && RndLocOk(xp+1, yp);
found = found && RndLocOk(xp+2, yp);
found = found && RndLocOk(xp+3, yp);
++yp;
++t;
}
lx1 = xp-2;
ly1 = random(0,t-1) + sy + 1;
lx2 = xp+2;
ly2 = random(0,t-1) + sy + 1;
trapdir = TRAP_VERT;
} else {
while (TrapLocOk(xp-1, yp)) --xp; // Go to left
sx = xp;
sy = yp;
xa = 1;
ya = 0;
t = 0;
while (TrapLocOk(xp+1, yp) && found) {
found = found && RndLocOk(xp, yp-3);
found = found && RndLocOk(xp, yp-2);
found = found && RndLocOk(xp, yp-1);
found = found && RndLocOk(xp, yp);
found = found && RndLocOk(xp, yp+1);
found = found && RndLocOk(xp, yp+2);
found = found && RndLocOk(xp, yp+3);
++xp;
++t;
}
lx1 = random(0,t-1) + sx + 1;
ly1 = yp-2;
lx2 = random(0,t-1) + sx + 1;
ly2 = yp+2;
trapdir = TRAP_HORIZ;
}
if ((t < 5) || (t > 12)) found = FALSE;
}
// Place trap
xp = sx;
yp = sy;
for (j = 0; j <= t; ++j) {
AddObject(tobjtype, xp, yp);
xp += xa;
yp += ya;
}
// Place levers
AddObject(lobjtype, lx1, ly1);
AddObject(lobjtype, lx2, ly2);
++trapid; // Next trap
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddLeverObj(int lx1, int ly1, int lx2, int ly2, int x1, int y1, int x2, int y2)
{
int xp, yp;
while (1) {
xp = random(141,lx2 - lx1 + 1) + lx1;
yp = random(141,ly2 - ly1 + 1) + ly1;
if (! RndLocOk(xp-1, yp-1)) continue;
if (! RndLocOk(xp+0, yp-1)) continue;
if (! RndLocOk(xp+1, yp-1)) continue;
if (! RndLocOk(xp-1, yp+0)) continue;
if (! RndLocOk(xp+0, yp+0)) continue;
if (! RndLocOk(xp+1, yp+0)) continue;
if (! RndLocOk(xp-1, yp+1)) continue;
if (! RndLocOk(xp+0, yp+1)) continue;
if (! RndLocOk(xp+1, yp+1)) continue;
break;
}
AddObject(OBJ_LEVER, xp, yp);
int i = dObject[xp][yp] - 1;
SetObjMapRange(i, x1, y1, x2, y2, leverid);
++leverid;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddBookLever(int lx1, int ly1, int lx2, int ly2, int x1, int y1, int x2, int y2, int msg)
{
/* int xp, yp;
while (1) {
xp = random(142,lx2 - lx1 + 1) + lx1;
yp = random(142,ly2 - ly1 + 1) + ly1;
if (! RndLocOk(xp-1, yp-1)) continue;
if (! RndLocOk(xp+0, yp-1)) continue;
if (! RndLocOk(xp+1, yp-1)) continue;
if (! RndLocOk(xp-1, yp+0)) continue;
if (! RndLocOk(xp+0, yp+0)) continue;
if (! RndLocOk(xp+1, yp+0)) continue;
if (! RndLocOk(xp-1, yp+1)) continue;
if (! RndLocOk(xp+0, yp+1)) continue;
if (! RndLocOk(xp+1, yp+1)) continue;
break;
}
*/
int xp, yp, xx, yy, cnt;
bool done;
cnt = 0;
done = false;
while (! done) {
done = true;
xp = random(139,DMAXX - DIRTEDGE) + (DIRTEDGED2);
yp = random(139,DMAXY - DIRTEDGE) + (DIRTEDGED2);
for (yy = -2; yy <= 2; ++yy) {
for (xx = -2; xx <= 2; ++xx) if (! RndLocOk(xp+xx,yp+yy)) done = FALSE;
}
if (!done) {
++cnt;
if (cnt > 20000) return;
}
}
if (QuestStatus(Q_BLIND)) AddObject(OBJ_BLINDBOOK, xp, yp);
if (QuestStatus(Q_WARLORD)) AddObject(OBJ_STEELTOME, xp, yp);
if (QuestStatus(Q_BLOOD)) {
xp = (setpc_x << 1) + DIRTEDGED2 + 9;
yp = (setpc_y << 1) + DIRTEDGED2 + 24;
AddObject(OBJ_BLOODBOOK, xp, yp);
}
app_assert((DWORD)xp < MAXDUNX);
app_assert((DWORD)yp < MAXDUNY);
int i = dObject[xp][yp] - 1;
app_assert((DWORD)i < MAXOBJECTS);
SetObjMapRange(i, x1, y1, x2, y2, leverid);
SetBookMsg(i, msg);
++leverid;
object[i]._oVar6 = object[i]._oAnimFrame + 1;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void InitRndBarrels()
{
int xp, yp, o, rv, c, t;
int numobjs = random(143,5) + 3;
for (int i = 0; i < numobjs; ++i) {
while (1) {
xp = random(143,DMAXX - DIRTEDGE) + (DIRTEDGED2);
yp = random(143,DMAXY - DIRTEDGE) + (DIRTEDGED2);
if (! RndLocOk(xp, yp)) continue;
break;
}
// Add normal or exploding barrel
if (random(143,4)) o = OBJ_BARREL;
else o = OBJ_BARRELEX;
AddObject(o, xp, yp);
c = 1;
bool found = true;
while ((random(143,c >> 1) == 0) && (found)) {
t = 0;
found = false;
while ((!found) && (t < 3)) {
rv = random(143,8);
xp += bxadd[rv];
yp += byadd[rv];
found = RndLocOk(xp, yp);
++t;
}
if (found) {
if (random(143,5)) o = OBJ_BARREL;
else o = OBJ_BARRELEX;
AddObject(o, xp, yp);
++c;
}
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void AddL1Objs(int x1, int y1, int x2, int y2)
{
int i,j,pn;
for (j = y1; j < y2; ++j) {
for (i = x1; i < x2; ++i) {
// Add Light
pn = dPiece[i][j];
if (pn == 270) AddObject(OBJ_L1LIGHT, i, j);
if ((pn == 44) || (pn == 51) || (pn == 214))
AddObject(OBJ_L1DOORL, i, j);
if ((pn == 46) || (pn == 56)) AddObject(OBJ_L1DOORR, i, j);
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void AddL5Objs(int x1, int y1, int x2, int y2)
{
int i,j,pn;
for (j = y1; j < y2; ++j) {
for (i = x1; i < x2; ++i) {
// Add Light
pn = dPiece[i][j];
// if (pn == 270) AddObject(OBJ_L1LIGHT, i, j);
if (pn == 77)
AddObject(OBJ_L1DOORL, i, j);
if (pn == 80)
AddObject(OBJ_L1DOORR, i, j);
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void AddL2Objs(int x1, int y1, int x2, int y2)
{
int i,j,pn;
for (j = y1; j < y2; ++j) {
for (i = x1; i < x2; ++i) {
// Add Doors
pn = dPiece[i][j];
if (pn == 13 || pn == 541) AddObject(OBJ_L2DOORL, i, j);
if (pn == 17 || pn == 542) AddObject(OBJ_L2DOORR, i, j);
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddL3Objs(int x1, int y1, int x2, int y2)
{
int i,j,pn;
for (j = y1; j < y2; ++j) {
for (i = x1; i < x2; ++i) {
// Add Doors
pn = dPiece[i][j];
if (pn == 531) AddObject(OBJ_L3DOORL, i, j);
if (pn == 534) AddObject(OBJ_L3DOORR, i, j);
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static bool TorchLocOK(int xp, int yp)
{
if (dFlags[xp][yp] & BFLAG_SETPC) return false;
return true;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddL2Torches()
{
int i,j,pn;
for (j = 0; j < DMAXY; ++j) {
for (i = 0; i < DMAXX; ++i) {
// Add Torches
if(TorchLocOK(i,j)) {
pn = dPiece[i][j];
if ((pn == 1) && (random(145,3) == 0)) AddObject(OBJ_TORCHL2, i, j);
if ((pn == 5) && (random(145,3) == 0)) AddObject(OBJ_TORCHR2, i, j);
if ((pn == 37) && (random(145,10) == 0) && (dObject[i-1][j] == 0)) AddObject(OBJ_TORCHL, i-1, j);
if ((pn == 41) && (random(145,10) == 0) && (dObject[i][j-1] == 0)) AddObject(OBJ_TORCHR, i, j-1);
}
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static bool WallTrapLocOk(int xp, int yp)
{
if (dFlags[xp][yp] & BFLAG_SETPC) return false;
if (!nTrapTable[dPiece[xp][yp]]) return false;
return true;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddObjTraps()
{
int i,j;
int x,y;
int rndv;
char oi, oi2;
if (currlevel == 1) rndv = 10;
if (currlevel >= 2) rndv = 15;
if (currlevel >= 5) rndv = 20;
if (currlevel >= 7) rndv = 25;
for (j = 0; j < DMAXY; ++j) {
for (i = 0; i < DMAXX; ++i) {
if ((dObject[i][j] > 0) && (random(144,100) < rndv)) {
oi = dObject[i][j] - 1;
if (AllObjects[object[oi]._otype].oTrapFlag) {
x = i;
y = j;
if (random(144,2) == 0) {
--x;
while (!nSolidTable[dPiece[x][y]]) --x;
if (WallTrapLocOk(x, y) && ((i - x) > 1)) {
AddObject(OBJ_TRAPL, x, y);
oi2 = dObject[x][y] - 1;
object[oi2]._oVar1 = i;
object[oi2]._oVar2 = j;
object[oi]._oTrapFlag = TRUE;
}
} else {
--y;
while (!nSolidTable[dPiece[x][y]]) --y;
if (WallTrapLocOk(x, y) && ((j - y) > 1)) {
AddObject(OBJ_TRAPR, x, y);
oi2 = dObject[x][y] - 1;
object[oi2]._oVar1 = i;
object[oi2]._oVar2 = j;
object[oi]._oTrapFlag = TRUE;
}
}
}
}
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddChestTraps()
{
int i,j;
char oi;
for (j = 0; j < DMAXY; ++j) {
for (i = 0; i < DMAXX; ++i) {
if (dObject[i][j] > 0) {
oi = dObject[i][j] - 1;
if ((object[oi]._otype >= OBJ_CHEST1) &&
(object[oi]._otype <= OBJ_CHEST3) &&
(!object[oi]._oTrapFlag) &&
(random(0, 100) < 10)) {
object[oi]._otype = (object[oi]._otype - OBJ_CHEST1) + OBJ_TCHEST1;
object[oi]._oTrapFlag = TRUE;
if (leveltype == 2) object[oi]._oVar4 = random(0, 2); // Type of trap
#if defined(HELLFIRE2)
else object[oi]._oVar4 = random(0, 7);
#else
else object[oi]._oVar4 = random(0, 6);
#endif
}
}
}
}
}
/*-----------------------------------------------------------------------*
** Used by diablo level only!!!!!
**-----------------------------------------------------------------------*/
static void LoadMapObjects(BYTE *pMap, int startx, int starty, int x1, int y1, int w, int h, int leveridx)
{
int i,j,rw,rh;
int ox,oy;
BYTE *lm;
long mapoff;
int ot, oi;
InitObjFlag = TRUE;
lm = pMap;
rw = *lm;
lm += 2;
rh = *lm;
// Skip map + height word
mapoff = ((rw * rh) << 1) + 2;
// Convert to index mini tile level instead of mega
rw = rw << 1;
rh = rh << 1;
// Skip treasure and monster map
mapoff += ((rw * rh) << 2);
lm += mapoff;
for (j = 0; j < rh; ++j) {
for (i = 0; i < rw; ++i) {
if (*lm != 0) {
ot = *lm;
ox = i + DIRTEDGED2 + startx;
oy = j + DIRTEDGED2 + starty;
AddObject(ObjTypeConv[ot], ox, oy);
oi = ObjIndex(ox, oy);
SetObjMapRange(oi, x1, y1, x1+w, y1+h, leveridx);
}
lm+=2;
}
}
InitObjFlag = FALSE;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void LoadMapObjs(BYTE *pMap, int startx, int starty)
{
int i,j,rw,rh;
int ox,oy;
BYTE *lm;
long mapoff;
int ot;
InitObjFlag = TRUE;
lm = pMap;
rw = *lm;
lm += 2;
rh = *lm;
// Skip map + height word
mapoff = ((rw * rh) << 1) + 2;
// Convert to index mini tile level instead of mega
rw = rw << 1;
rh = rh << 1;
// Skip treasure and monster map
mapoff += ((rw * rh) << 2);
lm += mapoff;
for (j = 0; j < rh; ++j) {
for (i = 0; i < rw; ++i) {
if (*lm != 0) {
ot = *lm;
ox = i + DIRTEDGED2 + startx;
oy = j + DIRTEDGED2 + starty;
AddObject(ObjTypeConv[ot], ox, oy);
}
lm+=2;
}
}
InitObjFlag = FALSE;
}
/*-----------------------------------------------------------------------*
** Levers for diablo level
**-----------------------------------------------------------------------*/
static void AddDiabObjs()
{
BYTE *pSetPiece;
int xx, yy;
pSetPiece = LoadFileInMemSig("Levels\\L4Data\\diab1.DUN",NULL,'STPC');
xx = (diabquad1x << 1);
yy = (diabquad1y << 1);
LoadMapObjects(pSetPiece, xx, yy, diabquad2x, diabquad2y, 11, 12, 1);
DiabloFreePtr(pSetPiece);
pSetPiece = LoadFileInMemSig("Levels\\L4Data\\diab2a.DUN",NULL,'STPC');
xx = (diabquad2x << 1);
yy = (diabquad2y << 1);
LoadMapObjects(pSetPiece, xx, yy, diabquad3x, diabquad3y, 11, 11, 2);
DiabloFreePtr(pSetPiece);
pSetPiece = LoadFileInMemSig("Levels\\L4Data\\diab3a.DUN",NULL,'STPC');
xx = (diabquad3x << 1);
yy = (diabquad3y << 1);
LoadMapObjects(pSetPiece, xx, yy, diabquad4x, diabquad4y, 9, 9, 3);
DiabloFreePtr(pSetPiece);
}
static void AddSkulkenBooks(int number) // Journal entry books JKE
{
int xp,yp,xx,yy,cnt;
bool done;
cnt = 0;
done = false;
while (! done) {
done = true;
xp = random(139,DMAXX - DIRTEDGE) + (DIRTEDGED2);
yp = random(139,DMAXY - DIRTEDGE) + (DIRTEDGED2);
for (yy = -2; yy <= 2; ++yy) {
for (xx = -3; xx <= 3; ++xx) if (! RndLocOk(xp+xx,yp+yy)) done = FALSE;
}
if (!done) {
++cnt;
if (cnt > 20000) return;
}
}
AddSkulkenObject(OBJ_STORYBOOK, number, xp, yp);
// AddObject(OBJ_STORYBOOK, xp, yp);
AddObject(OBJ_STORYCANDLE, xp-2, yp+1);
AddObject(OBJ_STORYCANDLE, xp-2, yp);
AddObject(OBJ_STORYCANDLE, xp-1, yp-1);
AddObject(OBJ_STORYCANDLE, xp+1, yp-1);
AddObject(OBJ_STORYCANDLE, xp+2, yp);
AddObject(OBJ_STORYCANDLE, xp+2, yp+1);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddStoryBooks()
{
int xp,yp,xx,yy,cnt;
bool done;
cnt = 0;
done = false;
while (! done) {
done = true;
xp = random(139,DMAXX - DIRTEDGE) + (DIRTEDGED2);
yp = random(139,DMAXY - DIRTEDGE) + (DIRTEDGED2);
for (yy = -2; yy <= 2; ++yy) {
for (xx = -3; xx <= 3; ++xx) if (! RndLocOk(xp+xx,yp+yy)) done = FALSE;
}
if (!done) {
++cnt;
if (cnt > 20000) return;
}
}
AddObject(OBJ_STORYBOOK, xp, yp);
AddObject(OBJ_STORYCANDLE, xp-2, yp+1);
AddObject(OBJ_STORYCANDLE, xp-2, yp);
AddObject(OBJ_STORYCANDLE, xp-1, yp-1);
AddObject(OBJ_STORYCANDLE, xp+1, yp-1);
AddObject(OBJ_STORYCANDLE, xp+2, yp);
AddObject(OBJ_STORYCANDLE, xp+2, yp+1);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddHookedBodies(int freq)
{
int i, j, ii, jj;
//Add tortured bodies on hooks
for (j = 0; j < MDMAXY; ++j) {
for (i = 0; i < MDMAXX; ++i) {
if ((dungeon[i][j] == 1 || dungeon[i][j] == 2) &&
((!random(0, freq)) && (SkipThemeRoom(i, j)))) {
ii = (i << 1) + DIRTEDGED2;
jj = (j << 1) + DIRTEDGED2;
if ((dungeon[i][j] == 1) && (dungeon[i+1][j] == 6)) {
switch(random(0, 3)) {
case 0:
AddObject(OBJ_TORTURE1, ii+1, jj);
break;
case 1:
AddObject(OBJ_TORTURE2, ii+1, jj);
break;
case 2:
AddObject(OBJ_TORTURE5, ii+1, jj);
break;
}
} else if ((dungeon[i][j] == 2) && (dungeon[i][j+1] == 6)) {
switch(random(0, 2)) {
case 0:
AddObject(OBJ_TORTURE3, ii, jj);
break;
case 1:
AddObject(OBJ_TORTURE4, ii, jj);
break;
}
}
}
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddL4Goodies()
{
AddHookedBodies(6);
InitRndLocObj(2, 6, OBJ_TNUDEM1);
InitRndLocObj(2, 6, OBJ_TNUDEM2);
InitRndLocObj(2, 6, OBJ_TNUDEM3);
InitRndLocObj(2, 6, OBJ_TNUDEM4);
InitRndLocObj(2, 6, OBJ_TNUDEW1);
InitRndLocObj(2, 6, OBJ_TNUDEW2);
InitRndLocObj(2, 6, OBJ_TNUDEW3);
InitRndLocObj(2, 6, OBJ_DECAP);
InitRndLocObj(1, 3, OBJ_CAULDRON);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddLazStand()
{
int xp,yp,xx,yy,cnt;
bool done = false;
cnt = 0;
while (! done) {
done = true;
xp = random(139,DMAXX - DIRTEDGE) + (DIRTEDGED2);
yp = random(139,DMAXY - DIRTEDGE) + (DIRTEDGED2);
for (yy = -3; yy <= 3; ++yy) {
for (xx = -2; xx <= 3; ++xx) if (! RndLocOk(xp+xx,yp+yy)) done = FALSE;
}
if (!done) {
++cnt;
if (cnt > 10000) {
// If can't find big area put it anywhere
InitRndLocObj(1, 1, OBJ_LAZSTAND);
return;
}
}
}
AddObject(OBJ_LAZSTAND, xp, yp);
AddObject(OBJ_TNUDEM2, xp+0, yp+2);
AddObject(OBJ_STORYCANDLE, xp+1, yp+2);
AddObject(OBJ_TNUDEM3, xp+2, yp+2);
AddObject(OBJ_TNUDEW1, xp+0, yp-2);
AddObject(OBJ_STORYCANDLE, xp+1, yp-2);
AddObject(OBJ_TNUDEW2, xp+2, yp-2);
AddObject(OBJ_STORYCANDLE, xp-1, yp-1);
AddObject(OBJ_TNUDEW3, xp-1, yp+0);
AddObject(OBJ_STORYCANDLE, xp-1, yp+1);
}
/*-----------------------------------------------------------------------*
** Does not get called for setlevels so no worries
**-----------------------------------------------------------------------*/
void InitObjects ()
{
int textdef;
byte *setp;
ClrAllObjects();
SpellProgress = 0;
// No objects on DIABLO_LEVEL. Inited seperatly
if (currlevel == DIABLO_LEVEL) {
AddDiabObjs();
return;
}
InitObjFlag = TRUE;
int rs = GetRndSeed();
if (currlevel == SLAIN_HERO_LEVEL && gbMaxPlayers == 1) {
AddSlainHero();
}
if (currlevel == quests[Q_BKMUSHRM]._qlevel
&& quests[Q_BKMUSHRM]._qactive == QUEST_NOTACTIVE) {
AddMushPatch();
}
if (currlevel == STORY_BOOK1_LEVEL) AddStoryBooks();
else if (currlevel == STORY_BOOK2_LEVEL) AddStoryBooks();
else if (currlevel == STORY_BOOK3_LEVEL) AddStoryBooks();
if (currlevel == SKULKEN_BOOK1_LEVEL)
{
// AddSkulkenBooks(0);
AddSkulkenBooks(1);
// AddStoryBooks();
// AddStoryBooks();
}
else if (currlevel == SKULKEN_BOOK2_LEVEL)
{
AddSkulkenBooks(2);
AddSkulkenBooks(3);
}
else if (currlevel == SKULKEN_BOOK3_LEVEL)
{
AddSkulkenBooks(4);
AddSkulkenBooks(5);
}
if (currlevel == NA_KRUL_LEVEL)
{
AddNa_Krul_Stuff();
}
if (leveltype == 1) {
if (QuestStatus(Q_BUTCHER)) AddTortures();
if (QuestStatus(Q_PWATER)) AddCandles();
if (QuestStatus(Q_LTBANNER)) AddObject(OBJ_SIGNCHEST,(setpc_x << 1) + DIRTEDGED2 + 10, (setpc_y << 1) + DIRTEDGED2 + 3);
InitRndLocBigObj(10, 15, OBJ_SARC);
if (currlevel < CRYPTSTART)
AddL1Objs(0, 0, DMAXX, DMAXY);
else
AddL5Objs(0,0,DMAXX,DMAXY);
InitRndBarrels();
}
if (leveltype == 2) {
if (QuestStatus(Q_ROCK))
InitRndLocObj5x5(1, 1, OBJ_STAND); // Rock stand
if (QuestStatus(Q_SCHAMB))
InitRndLocObj5x5(1, 1, OBJ_BOOK2R); // SCamb book
AddL2Objs(0, 0, DMAXX, DMAXY);
AddL2Torches();
if (QuestStatus(Q_BLIND)) {
if (plr[myplr]._pClass == CLASS_WARRIOR) textdef = TXT_WARBLIND;
else if (plr[myplr]._pClass == CLASS_ROGUE) textdef = TXT_ROGBLIND;
else if (plr[myplr]._pClass == CLASS_SORCEROR) textdef = TXT_SORBLIND;
else if (plr[myplr]._pClass == CLASS_MONK) textdef = TXT_MNKBLIND;
else if (plr[myplr]._pClass == CLASS_BARD) textdef = TXT_BRDBLIND;
else if (plr[myplr]._pClass == CLASS_BARBARIAN) textdef = TXT_BARBLIND;
quests[Q_BLIND]._qmsg = textdef;
AddBookLever(0, 0, DMAXX, DMAXY, setpc_x, setpc_y, setpc_x+setpc_w+1, setpc_y+setpc_h+1, textdef);
setp = LoadFileInMemSig("Levels\\L2Data\\Blind2.DUN",NULL,'STPC');
LoadMapObjs(setp, (setpc_x << 1), (setpc_y << 1));
DiabloFreePtr(setp);
}
if (QuestStatus(Q_BLOOD)) {
if (plr[myplr]._pClass == CLASS_WARRIOR) textdef = TXT_WARBLOOD;
else if (plr[myplr]._pClass == CLASS_ROGUE) textdef = TXT_ROGBLOOD;
else if (plr[myplr]._pClass == CLASS_SORCEROR) textdef = TXT_SORBLOOD;
else if (plr[myplr]._pClass == CLASS_MONK) textdef = TXT_MNKBLOOD;
else if (plr[myplr]._pClass == CLASS_BARD) textdef = TXT_BRDBLOOD;
else if (plr[myplr]._pClass == CLASS_BARBARIAN) textdef = TXT_BARBLOOD;
quests[Q_BLOOD]._qmsg = textdef;
AddBookLever(0, 0, DMAXX, DMAXY, setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7, textdef);
AddObject(OBJ_PEDISTAL, (setpc_x << 1) + DIRTEDGED2 + 9, (setpc_y << 1) +DIRTEDGED2 + 16);
}
InitRndBarrels();
}
if (leveltype == 3) {
AddL3Objs(0, 0, DMAXX, DMAXY);
InitRndBarrels();
}
if (leveltype == 4) {
if (QuestStatus(Q_WARLORD)) {
if (plr[myplr]._pClass == CLASS_WARRIOR) textdef = TXT_WARLORD;
else if (plr[myplr]._pClass == CLASS_ROGUE) textdef = TXT_ROGLORD;
else if (plr[myplr]._pClass == CLASS_SORCEROR) textdef = TXT_SORLORD;
else if (plr[myplr]._pClass == CLASS_MONK) textdef = TXT_MNKLORD;
else if (plr[myplr]._pClass == CLASS_BARD) textdef = TXT_BRDLORD;
else if (plr[myplr]._pClass == CLASS_BARBARIAN) textdef = TXT_BARLORD;
quests[Q_WARLORD]._qmsg = textdef;
AddBookLever(0, 0, DMAXX, DMAXY, setpc_x, setpc_y, setpc_x+setpc_w, setpc_y+setpc_h, textdef);
setp = LoadFileInMemSig("Levels\\L4Data\\Warlord.DUN",NULL,'STPC');
LoadMapObjs(setp, (setpc_x << 1), (setpc_y << 1));
DiabloFreePtr(setp);
}
if (QuestStatus(Q_BETRAYER) && (gbMaxPlayers == 1)) {
AddLazStand();
}
InitRndBarrels();
AddL4Goodies();
}
InitRndLocObj(5, 10, OBJ_CHEST1);
InitRndLocObj(3, 6, OBJ_CHEST2);
InitRndLocObj(1, 5, OBJ_CHEST3);
if (leveltype != 4) AddObjTraps();
if (leveltype > 1) AddChestTraps();
InitObjFlag = FALSE;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void SetMapObjects(BYTE *pMap, int startx, int starty)
{
int i,j,rw,rh;
int ox,oy;
BYTE *lm, *h;
long mapoff;
int ot;
bool fileload[MAXOBJFILES];
char filestr[32];
ClrAllObjects();
InitObjFlag = TRUE;
for (i = 0; i < MAXOBJFILES; ++i) fileload[i] = FALSE;
// Load all must obj gfx for leveltype
for (i = 0; AllObjects[i].oload != -1; ++i) {
if ((AllObjects[i].oload == OBJMUST) && (leveltype == AllObjects[i].olvltype))
fileload[AllObjects[i].ofindex] = true;
}
lm = pMap;
rw = *lm;
lm += 2;
rh = *lm;
// Skip map + height word
mapoff = ((rw * rh) << 1) + 2;
// Convert to index mini tile level instead of mega
rw = rw << 1;
rh = rh << 1;
// Skip treasure and monster map
mapoff += ((rw * rh) << 2);
lm += mapoff;
h = lm;
for (j = 0; j < rh; ++j) {
for (i = 0; i < rw; ++i) {
if (*lm != 0) {
ot = *lm;
ot = ObjTypeConv[ot];
fileload[AllObjects[ot].ofindex] = TRUE;
}
lm+=2;
}
}
app_assert(numobjfiles == 0);
for (i = 0; i < MAXOBJFILES; ++i) {
if (fileload[i]) {
ObjFileList[numobjfiles] = i;
sprintf(filestr, "Objects\\%s.CEL", ObjMasterFList[i]);
app_assert(! pObjCels[numobjfiles]);
pObjCels[numobjfiles] = LoadFileInMemSig(filestr,NULL,'OGFX');
++numobjfiles;
}
}
lm = h;
for (j = 0; j < rh; ++j) {
for (i = 0; i < rw; ++i) {
if (*lm != 0) {
ot = *lm;
ox = i + DIRTEDGED2 + startx;
oy = j + DIRTEDGED2 + starty;
AddObject(ObjTypeConv[ot], ox, oy);
}
lm+=2;
}
}
InitObjFlag = FALSE;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void DeleteObject(int oi, int i)
{
int ox,oy;
app_assert((DWORD)oi < MAXOBJECTS);
ox = object[oi]._ox;
oy = object[oi]._oy;
dObject[ox][oy] = 0;
objectavail[MAXOBJECTS - numobjects] = oi;
--numobjects;
if ((numobjects > 0) && (i != numobjects)) {
objectactive[i] = objectactive[numobjects];
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void SetupObject(int i, int x, int y, int ot)
{
int ai, j;
app_assert((DWORD)i < MAXOBJECTS);
object[i]._otype = ot;
object[i]._ox = x;
object[i]._oy = y;
ai = AllObjects[ot].ofindex;
for (j = 0; ObjFileList[j] != ai; ++j);
object[i]._oAnimData = pObjCels[j];
object[i]._oAnimFlag = AllObjects[ot].oAnimFlag;
if (object[i]._oAnimFlag) {
object[i]._oAnimDelay = AllObjects[ot].oAnimDelay;
object[i]._oAnimCnt = random(146,AllObjects[ot].oAnimDelay);
object[i]._oAnimLen = AllObjects[ot].oAnimLen;
object[i]._oAnimFrame = random(146,AllObjects[ot].oAnimLen-1) + 1;
} else {
object[i]._oAnimDelay = 1000;
object[i]._oAnimCnt = 0;
object[i]._oAnimLen = AllObjects[ot].oAnimLen;
object[i]._oAnimFrame = AllObjects[ot].oAnimDelay;
}
object[i]._oAnimWidth = AllObjects[ot].oAnimWidth;
object[i]._oSolidFlag = AllObjects[ot].oSolidFlag;
object[i]._oMissFlag = AllObjects[ot].oMissFlag;
object[i]._oLight = AllObjects[ot].oLightFlag;
object[i]._oDelFlag = FALSE;
object[i]._oBreak = AllObjects[ot].oBreak;
object[i]._oSelFlag = AllObjects[ot].oSelFlag;
object[i]._oPreFlag = FALSE;
object[i]._oTrapFlag = FALSE;
object[i]._oDoorFlag = FALSE;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void SetObjMapRange(int i, int x1, int y1, int x2, int y2, int v)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oVar1 = x1;
object[i]._oVar2 = y1;
object[i]._oVar3 = x2;
object[i]._oVar4 = y2;
object[i]._oVar8 = v;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void SetBookMsg(int i, int msg)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oVar7 = msg;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddL1Door(int i, int x, int y, int ot)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oDoorFlag = TRUE;
if (ot == OBJ_L1DOORL) {
object[i]._oVar1 = dPiece[x][y];
object[i]._oVar2 = dPiece[x][y-1];
} else {
object[i]._oVar1 = dPiece[x][y];
object[i]._oVar2 = dPiece[x-1][y];
}
object[i]._oVar4 = DOOR_CLOSED;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddSCambBook(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
// if (quests[Q_SCHAMB]._qactive != QUEST_NOTACTIVE) {
// object[i]._oSelFlag = OSEL_NONE;
// object[i]._oAnimFrame = 6;
// }
object[i]._oVar1 = setpc_x;
object[i]._oVar2 = setpc_y;
object[i]._oVar3 = setpc_x+setpc_w+1;
object[i]._oVar4 = setpc_y+setpc_h+1;
object[i]._oVar6 = object[i]._oAnimFrame + 1;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddChest(int i, int t)
{
app_assert((DWORD)i < MAXOBJECTS);
if (random(147,2) == 0) object[i]._oAnimFrame += 3; // Left or right
object[i]._oRndSeed = GetRndSeed();
// Set # chest items. If a setlevel then so to max items.
switch(t) {
case OBJ_CHEST1:
case OBJ_TCHEST1:
if (setlevel) object[i]._oVar1 = 1;
else object[i]._oVar1 = random(147,2);
break;
case OBJ_CHEST2:
case OBJ_TCHEST2:
if (setlevel) object[i]._oVar1 = 2;
else object[i]._oVar1 = random(147,3);
break;
case OBJ_CHEST3:
case OBJ_TCHEST3:
if (setlevel) object[i]._oVar1 = 3;
else object[i]._oVar1 = random(147,4);
break;
}
object[i]._oVar2 = random(147,8);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddL2Door(int i, int x, int y, int ot)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oDoorFlag = TRUE;
if (ot == OBJ_L2DOORL) ObjSetMicro(x, y, 538);
else ObjSetMicro(x, y, 540);
object[i]._oVar4 = DOOR_CLOSED;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddL3Door(int i, int x, int y, int ot)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oDoorFlag = TRUE;
if (ot == OBJ_L3DOORL) ObjSetMicro(x, y, 531);
else ObjSetMicro(x, y, 534);
object[i]._oVar4 = DOOR_CLOSED;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddSarc(int i)
{
int x,y;
app_assert((DWORD)i < MAXOBJECTS);
x = object[i]._ox;
y = object[i]._oy - 1;
dObject[x][y] = -1 - (char)i;
object[i]._oVar1 = random(153,10);
object[i]._oRndSeed = GetRndSeed();
if (object[i]._oVar1 >= 8) object[i]._oVar2 = PreSpawnSkeleton();
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddFlameTrap(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oVar1 = trapid; // Set trap id
object[i]._oVar2 = 0; // Trap active
object[i]._oVar3 = trapdir; // Horizontal, Vertical, or none
object[i]._oVar4 = 0; // Init to off
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddFlameLvr(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oVar1 = trapid; // Set trap id
object[i]._oVar2 = OBJ_FLAMEHOLE; // Trap active
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddTrap(int i, int ot)
{
int mt, tdiff;
// Difficulty
tdiff = (currlevel / 3) + 1;
// Temp hack trap JKE 7/30
if (currlevel > 16) tdiff = ((currlevel-4)/3) + 1;
if (currlevel > 20) tdiff = ((currlevel-8)/3) + 1;
// Missile type
mt = random(148,tdiff);
app_assert((DWORD)i < MAXOBJECTS);
if (mt == 0) object[i]._oVar3 = MIT_ARROW;
if (mt == 1) object[i]._oVar3 = MIT_FIREBOLT;
if (mt == 2) object[i]._oVar3 = MIT_LIGHTCTRL;
object[i]._oVar4 = 0; // Trap active
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddObjLight(int i, int r)
{
app_assert((DWORD)i < MAXOBJECTS);
if (InitObjFlag) {
DoLighting(object[i]._ox, object[i]._oy, r, -1);
object[i]._oVar1 = -1;
} else object[i]._oVar1 = 0;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddBarrel(int i, int ot)
{
app_assert((DWORD)i < MAXOBJECTS);
//object[i]._oVar1 = random(149,5) + 5; // Barrel hit points
object[i]._oVar1 = 0;
object[i]._oRndSeed = GetRndSeed();
object[i]._oVar2 = random(149,10); // What is inside
object[i]._oVar3 = random(149,3); // if item, useful or not
if (object[i]._oVar2 >= 8)
object[i]._oVar4 = PreSpawnSkeleton(); // Get monster index if one will pop out
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddShrine(int i)
{
int st, j;
bool slist[NUMSHRINETYPES];
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oPreFlag = TRUE;
for (j = 0; j < NUMSHRINETYPES; ++j) {
if ((currlevel >= shrineminlvl[j]) && (currlevel <= shrinemaxlvl[j]))
slist[j] = true;
else
slist[j] = false;
if ((gbMaxPlayers != 1) && (shrineavail[j] == SHRINE_SINGLE)) slist[j] = false;
if ((gbMaxPlayers == 1) && (shrineavail[j] == SHRINE_MULTI)) slist[j] = false;
}
// Choose shrine type
do {
st = random(150,NUMSHRINETYPES);
} while (!slist[st]);
object[i]._oVar1 = st;
if (random(150,2)) {
object[i]._oAnimFrame = 12;
object[i]._oAnimLen = 22;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddBookcase(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oRndSeed = GetRndSeed();
object[i]._oPreFlag = TRUE;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddBookstand(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oRndSeed = GetRndSeed();
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddBloodFtn(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oRndSeed = GetRndSeed();
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddPurifyingFountain(int i)
{
int x, y;
app_assert((DWORD)i < MAXOBJECTS);
x = object[i]._ox;
y = object[i]._oy;
dObject[x][y-1] = -1 - (char)i;
dObject[x-1][y] = -1 - (char)i;
dObject[x-1][y-1] = -1 - (char)i;
object[i]._oRndSeed = GetRndSeed();
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddArmorStand(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
if (!armorFlag) {
//A functional armor stand has already been placed
//Only place non-functional empty stands
object[i]._oAnimFlag = 2;
object[i]._oSelFlag = OSEL_NONE;
}
object[i]._oRndSeed = GetRndSeed();
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddGoatShrine(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oRndSeed = GetRndSeed();
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddCauldron(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oRndSeed = GetRndSeed();
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddMurkyFountain(int i)
{
int x, y;
app_assert((DWORD)i < MAXOBJECTS);
x = object[i]._ox;
y = object[i]._oy;
dObject[x][y-1] = -1 - (char)i;
dObject[x-1][y] = -1 - (char)i;
dObject[x-1][y-1] = -1 - (char)i;
object[i]._oRndSeed = GetRndSeed();
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddTearFountain(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oRndSeed = GetRndSeed();
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddDecap(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oRndSeed = GetRndSeed();
object[i]._oAnimFrame = random(151,8) + 1;
object[i]._oPreFlag = TRUE;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
const void AddVilebook(int i)
{
if ((setlevel) && (setlvlnum == SL_VILEBETRAYER)) {
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oAnimFrame = 4;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
const void AddMagicCircle(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oRndSeed = GetRndSeed();
object[i]._oPreFlag = TRUE;
object[i]._oVar6 = OBJNOWARP;
object[i]._oVar5 = OBJWARP1;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
const void AddBrnCross(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oRndSeed = GetRndSeed();
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
const void AddPedistal(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oVar1 = setpc_x;
object[i]._oVar2 = setpc_y;
object[i]._oVar3 = setpc_x + setpc_w;
object[i]._oVar4 = setpc_y + setpc_h;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
int const StoryText[3][3] = {
{ TXT_BOOK11, TXT_BOOK12, TXT_BOOK13 },
{ TXT_BOOK21, TXT_BOOK22, TXT_BOOK23 },
{ TXT_BOOK31, TXT_BOOK32, TXT_BOOK33 } };
static void AddStoryBook(int i)
{
// Use the last level seed to determine book types (which of 3)
SetRndSeed(glSeedTbl[16]);
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oVar1 = random(0, 3);
if (currlevel == STORY_BOOK1_LEVEL) object[i]._oVar2 = StoryText[object[i]._oVar1][0];
else if (currlevel == STORY_BOOK2_LEVEL) object[i]._oVar2 = StoryText[object[i]._oVar1][1];
else if (currlevel == STORY_BOOK3_LEVEL) object[i]._oVar2 = StoryText[object[i]._oVar1][2];
object[i]._oVar3 = (object[i]._oVar1 * 3) + (currlevel >> 2) - 1;
object[i]._oAnimFrame = 5 - (object[i]._oVar1 << 1);
object[i]._oVar4 = object[i]._oAnimFrame + 1;
}
static void addskulkenbook (int i, int number) // number is the text to associate JKE
{
app_assert((DWORD)i < MAXOBJECTS);
if (number > 5)
{
object[i]._oVar8 = number;
switch (object[i]._oVar8)
{
case 6:
// object[i]._oVar2 = TXT_SPELL1;
if (plr[myplr]._pClass == CLASS_WARRIOR) object[i]._oVar2 = TXT_SPELL1;
else if (plr[myplr]._pClass == CLASS_ROGUE) object[i]._oVar2 = TXT_R_SPELL1;
else if (plr[myplr]._pClass == CLASS_SORCEROR) object[i]._oVar2 = TXT_S_SPELL1;
else if (plr[myplr]._pClass == CLASS_MONK) object[i]._oVar2 = TXT_M_SPELL1;
else if (plr[myplr]._pClass == CLASS_BARD) object[i]._oVar2 = TXT_B_SPELL1;
else if (plr[myplr]._pClass == CLASS_BARBARIAN) object[i]._oVar2 = TXT_C_SPELL1;
break;
case 7:
// object[i]._oVar2 = TXT_SPELL2;
if (plr[myplr]._pClass == CLASS_WARRIOR) object[i]._oVar2 = TXT_SPELL2;
else if (plr[myplr]._pClass == CLASS_ROGUE) object[i]._oVar2 = TXT_R_SPELL2;
else if (plr[myplr]._pClass == CLASS_SORCEROR) object[i]._oVar2 = TXT_S_SPELL2;
else if (plr[myplr]._pClass == CLASS_MONK) object[i]._oVar2 = TXT_M_SPELL2;
else if (plr[myplr]._pClass == CLASS_BARD) object[i]._oVar2 = TXT_B_SPELL2;
else if (plr[myplr]._pClass == CLASS_BARBARIAN) object[i]._oVar2 = TXT_C_SPELL2;
break;
case 8:
// object[i]._oVar2 = TXT_SPELL3;
if (plr[myplr]._pClass == CLASS_WARRIOR) object[i]._oVar2 = TXT_SPELL3;
else if (plr[myplr]._pClass == CLASS_ROGUE) object[i]._oVar2 = TXT_R_SPELL3;
else if (plr[myplr]._pClass == CLASS_SORCEROR) object[i]._oVar2 = TXT_S_SPELL3;
else if (plr[myplr]._pClass == CLASS_MONK) object[i]._oVar2 = TXT_M_SPELL3;
else if (plr[myplr]._pClass == CLASS_BARD) object[i]._oVar2 = TXT_B_SPELL3;
else if (plr[myplr]._pClass == CLASS_BARBARIAN) object[i]._oVar2 = TXT_C_SPELL3;
break;
}
object[i]._oVar1 = 1;
object[i]._oVar3 = 15;
object[i]._oAnimFrame = 5 - ((object[i]._oVar1) << 1);
object[i]._oVar4 = object[i]._oAnimFrame + 1;
}
else
{
object[i]._oVar1 = 1;
object[i]._oVar2 = TXT_SKULLJRNL1 + number;
object[i]._oVar3 = 9 + number;
object[i]._oAnimFrame = 5 - (object[i]._oVar1 << 1);
object[i]._oVar4 = object[i]._oAnimFrame + 1;
object[i]._oVar8 = 0;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddWeaponRack(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
if (!weaponFlag) {
//A functional weapon rack has already been placed
//Only place non-functional empty racks
object[i]._oAnimFlag = 2;
object[i]._oSelFlag = OSEL_NONE;
}
object[i]._oRndSeed = GetRndSeed();
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddTorturedBody(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oRndSeed = GetRndSeed();
object[i]._oAnimFrame = random(0, 4) + 1;
object[i]._oPreFlag = TRUE;
}
/*-----------------------------------------------------------------------*
* GetRndObjLoc
*
* Gets a x by y empty location for object placement
**-----------------------------------------------------------------------*/
static void GetRndObjLoc(int randarea, int &xx, int &yy)
{
int i,j;
bool failed;
if (randarea) {
int tries = 0;
do {
if (++tries > 1000 && randarea > 1)
--randarea;
xx = random(0, DMAXX);
yy = random(0, DMAXY);
failed = false;
for (i = 0; i < randarea && !failed; ++i)
for (j = 0; j < randarea && !failed; ++j)
failed = !RndLocOk(xx + i, yy + j);
} while (failed);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddMushPatch()
{
int x,y;
if (numobjects < MAXOBJECTS) {
int i = objectavail[0];
GetRndObjLoc(5, x, y);
dObject[x+1][y+1] = -1 - (char)i;
dObject[x+2][y+1] = -1 - (char)i;
dObject[x+1][y+2] = -1 - (char)i;
AddObject(OBJ_MUSHPATCH, x+2, y+2);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void AddSlainHero()
{
int x, y;
GetRndObjLoc(5, x, y);
AddObject(OBJ_SLAINHERO, x+2, y+2);
}
void AddSkulkenObject(int ot, int number, int ox, int oy)
{
int oi; // Standard setup JKE
if (numobjects < MAXOBJECTS) {
oi = objectavail[0];
objectavail[0] = objectavail[MAXOBJECTS - numobjects - 1];
objectactive[numobjects] = oi;
dObject[ox][oy] = (char)oi + 1;
// Standard init
SetupObject(oi, ox, oy, ot);
addskulkenbook(oi, number);
app_assert((DWORD)oi < MAXOBJECTS);
object[oi]._oAnimWidth2 = (object[oi]._oAnimWidth - 64) >> 1;
++numobjects;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void AddObject(int ot, int ox, int oy)
{
int oi;
if (numobjects < MAXOBJECTS) {
oi = objectavail[0];
objectavail[0] = objectavail[MAXOBJECTS - numobjects - 1];
objectactive[numobjects] = oi;
dObject[ox][oy] = (char)oi + 1;
// Standard init
SetupObject(oi, ox, oy, ot);
// Bonus inits
switch (ot) {
case OBJ_L1LIGHT :
//AddObjLight(oi, 10);
AddObjLight(oi, 5);
break;
case OBJ_CANDLE1 :
case OBJ_CANDLE2 :
case OBJ_SKFIRE :
case OBJ_BOOKCANDLE:
AddObjLight(oi, 5);
break;
case OBJ_STORYCANDLE:
AddObjLight(oi, 3);
break;
case OBJ_TORCHL:
case OBJ_TORCHR:
case OBJ_TORCHL2:
case OBJ_TORCHR2:
AddObjLight(oi, 8);
break;
case OBJ_L1DOORL :
case OBJ_L1DOORR :
AddL1Door(oi, ox, oy, ot);
break;
case OBJ_L2DOORL :
case OBJ_L2DOORR :
AddL2Door(oi, ox, oy, ot);
break;
case OBJ_L3DOORL :
case OBJ_L3DOORR :
AddL3Door(oi, ox, oy, ot);
break;
case OBJ_BOOK2R:
AddSCambBook(oi);
break;
case OBJ_CHEST1:
case OBJ_CHEST2:
case OBJ_CHEST3:
case OBJ_TCHEST1:
case OBJ_TCHEST2:
case OBJ_TCHEST3:
AddChest(oi, ot);
break;
case OBJ_SARC:
AddSarc(oi);
break;
case OBJ_FLAMEHOLE:
AddFlameTrap(oi);
break;
case OBJ_FLAMELVR:
AddFlameLvr(oi);
break;
case OBJ_WATER:
app_assert((DWORD)oi < MAXOBJECTS);
object[oi]._oAnimFrame = 1;
break;
case OBJ_TRAPL:
case OBJ_TRAPR:
AddTrap(oi, ot);
break;
case OBJ_BARREL:
case OBJ_BARRELEX:
AddBarrel(oi, ot);
break;
case OBJ_SHRINEL:
case OBJ_SHRINER:
AddShrine(oi);
break;
case OBJ_BOOKCASEL:
case OBJ_BOOKCASER:
AddBookcase(oi);
break;
case OBJ_SKELBOOK:
case OBJ_BOOKSTAND:
AddBookstand(oi);
break;
case OBJ_BLOODFTN:
AddBloodFtn(oi);
break;
case OBJ_DECAP:
AddDecap(oi);
break;
case OBJ_PURIFYINGFTN:
AddPurifyingFountain(oi);
break;
case OBJ_ARMORSTAND:
case OBJ_WARARMOR:
AddArmorStand(oi);
break;
case OBJ_GOATSHRINE:
AddGoatShrine(oi);
break;
case OBJ_CAULDRON:
AddCauldron(oi);
break;
case OBJ_MURKYFTN:
AddMurkyFountain(oi);
break;
case OBJ_TEARFTN:
AddTearFountain(oi);
break;
case OBJ_BOOK2L:
AddVilebook(oi);
break;
case OBJ_MCIRCLE1:
case OBJ_MCIRCLE2:
AddMagicCircle(oi);
break;
case OBJ_STORYBOOK:
AddStoryBook(oi);
break;
case OBJ_TBCROSS:
case OBJ_BCROSS:
AddBrnCross(oi);
AddObjLight(oi, 5);
break;
case OBJ_PEDISTAL:
AddPedistal(oi);
break;
case OBJ_WARWEAP:
case OBJ_WEAPONRACK:
AddWeaponRack(oi);
break;
case OBJ_TNUDEM2:
AddTorturedBody(oi);
break;
}
app_assert((DWORD)oi < MAXOBJECTS);
object[oi]._oAnimWidth2 = (object[oi]._oAnimWidth - 64) >> 1;
++numobjects;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void Obj_Light(int i, int lr)
{
int ox, oy;
int dx, dy, p, tr;
bool turnon = false;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oVar1 == -1) return;
ox = object[i]._ox;
oy = object[i]._oy;
tr = lr + PLRLRAD;
if (lightflag == 0) {
for (p = 0; (p < MAX_PLRS) && (!turnon); ++p) {
if (!plr[p].plractive) continue;
if (currlevel != plr[p].plrlevel) continue;
dx = abs(plr[p]._px - ox);
dy = abs(plr[p]._py - oy);
if ((dx < tr) && (dy < tr)) turnon = true;
}
}
if (turnon) {
if (object[i]._oVar1 == 0) object[i]._olid = AddLight (ox, oy, lr);
object[i]._oVar1 = 1;
} else {
if (object[i]._oVar1 == 1) AddUnLight(object[i]._olid);
object[i]._oVar1 = 0;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void Obj_Circle(int i)
{
int px, py, ox, oy;
int v1, v2, v3;
app_assert((DWORD)i < MAXOBJECTS);
ox = object[i]._ox;
oy = object[i]._oy;
px = plr[myplr]._px;
py = plr[myplr]._py;
if ((px == ox) && (py == oy)) {
if (object[i]._otype == OBJ_MCIRCLE1) object[i]._oAnimFrame = 2;
if (object[i]._otype == OBJ_MCIRCLE2) object[i]._oAnimFrame = 4;
if ((ox == 45) && (oy == 47)) object[i]._oVar6 = OBJWARP2;
else if ((ox == 26) && (oy == 46)) object[i]._oVar6 = OBJWARP1;
else object[i]._oVar6 = OBJNOWARP;
if ((ox == 35) && (oy == 36) && object[i]._oVar5 == OBJWARP3) {
object[i]._oVar6 = OBJDONEWARP;
v1 = 35;
v2 = 46;
ObjChangeMapResync(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
if (quests[Q_BETRAYER]._qactive == QUEST_NOTDONE)
quests[Q_BETRAYER]._qvar1 = 4;
v3 = dPiece[v1][v2];
//Cast phase
AddMissile(plr[myplr]._px, plr[myplr]._py, v1, v2, plr[myplr]._pdir, MIT_PHASE, MI_ENEMYMONST, myplr, 0, 0);
void TrackInit(BOOL bMouseDown);
TrackInit(FALSE);
// drb.patch1.start.1/24/97
// static BYTE sgbMouseDown;
extern BYTE sgbMouseDown;
// drb.patch1.end.1/24/97
sgbMouseDown = FALSE;
ReleaseCapture();
ClrPlrPath(myplr);
void StartStand(int, int);
StartStand(myplr, 0);
}
}
else {
if (object[i]._otype == OBJ_MCIRCLE1) object[i]._oAnimFrame = 1;
if (object[i]._otype == OBJ_MCIRCLE2) object[i]._oAnimFrame = 3;
object[i]._oVar6 = OBJNOWARP;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void Obj_StopAnim(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oAnimFrame == object[i]._oAnimLen) {
object[i]._oAnimCnt = 0;
object[i]._oAnimDelay = 1000;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void Obj_Door(int i)
{
int dx, dy;
bool dok;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oVar4 == DOOR_CLOSED) {
object[i]._oSelFlag = OSEL_ALL;
object[i]._oMissFlag = FALSE;
} else {
dx = object[i]._ox;
dy = object[i]._oy;
dok = (dMonster[dx][dy] == 0);
dok = dok && (dItem[dx][dy] == 0);
dok = dok && (dDead[dx][dy] == 0);
dok = dok && (dPlayer[dx][dy] == 0);
object[i]._oSelFlag = OSEL_TOP;
if (dok) object[i]._oVar4 = DOOR_OPEN;
else object[i]._oVar4 = DOOR_BLOCKED;
object[i]._oMissFlag = TRUE;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void Obj_Sarc(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oAnimFrame == object[i]._oAnimLen) object[i]._oAnimFlag = FALSE;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void ActivateTrapLine(int ttype, int tid)
{
int i, oi;
for (i = 0; i < numobjects; ++i) {
oi = objectactive[i];
if ((object[oi]._otype == ttype) && (object[oi]._oVar1 == tid)) {
object[oi]._oVar4 = 1;
object[oi]._oAnimFlag = TRUE;
object[oi]._oAnimDelay = 1;
object[oi]._olid = AddLight (object[oi]._ox, object[oi]._oy, 1);
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void Obj_FlameTrap(int i)
{
int xp,yp;
int j;
// Is trap active?
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oVar2 != 0) {
// Not active, try dying down
if (object[i]._oVar4 != 0) {
--object[i]._oAnimFrame;
if (object[i]._oAnimFrame == 1) {
object[i]._oVar4 = 0;
AddUnLight(object[i]._olid);
} else {
if (object[i]._oAnimFrame <= 4) ChangeLightRadius(object[i]._olid, object[i]._oAnimFrame);
}
}
} else {
// Active so continue
// Not on?
if (object[i]._oVar4 == 0) {
if (object[i]._oVar3 == TRAP_VERT) {
xp = object[i]._ox-2;
yp = object[i]._oy;
for (j = 0; j < 5; ++j) {
if ((dPlayer[xp][yp] != 0) || (dMonster[xp][yp] != 0))
object[i]._oVar4 = 1;
++xp;
}
} else {
xp = object[i]._ox;
yp = object[i]._oy-2;
for (j = 0; j < 5; ++j) {
if ((dPlayer[xp][yp] != 0) || (dMonster[xp][yp] != 0))
object[i]._oVar4 = 1;
++yp;
}
}
if (object[i]._oVar4 != 0) ActivateTrapLine(object[i]._otype, object[i]._oVar1);
} else {
if (object[i]._oAnimFrame == object[i]._oAnimLen) object[i]._oAnimFrame = 11;
if (object[i]._oAnimFrame <= 5) ChangeLightRadius(object[i]._olid, object[i]._oAnimFrame);
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void Obj_Trap(int i)
{
int oti;
bool otrig = false;
int sx, sy, dx, dy;
int x, y;
int ax, ay;
int mdir;
// Triggered?
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oVar4 == 0) {
oti = dObject[object[i]._oVar1][object[i]._oVar2] - 1;
switch (object[oti]._otype) {
case OBJ_CHEST1:
case OBJ_CHEST2:
case OBJ_CHEST3:
case OBJ_SWITCHSKL:
case OBJ_LEVER :
case OBJ_SARC:
if (object[oti]._oSelFlag == OSEL_NONE) otrig = true;
break;
case OBJ_L1DOORL :
case OBJ_L1DOORR :
case OBJ_L2DOORL :
case OBJ_L2DOORR :
case OBJ_L3DOORL :
case OBJ_L3DOORR :
if (object[oti]._oVar4 != DOOR_CLOSED) otrig = true;
break;
}
if (otrig) {
object[i]._oVar4 = 1;
sx = object[i]._ox;
sy = object[i]._oy;
dx = object[oti]._ox;
dy = object[oti]._oy;
ax = dx;
ay = dy;
for (y = ay-1; y <= ay+1; ++y) {
for (x = ax-1; x <= ax+1; ++x) {
if (dPlayer[x][y] != 0) {
dx = x;
dy = y;
}
}
}
if (!deltaload) {
mdir = GetDirection(sx, sy, dx, dy);
AddMissile(sx, sy, dx, dy, mdir, object[i]._oVar3, MI_ENEMYPLR, -1, 0, 0);
PlaySfxLoc(IS_TRAP, object[oti]._ox, object[oti]._oy);
}
object[oti]._oTrapFlag = FALSE;
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void Obj_BCrossDamage(int i)
{
int resist;
int damage[4] = { 6, 8, 10, 12 };
if (plr[myplr]._pmode != PM_DEATH) {
//Check for fire resistance. If resistance, adjust damage accordingly.
resist = plr[myplr]._pFireResist;
if (resist > 0) damage[leveltype-1] -= (damage[leveltype-1] * resist) / 100;
//Is the player in the fire?
app_assert((DWORD)i < MAXOBJECTS);
if ((plr[myplr]._px == object[i]._ox) && (plr[myplr]._py == object[i]._oy-1)) {
//Subtract damage
plr[myplr]._pHitPoints -= damage[leveltype-1];
plr[myplr]._pHPBase -= damage[leveltype-1];
//Check if player is dead
if ((plr[myplr]._pHitPoints >> HP_SHIFT) <= 0) {
// rjs - manashld fix? - SetPlayerHitPoints(myplr, 0);
StartPlrKill(myplr, FALSE);
} else {
//Play pain sfx
if (plr[myplr]._pClass == CLASS_WARRIOR) PlaySfxLoc(PS_WARR68, plr[myplr]._px, plr[myplr]._py);
#if !IS_VERSION(SHAREWARE)
else if (plr[myplr]._pClass == CLASS_ROGUE) PlaySfxLoc(PS_ROGUE68, plr[myplr]._px, plr[myplr]._py);
else if (plr[myplr]._pClass == CLASS_SORCEROR) PlaySfxLoc(PS_MAGE68, plr[myplr]._px, plr[myplr]._py);
else if (plr[myplr]._pClass == CLASS_MONK) PlaySfxLoc(PS_MONK68, plr[myplr]._px, plr[myplr]._py);
else if (plr[myplr]._pClass == CLASS_BARD) PlaySfxLoc(PS_BARD68, plr[myplr]._px, plr[myplr]._py);
else if (plr[myplr]._pClass == CLASS_BARBARIAN) PlaySfxLoc(PS_BARBARIAN68, plr[myplr]._px, plr[myplr]._py);
#endif
}
drawhpflag = TRUE;
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void ProcessObjects ()
{
int i, oi;
for (i = 0; i < numobjects; ++i) {
oi = objectactive[i];
app_assert((DWORD)oi < MAXOBJECTS);
switch (object[oi]._otype) {
case OBJ_L1LIGHT :
Obj_Light(oi, 10);
break;
case OBJ_CANDLE2 :
case OBJ_SKFIRE :
case OBJ_BOOKCANDLE:
Obj_Light(oi, 5);
break;
case OBJ_STORYCANDLE:
Obj_Light(oi, 3);
break;
case OBJ_CRUX1 :
case OBJ_CRUX2 :
case OBJ_CRUX3 :
case OBJ_BARREL:
case OBJ_BARRELEX:
case OBJ_SHRINEL:
case OBJ_SHRINER:
Obj_StopAnim(oi);
break;
case OBJ_L1DOORL :
case OBJ_L1DOORR :
case OBJ_L2DOORL :
case OBJ_L2DOORR :
case OBJ_L3DOORL :
case OBJ_L3DOORR :
Obj_Door(oi);
break;
case OBJ_TORCHL:
case OBJ_TORCHR:
case OBJ_TORCHL2:
case OBJ_TORCHR2:
Obj_Light(oi, 8);
break;
case OBJ_SARC:
Obj_Sarc(oi);
break;
case OBJ_FLAMEHOLE:
Obj_FlameTrap(oi);
break;
case OBJ_TRAPL:
case OBJ_TRAPR:
Obj_Trap(oi);
break;
case OBJ_MCIRCLE1:
case OBJ_MCIRCLE2:
Obj_Circle(oi);
break;
case OBJ_TBCROSS:
case OBJ_BCROSS:
Obj_Light(oi, 10);
Obj_BCrossDamage(oi);
break;
}
// Animate Objects
if (object[oi]._oAnimFlag) {
++object[oi]._oAnimCnt;
if (object[oi]._oAnimCnt >= object[oi]._oAnimDelay) {
object[oi]._oAnimCnt = 0;
++object[oi]._oAnimFrame;
if (object[oi]._oAnimFrame > object[oi]._oAnimLen) object[oi]._oAnimFrame = 1;
}
}
}
i = 0;
while (i < numobjects) {
oi = objectactive[i];
if (object[oi]._oDelFlag) {
DeleteObject(oi, i);
i = 0;
} else ++i;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void ObjSetMicro(int dx, int dy, int pn)
{
WORD *mtsource;
int t;
WORD *mt;
dPiece[dx][dy] = pn;
--pn;
mt = &(dMT2[CalcRot(dx,dy)].mt[0]);
if (leveltype != 4) {
mtsource = (WORD *)(pMiniTiles + 20*pn);
for(t = 0; t < 10; ++t)
// MiniTiles array uses opposite y direction
// hence wierd index on next line
mt[t] = mtsource[8-(t&0xe)+(t&1)];
} else {
mtsource = (WORD *)(pMiniTiles + 32*pn);
for(t = 0; t < 16; ++t)
// MiniTiles array uses opposite y direction
// hence wierd index on next line
mt[t] = mtsource[14-(t&0xe)+(t&1)];
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void ObjSetMicro12(int dx, int dy)
{
long mt1,mt2;
int pn;
pn = dPiece[dx][dy] - 1;
__asm {
mov esi,dword ptr [pMiniTiles]
xor eax,eax
mov ax,word ptr [pn]
mov ebx,20
mul ebx
add esi,eax
add esi,16
xor eax,eax
lodsw
mov word ptr [mt1],ax
lodsw
mov word ptr [mt2],ax
}
dMT2[CalcRot(dx,dy)].mt[0] = mt1 & 0xffff;
dMT2[CalcRot(dx,dy)].mt[1] = mt2 & 0xffff;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void ObjSetMini(int x, int y, int v)
{
long v1,v2,v3,v4;
int xx, yy;
__asm {
mov esi,dword ptr [pMegaTiles]
xor eax,eax
mov ax,word ptr [v];
dec eax
shl eax,3
add esi,eax
xor eax,eax
lodsw
inc eax
mov dword ptr [v1],eax
lodsw
inc eax
mov dword ptr [v2],eax
lodsw
inc eax
mov dword ptr [v3],eax
lodsw
inc eax
mov dword ptr [v4],eax
}
xx = (x << 1) + DIRTEDGED2;
yy = (y << 1) + DIRTEDGED2;
ObjSetMicro(xx, yy, v1);
ObjSetMicro(xx+1, yy, v2);
ObjSetMicro(xx, yy+1, v3);
ObjSetMicro(xx+1, yy+1, v4);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void ObjL1Special(int x1, int y1, int x2, int y2)
{
int i,j;
for (j = y1; j <= y2; ++j) {
for (i = x1; i <= x2; ++i) {
dSpecial[i][j] = 0;
// Place tops of arches
if (dPiece[i][j] == 12) dSpecial[i][j] = 1;
if (dPiece[i][j] == 11) dSpecial[i][j] = 2;
if (dPiece[i][j] == 71) dSpecial[i][j] = 1;
if (dPiece[i][j] == 259) dSpecial[i][j] = 5;
if (dPiece[i][j] == 249) dSpecial[i][j] = 2;
if (dPiece[i][j] == 325) dSpecial[i][j] = 2;
if (dPiece[i][j] == 321) dSpecial[i][j] = 1;
if (dPiece[i][j] == 255) dSpecial[i][j] = 4;
if (dPiece[i][j] == 211) dSpecial[i][j] = 1;
if (dPiece[i][j] == 344) dSpecial[i][j] = 2;
if (dPiece[i][j] == 341) dSpecial[i][j] = 1;
if (dPiece[i][j] == 331) dSpecial[i][j] = 2;
if (dPiece[i][j] == 418) dSpecial[i][j] = 1;
if (dPiece[i][j] == 421) dSpecial[i][j] = 2;
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void ObjL2Special(int x1, int y1, int x2, int y2)
{
int i,j;
for (j = y1; j <= y2; ++j) {
for (i = x1; i <= x2; ++i) {
dSpecial[i][j] = 0;
if (dPiece[i][j] == 541) dSpecial[i][j] = 5;
if (dPiece[i][j] == 178) dSpecial[i][j] = 5;
if (dPiece[i][j] == 551) dSpecial[i][j] = 5;
if (dPiece[i][j] == 542) dSpecial[i][j] = 6;
if (dPiece[i][j] == 553) dSpecial[i][j] = 6;
if (dPiece[i][j] == 13) dSpecial[i][j] = 5;
if (dPiece[i][j] == 17) dSpecial[i][j] = 6;
}
}
for (j = y1; j <= y2; ++j) {
for (i = x1; i <= x2; ++i) {
if (dPiece[i][j] == 132) {
dSpecial[i][j+1] = 2;
dSpecial[i][j+2] = 1;
}
if ((dPiece[i][j] == 135) || (dPiece[i][j] == 139)) {
dSpecial[i+1][j] = 3;
dSpecial[i+2][j] = 4;
}
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void DoorSet(int oi, int dx, int dy)
{
int pn;
app_assert((DWORD)oi < MAXOBJECTS);
pn = dPiece[dx][dy];
if (currlevel < HIVESTART)
{
if (pn == 43) ObjSetMicro(dx,dy,392);
if (pn == 45) ObjSetMicro(dx,dy,394);
if ((pn == 50) && (object[oi]._otype == OBJ_L1DOORL)) ObjSetMicro(dx,dy,411);
if ((pn == 50) && (object[oi]._otype == OBJ_L1DOORR)) ObjSetMicro(dx,dy,412);
if (pn == 54) ObjSetMicro(dx,dy,397);
if (pn == 55) ObjSetMicro(dx,dy,398);
if (pn == 61) ObjSetMicro(dx,dy,399);
if (pn == 67) ObjSetMicro(dx,dy,400);
if (pn == 68) ObjSetMicro(dx,dy,401);
if (pn == 69) ObjSetMicro(dx,dy,403);
if (pn == 70) ObjSetMicro(dx,dy,404);
if (pn == 72) ObjSetMicro(dx,dy,406);
if (pn == 212) ObjSetMicro(dx,dy,407); // Blood
if (pn == 354) ObjSetMicro(dx,dy,409); // Plain L
if (pn == 355) ObjSetMicro(dx,dy,410); // Plain R
if (pn == 411) ObjSetMicro(dx,dy,396); // Double open
if (pn == 412) ObjSetMicro(dx,dy,396); // Double open
}
else
{
if (pn == 75) ObjSetMicro(dx,dy,204);
if (pn == 79) ObjSetMicro(dx,dy,208);
if ((pn == 86) && (object[oi]._otype == OBJ_L1DOORL)) ObjSetMicro(dx,dy,232);
if ((pn == 86) && (object[oi]._otype == OBJ_L1DOORR)) ObjSetMicro(dx,dy,234);
if (pn == 91) ObjSetMicro(dx,dy,215);
if (pn == 93) ObjSetMicro(dx,dy,218);
if (pn == 99) ObjSetMicro(dx,dy,220);
if (pn == 111) ObjSetMicro(dx,dy,222);
if (pn == 113) ObjSetMicro(dx,dy,224);
if (pn == 115) ObjSetMicro(dx,dy,226);
if (pn == 117) ObjSetMicro(dx,dy,228);
if (pn == 119) ObjSetMicro(dx,dy,230);
if (pn == 232) ObjSetMicro(dx,dy,212); // Double open
if (pn == 234) ObjSetMicro(dx,dy,212); // Double open
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void RedoPlayerVision()
{
int p;
for (p = 0; p < MAX_PLRS; ++p) {
if (! plr[p].plractive) continue;
if (currlevel != plr[p].plrlevel) continue;
ChangeVisionXY(plr[p]._pvid, plr[p]._px, plr[p]._py);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateL1RDoor(int pnum, int oi, bool sendflag)
{
int dx, dy;
bool dok;
app_assert((DWORD)oi < MAXOBJECTS);
if (object[oi]._oVar4 == DOOR_BLOCKED) {
if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
return;
}
dx = object[oi]._ox;
dy = object[oi]._oy;
if (object[oi]._oVar4 == DOOR_CLOSED) {
if ((pnum == myplr) && sendflag) NetSendCmdParam1(TRUE,CMD_OPENDOOR,oi);
if (currlevel < CRYPTSTART)
{
if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy);
}
else
{
if (!deltaload) PlaySfxLoc(CR_DOOROPEN, object[oi]._ox, object[oi]._oy);
}
if (currlevel < CRYPTSTART)
ObjSetMicro(dx,dy,395);
else
ObjSetMicro(dx,dy,209);
if (currlevel < HIVESTART)
dSpecial[dx][dy] = 8;
else
dSpecial[dx][dy] = 2;
ObjSetMicro12(dx,dy-1);
--dx;
object[oi]._oAnimFrame += 2;
#ifdef NO_L5_DOORS
if (currlevel > HIVESTART)
object[oi]._oAnimFrame = -1;
#endif
object[oi]._oPreFlag = TRUE;
DoorSet(oi, dx, dy);
object[oi]._oVar4 = DOOR_OPEN;
object[oi]._oSelFlag = OSEL_TOP;
RedoPlayerVision();
} else {
if (currlevel < CRYPTSTART)
{
if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
}
else
{
if (!deltaload) PlaySfxLoc(CR_DOORCLOS, object[oi]._ox, object[oi]._oy);
}
dok = (dMonster[dx][dy] == 0);
dok = dok && (dItem[dx][dy] == 0);
dok = dok && (dDead[dx][dy] == 0);
if (dok) {
if ((pnum == myplr) && sendflag) NetSendCmdParam1(TRUE,CMD_CLOSEDOOR,oi);
object[oi]._oVar4 = DOOR_CLOSED;
object[oi]._oSelFlag = OSEL_ALL;
ObjSetMicro(dx,dy,object[oi]._oVar1);
if (currlevel < HIVESTART)
{
if (object[oi]._oVar2 != 50) ObjSetMicro(dx-1,dy,object[oi]._oVar2);
else {
// Double door
if (dPiece[dx-1][dy] == 396) ObjSetMicro(dx-1,dy,411);
else ObjSetMicro(dx-1,dy,object[oi]._oVar2);
}
}
else
{
if (object[oi]._oVar2 != 86) ObjSetMicro(dx-1,dy,object[oi]._oVar2);
else {
// Double door
if (dPiece[dx-1][dy] == 210) ObjSetMicro(dx-1,dy,232);
else ObjSetMicro(dx-1,dy,object[oi]._oVar2);
}
}
object[oi]._oAnimFrame -= 2;
object[oi]._oPreFlag = FALSE;
RedoPlayerVision();
} else object[oi]._oVar4 = DOOR_BLOCKED;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateL1LDoor(int pnum, int oi, bool sendflag)
{
int dx, dy;
bool dok;
app_assert((DWORD)oi < MAXOBJECTS);
if (object[oi]._oVar4 == DOOR_BLOCKED) {
if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
return;
}
dx = object[oi]._ox;
dy = object[oi]._oy;
if (object[oi]._oVar4 == DOOR_CLOSED) {
if ((pnum == myplr) && sendflag) NetSendCmdParam1(TRUE,CMD_OPENDOOR,oi);
if (currlevel < CRYPTSTART)
{
if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy);
}
else
{
if (!deltaload) PlaySfxLoc(CR_DOOROPEN, object[oi]._ox, object[oi]._oy);
}
if (currlevel < CRYPTSTART)
{
if (object[oi]._oVar1 == 214)
ObjSetMicro(dx,dy,408); //Blood
else
ObjSetMicro(dx,dy,393);
}
else
ObjSetMicro(dx,dy,206);
if (currlevel < HIVESTART)
dSpecial[dx][dy] = 7;
else
dSpecial[dx][dy] = 1;
ObjSetMicro12(dx-1,dy);
--dy;
object[oi]._oAnimFrame += 2;
#ifdef NO_L5_DOORS
if (currlevel > HIVESTART)
object[oi]._oAnimFrame = -1;
#endif
object[oi]._oPreFlag = TRUE;
DoorSet(oi, dx, dy);
object[oi]._oVar4 = DOOR_OPEN;
object[oi]._oSelFlag = OSEL_TOP;
RedoPlayerVision();
} else {
if (currlevel < CRYPTSTART)
{
if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
}
else
{
if (!deltaload) PlaySfxLoc(CR_DOORCLOS, object[oi]._ox, object[oi]._oy);
}
dok = (dMonster[dx][dy] == 0);
dok = dok && (dItem[dx][dy] == 0);
dok = dok && (dDead[dx][dy] == 0);
if (dok) {
if ((pnum == myplr) && sendflag) NetSendCmdParam1(TRUE,CMD_CLOSEDOOR,oi);
object[oi]._oVar4 = DOOR_CLOSED;
object[oi]._oSelFlag = OSEL_ALL;
ObjSetMicro(dx,dy,object[oi]._oVar1);
if (currlevel < HIVESTART)
{
if (object[oi]._oVar2 != 50) ObjSetMicro(dx,dy-1,object[oi]._oVar2);
else {
// Double door
if (dPiece[dx][dy-1] == 396) ObjSetMicro(dx,dy-1,412);
else ObjSetMicro(dx,dy-1,object[oi]._oVar2);
}
}
else
{
if (object[oi]._oVar2 != 86) ObjSetMicro(dx,dy-1,object[oi]._oVar2);
else {
// Double door
if (dPiece[dx][dy-1] == 210) ObjSetMicro(dx,dy-1,234);
else ObjSetMicro(dx,dy-1,object[oi]._oVar2);
}
}
object[oi]._oAnimFrame -= 2;
object[oi]._oPreFlag = FALSE;
RedoPlayerVision();
} else object[oi]._oVar4 = DOOR_BLOCKED;
}
}
/*-----------------------------------------------------------------------*/
// this is the stupidest fix I've ever seen an' I did it! JKE
/*-----------------------------------------------------------------------*/
void OpenCloseAllDoors()
{
int i;
BOOL odeltaload = deltaload;
deltaload = TRUE;
for (i = 0; i < MAXOBJECTS; ++i)
{
if (object[i]._otype == OBJ_L1DOORL)
{
OperateL1LDoor(myplr, i, FALSE);
OperateL1LDoor(myplr, i, FALSE);
}
else
if (object[i]._otype == OBJ_L1DOORR)
{
OperateL1RDoor(myplr, i, FALSE);
OperateL1RDoor(myplr, i, FALSE);
}
}
deltaload = odeltaload;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateL2RDoor(int pnum, int oi, bool sendflag)
{
int dx, dy;
bool dok;
app_assert((DWORD)oi < MAXOBJECTS);
if (object[oi]._oVar4 == DOOR_BLOCKED) {
if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
return;
}
dx = object[oi]._ox;
dy = object[oi]._oy;
if (object[oi]._oVar4 == DOOR_CLOSED) {
if ((pnum == myplr) && sendflag) NetSendCmdParam1(TRUE,CMD_OPENDOOR,oi);
if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy);
ObjSetMicro(dx,dy,17);
object[oi]._oAnimFrame += 2;
object[oi]._oPreFlag = TRUE;
object[oi]._oVar4 = DOOR_OPEN;
object[oi]._oSelFlag = OSEL_TOP;
RedoPlayerVision();
} else {
if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
dok = (dMonster[dx][dy] == 0);
dok = dok && (dItem[dx][dy] == 0);
dok = dok && (dDead[dx][dy] == 0);
if (dok) {
if ((pnum == myplr) && sendflag) NetSendCmdParam1(TRUE,CMD_CLOSEDOOR,oi);
object[oi]._oVar4 = DOOR_CLOSED;
object[oi]._oSelFlag = OSEL_ALL;
ObjSetMicro(dx,dy,540);
object[oi]._oAnimFrame -= 2;
object[oi]._oPreFlag = FALSE;
RedoPlayerVision();
} else object[oi]._oVar4 = DOOR_BLOCKED;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
const void OperateL2LDoor(int pnum, int oi, BOOL sendflag)
{
int dx, dy;
bool dok;
app_assert((DWORD)oi < MAXOBJECTS);
if (object[oi]._oVar4 == DOOR_BLOCKED) {
if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
return;
}
dx = object[oi]._ox;
dy = object[oi]._oy;
if (object[oi]._oVar4 == DOOR_CLOSED) {
if ((pnum == myplr) && sendflag) NetSendCmdParam1(TRUE,CMD_OPENDOOR,oi);
if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy);
ObjSetMicro(dx,dy,13);
object[oi]._oAnimFrame += 2;
object[oi]._oPreFlag = TRUE;
object[oi]._oVar4 = DOOR_OPEN;
object[oi]._oSelFlag = OSEL_TOP;
RedoPlayerVision();
} else {
if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
dok = (dMonster[dx][dy] == 0);
dok = dok && (dItem[dx][dy] == 0);
dok = dok && (dDead[dx][dy] == 0);
if (dok) {
if ((pnum == myplr) && sendflag) NetSendCmdParam1(TRUE,CMD_CLOSEDOOR,oi);
object[oi]._oVar4 = DOOR_CLOSED;
object[oi]._oSelFlag = OSEL_ALL;
ObjSetMicro(dx,dy,538);
object[oi]._oAnimFrame -= 2;
object[oi]._oPreFlag = FALSE;
RedoPlayerVision();
} else object[oi]._oVar4 = DOOR_BLOCKED;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateL3RDoor(int pnum, int oi, bool sendflag)
{
int dx, dy;
bool dok;
app_assert((DWORD)oi < MAXOBJECTS);
if (object[oi]._oVar4 == DOOR_BLOCKED) {
if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
return;
}
dx = object[oi]._ox;
dy = object[oi]._oy;
if (object[oi]._oVar4 == DOOR_CLOSED) {
if ((pnum == myplr) && sendflag) NetSendCmdParam1(TRUE,CMD_OPENDOOR,oi);
if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy);
ObjSetMicro(dx,dy,541);
object[oi]._oAnimFrame += 2;
object[oi]._oPreFlag = TRUE;
object[oi]._oVar4 = DOOR_OPEN;
object[oi]._oSelFlag = OSEL_TOP;
RedoPlayerVision();
} else {
if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
dok = (dMonster[dx][dy] == 0);
dok = dok && (dItem[dx][dy] == 0);
dok = dok && (dDead[dx][dy] == 0);
if (dok) {
if ((pnum == myplr) && sendflag) NetSendCmdParam1(TRUE,CMD_CLOSEDOOR,oi);
object[oi]._oVar4 = DOOR_CLOSED;
object[oi]._oSelFlag = OSEL_ALL;
ObjSetMicro(dx,dy,534);
object[oi]._oAnimFrame -= 2;
object[oi]._oPreFlag = FALSE;
RedoPlayerVision();
} else object[oi]._oVar4 = DOOR_BLOCKED;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateL3LDoor(int pnum, int oi, bool sendflag)
{
int dx, dy;
bool dok;
app_assert((DWORD)oi < MAXOBJECTS);
if (object[oi]._oVar4 == DOOR_BLOCKED) {
if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
return;
}
dx = object[oi]._ox;
dy = object[oi]._oy;
if (object[oi]._oVar4 == DOOR_CLOSED) {
if ((pnum == myplr) && sendflag) NetSendCmdParam1(TRUE,CMD_OPENDOOR,oi);
if (!deltaload) PlaySfxLoc(IS_DOOROPEN, object[oi]._ox, object[oi]._oy);
ObjSetMicro(dx,dy,538);
object[oi]._oAnimFrame += 2;
object[oi]._oPreFlag = TRUE;
object[oi]._oVar4 = DOOR_OPEN;
object[oi]._oSelFlag = OSEL_TOP;
RedoPlayerVision();
} else {
if (!deltaload) PlaySfxLoc(IS_DOORCLOS, object[oi]._ox, object[oi]._oy);
dok = (dMonster[dx][dy] == 0);
dok = dok && (dItem[dx][dy] == 0);
dok = dok && (dDead[dx][dy] == 0);
if (dok) {
if ((pnum == myplr) && sendflag) NetSendCmdParam1(TRUE,CMD_CLOSEDOOR,oi);
object[oi]._oVar4 = DOOR_CLOSED;
object[oi]._oSelFlag = OSEL_ALL;
ObjSetMicro(dx,dy,531);
object[oi]._oAnimFrame -= 2;
object[oi]._oPreFlag = FALSE;
RedoPlayerVision();
} else object[oi]._oVar4 = DOOR_BLOCKED;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void MonstCheckDoors(int m)
{
int i, oi, dpx, dpy;
int mx, my;
mx = monster[m]._mx;
my = monster[m]._my;
if (!(dObject[mx-1][my-1]
|| dObject[mx][my-1]
|| dObject[mx+1][my-1]
|| dObject[mx-1][my]
|| dObject[mx+1][my]
|| dObject[mx-1][my+1]
|| dObject[mx][my+1]
|| dObject[mx+1][my+1]))
return;
for (i = 0; i < numobjects; ++i) {
oi = objectactive[i];
app_assert((DWORD)oi < MAXOBJECTS);
if ((object[oi]._otype == OBJ_L1DOORL) || (object[oi]._otype == OBJ_L1DOORR)) {
if (object[oi]._oVar4 == DOOR_CLOSED) {
dpx = abs(object[oi]._ox - mx);
dpy = abs(object[oi]._oy - my);
if ((dpx == 1) && (dpy <= 1) && (object[oi]._otype == OBJ_L1DOORL)) OperateL1LDoor(myplr, oi, true);
if ((dpx <= 1) && (dpy == 1) && (object[oi]._otype == OBJ_L1DOORR)) OperateL1RDoor(myplr, oi, true);
}
}
if ((object[oi]._otype == OBJ_L2DOORL) || (object[oi]._otype == OBJ_L2DOORR)) {
if (object[oi]._oVar4 == DOOR_CLOSED) {
dpx = abs(object[oi]._ox - mx);
dpy = abs(object[oi]._oy - my);
if ((dpx == 1) && (dpy <= 1) && (object[oi]._otype == OBJ_L2DOORL)) OperateL2LDoor(myplr, oi, true);
if ((dpx <= 1) && (dpy == 1) && (object[oi]._otype == OBJ_L2DOORR)) OperateL2RDoor(myplr, oi, true);
}
}
if ((object[oi]._otype == OBJ_L3DOORL) || (object[oi]._otype == OBJ_L3DOORR)) {
if (object[oi]._oVar4 == DOOR_CLOSED) {
dpx = abs(object[oi]._ox - mx);
dpy = abs(object[oi]._oy - my);
if ((dpx == 1) && (dpy <= 1) && (object[oi]._otype == OBJ_L3DOORR)) OperateL3RDoor(myplr, oi, true);
if ((dpx <= 1) && (dpy == 1) && (object[oi]._otype == OBJ_L3DOORL)) OperateL3LDoor(myplr, oi, true);
}
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void ObjChangeMap(int x1, int y1, int x2, int y2)
{
int i,j;
for (j = y1; j <= y2; ++j) {
for (i = x1; i <= x2; ++i) {
ObjSetMini(i, j, pdungeon[i][j]);
dungeon[i][j] = pdungeon[i][j]; // For automap
}
}
if ((leveltype == 1)&&(currlevel < HIVESTART)) { // JKE
ObjL1Special((x1 << 1) + DIRTEDGED2, (y1 << 1) + DIRTEDGED2, (x2 << 1) + DIRTEDGED2 + 1, (y2 << 1) + DIRTEDGED2 + 1);
AddL1Objs((x1 << 1) + DIRTEDGED2, (y1 << 1) + DIRTEDGED2, (x2 << 1) + DIRTEDGED2 + 1, (y2 << 1) + DIRTEDGED2 + 1);
}
if (leveltype == 2) {
ObjL2Special((x1 << 1) + DIRTEDGED2, (y1 << 1) + DIRTEDGED2, (x2 << 1) + DIRTEDGED2 + 1, (y2 << 1) + DIRTEDGED2 + 1);
AddL2Objs((x1 << 1) + DIRTEDGED2, (y1 << 1) + DIRTEDGED2, (x2 << 1) + DIRTEDGED2 + 1, (y2 << 1) + DIRTEDGED2 + 1);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void ObjChangeMapResync(int x1, int y1, int x2, int y2)
{
int i,j;
for (j = y1; j <= y2; ++j) {
for (i = x1; i <= x2; ++i) {
ObjSetMini(i, j, pdungeon[i][j]);
dungeon[i][j] = pdungeon[i][j]; // For automap
}
}
if ((leveltype == 1)&&(currlevel < HIVESTART))
ObjL1Special((x1 << 1) + DIRTEDGED2, (y1 << 1) + DIRTEDGED2, (x2 << 1) + DIRTEDGED2 + 1, (y2 << 1) + DIRTEDGED2 + 1);
if (leveltype == 2)
ObjL2Special((x1 << 1) + DIRTEDGED2, (y1 << 1) + DIRTEDGED2, (x2 << 1) + DIRTEDGED2 + 1, (y2 << 1) + DIRTEDGED2 + 1);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateL1Door(int pnum, int i, bool sendflag)
{
int dpx, dpy;
app_assert((DWORD)i < MAXOBJECTS);
dpx = abs(object[i]._ox - plr[pnum]._px);
dpy = abs(object[i]._oy - plr[pnum]._py);
if ((dpx == 1) && (dpy <= 1) && (object[i]._otype == OBJ_L1DOORL)) OperateL1LDoor(pnum, i, sendflag);
if ((dpx <= 1) && (dpy == 1) && (object[i]._otype == OBJ_L1DOORR)) OperateL1RDoor(pnum, i, sendflag);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateLever(int pnum, int i)
{
bool mapflag;
int j, oi, ot;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
if (!deltaload) PlaySfxLoc(IS_LEVER, object[i]._ox, object[i]._oy);
// Toggle to on
object[i]._oSelFlag = OSEL_NONE;
++object[i]._oAnimFrame;
mapflag = true;
if (currlevel == DIABLO_LEVEL) {
for (j = 0; j < numobjects; ++j) {
oi = objectactive[j];
ot = object[oi]._otype;
if (ot == OBJ_SWITCHSKL) {
if ((object[i]._oVar8 == object[oi]._oVar8) && (object[oi]._oSelFlag != OSEL_NONE))
mapflag = FALSE;
}
}
}
if (currlevel == NA_KRUL_LEVEL)
{
// dPiece[Na_Krul.LeverX][Na_Krul.LeverY] = 316;
OpenNaKrul();
Na_Krul.Lever_Thrown = TRUE;
mapflag = FALSE;
quests[Q_NA_KRUL]._qactive = QUEST_DONE;
}
if (mapflag) ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
if (pnum == myplr) NetSendCmdParam1(FALSE,CMD_OPERATEOBJ,i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateBook(int pnum, int i)
{
int v1, v2, v3;
int j, oi, ot, itm;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
if ((setlevel) && (setlvlnum == SL_VILEBETRAYER)) {
bool found = false;
bool dowarp = false;
for (j = 0; j < numobjects; ++j) {
oi = objectactive[j];
ot = object[oi]._otype;
if ((ot == OBJ_MCIRCLE2) && (object[oi]._oVar6 == OBJWARP1)) {
v1 = 27;
v2 = 29;
// rmw.patch1.start.1/23/97
// object[oi]._oVar6 == OBJDONEWARP;
object[oi]._oVar6 = OBJDONEWARP;
// rmw.patch1.end.1/23/97
dowarp = TRUE;
}
if ((ot == OBJ_MCIRCLE2) && (object[oi]._oVar6 == OBJWARP2)) {
v1 = 43;
v2 = 29;
// rmw.patch1.start.1/23/97
// object[oi]._oVar6 == OBJDONEWARP;
object[oi]._oVar6 = OBJDONEWARP;
// rmw.patch1.end.1/23/97
dowarp = TRUE;
}
if (dowarp) {
v3 = dPiece[v1][v2];
++object[dObject[35][36]-1]._oVar5;
AddMissile(plr[pnum]._px, plr[pnum]._py, v1, v2, plr[pnum]._pdir, MIT_PHASE, MI_ENEMYMONST, pnum, 0, 0);
found = TRUE;
dowarp = FALSE;
}
}
if (!found) return;
}
// Toggle open
object[i]._oSelFlag = OSEL_NONE;
++object[i]._oAnimFrame;
if ((setlevel) && (setlvlnum == SL_BONECHAMB)) {
__int64 t = 1;
plr[myplr]._pMemSpells |= t << (SPL_GUARDIAN-1);
if (plr[pnum]._pSplLvl[SPL_GUARDIAN] < SPELLCAP) {
++plr[myplr]._pSplLvl[SPL_GUARDIAN];
}
quests[Q_SCHAMB]._qactive = QUEST_DONE;
if (!deltaload) PlaySfxLoc(IS_QUESTDN, object[i]._ox, object[i]._oy);
InitDiabloMsg(MSG_INBONE);
AddMissile(plr[myplr]._px, plr[myplr]._py, object[i]._ox - 2, object[i]._oy - 4, plr[myplr]._pdir, MIT_GUARDIAN, MI_ENEMYMONST, myplr, 0, 0);
}
if ((setlevel) && (setlvlnum == SL_VILEBETRAYER)) {
ObjChangeMapResync(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
for (itm = 0; itm < numobjects; ++itm) SyncObjectAnim(objectactive[itm]);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateBookLever(int pnum, int i)
{
int x,y, tren;
app_assert(gbMaxPlayers == 1);
x = (setpc_x << 1) + DIRTEDGED2;
y = (setpc_y << 1) + DIRTEDGED2;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
if (qtextflag) return;
// Check quests
if ((object[i]._otype == OBJ_BLINDBOOK) && (quests[Q_BLIND]._qvar1 == 0)) {
quests[Q_BLIND]._qactive = QUEST_NOTDONE;
quests[Q_BLIND]._qlog = TRUE;
quests[Q_BLIND]._qvar1 = 1;
}
if ((object[i]._otype == OBJ_BLOODBOOK) && (quests[Q_BLOOD]._qvar1 == 0)) {
quests[Q_BLOOD]._qactive = QUEST_NOTDONE;
quests[Q_BLOOD]._qlog = TRUE;
quests[Q_BLOOD]._qvar1 = 1;
SpawnQuestItem(IDI_BLDSTONE, (setpc_x << 1) + 3 + DIRTEDGED2, (setpc_y << 1) + 10 + DIRTEDGED2, FALSE, ISEL_FLR);
SpawnQuestItem(IDI_BLDSTONE, (setpc_x << 1) + 15 + DIRTEDGED2, (setpc_y << 1) + 10 + DIRTEDGED2, FALSE, ISEL_FLR);
SpawnQuestItem(IDI_BLDSTONE, (setpc_x << 1) + 9 + DIRTEDGED2, (setpc_y << 1) + 17 + DIRTEDGED2, FALSE, ISEL_FLR);
}
if ((object[i]._otype == OBJ_STEELTOME) && (quests[Q_WARLORD]._qvar1 == 0)) {
quests[Q_WARLORD]._qactive = QUEST_NOTDONE;
quests[Q_WARLORD]._qlog = TRUE;
quests[Q_WARLORD]._qvar1 = 1;
}
// Change map
if (object[i]._oAnimFrame != object[i]._oVar6) {
if (object[i]._otype != OBJ_BLOODBOOK) ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
if (object[i]._otype == OBJ_BLINDBOOK) {
CreateItem(UID_OPTAMULET, x+5, y+5);
tren = TransVal;
TransVal = 9;
DRLG_MRectTrans(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
TransVal = tren;
}
}
// Toggle open
// object[i]._oSelFlag = OSEL_NONE;
object[i]._oAnimFrame = object[i]._oVar6;
// Display msg
InitQTextMsg(object[i]._oVar7);
if (pnum == myplr) NetSendCmdParam1(FALSE,CMD_OPERATEOBJ,i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateSChambBk(int pnum, int i)
{
int textdef,j;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
if (qtextflag) return;
// object[i]._oSelFlag = OSEL_NONE;
// Change map
if (object[i]._oAnimFrame != object[i]._oVar6) {
ObjChangeMapResync(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
for (j = 0; j < numobjects; ++j) SyncObjectAnim(objectactive[j]);
}
// Toggle open
object[i]._oAnimFrame = object[i]._oVar6;
if (quests[Q_SCHAMB]._qactive == QUEST_NOTACTIVE) {
quests[Q_SCHAMB]._qactive = QUEST_NOTDONE;
quests[Q_SCHAMB]._qlog = TRUE;
}
if (plr[myplr]._pClass == CLASS_WARRIOR) textdef = TXT_WARBONE;
else if (plr[myplr]._pClass == CLASS_ROGUE) textdef = TXT_ROGBONE;
else if (plr[myplr]._pClass == CLASS_SORCEROR) textdef = TXT_SORBONE;
else if (plr[myplr]._pClass == CLASS_MONK) textdef = TXT_MNKBONE;
else if (plr[myplr]._pClass == CLASS_BARD) textdef = TXT_BRDBONE;
else if (plr[myplr]._pClass == CLASS_BARBARIAN) textdef = TXT_BARBONE;
quests[Q_SCHAMB]._qmsg = textdef;
InitQTextMsg(textdef);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateChest(int pnum, int i, bool sendmsg)
{
int j, mdir, mtype = MIT_ARROW;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
if (!deltaload) PlaySfxLoc(IS_CHEST, object[i]._ox, object[i]._oy);
object[i]._oSelFlag = OSEL_NONE;
object[i]._oAnimFrame += 2;
if (deltaload) return;
SetRndSeed(object[i]._oRndSeed);
if (setlevel) { //Create only good items for set levels
for (j = 0; j < object[i]._oVar1; ++j) {
CreateRndItem(object[i]._ox, object[i]._oy, TRUE, sendmsg, FALSE);
}
} else {
for (j = 0; j < object[i]._oVar1; ++j) {
if (object[i]._oVar2) CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE);
else CreateRndUseful(pnum, object[i]._ox, object[i]._oy, sendmsg);
}
}
if ((object[i]._oTrapFlag) &&
(object[i]._otype >= OBJ_TCHEST1) &&
(object[i]._otype <= OBJ_TCHEST3)) {
mdir = GetDirection(object[i]._ox, object[i]._oy, plr[pnum]._px, plr[pnum]._py);
switch(object[i]._oVar4) {
case 0:
mtype = MIT_ARROW;
break;
case 1:
mtype = MIT_FARROW;
break;
case 2:
mtype = MIT_NOVA;
break;
case 3:
mtype = MIT_FLAMEBOX;
// SpawnSkeleton(object[i]._oVar2, object[i]._ox, object[i]._oy);
break;
case 4:
mtype = MIT_DISENCHANT;
break;
case 5:
mtype = MIT_MANAREMOVE;
break;
#if defined(HELLFIRE2)
// GWP Another good trap might be acid splatted all around.
case 6:
mtype = MIT_LIGHTBOX;
// SpawnSkeleton(object[i]._oVar2, object[i]._ox, object[i]._oy);
break;
#endif
default:
mtype = MIT_ARROW;
break;
}
AddMissile(object[i]._ox, object[i]._oy, plr[pnum]._px, plr[pnum]._py, mdir, mtype, MI_ENEMYPLR, -1, 0, 0);
object[i]._oTrapFlag = FALSE;
}
if (pnum == myplr) NetSendCmdParam2(FALSE,CMD_PLROPOBJ,pnum,i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateMushPatch(int pnum, int i)
{
int x, y;
if (!(quests[Q_BKMUSHRM]._qactive == QUEST_NOTDONE
&& (quests[Q_BKMUSHRM]._qvar1 >= QS_TOMEGIVEN))) // FUNGALTM was given to Witch
{
if (!deltaload && pnum == myplr) {
if (plr[myplr]._pClass == CLASS_WARRIOR) PlaySFX(PS_WARR13);
#if !IS_VERSION(SHAREWARE)
else if (plr[myplr]._pClass == CLASS_ROGUE) PlaySFX(PS_ROGUE13);
else if (plr[myplr]._pClass == CLASS_SORCEROR) PlaySFX(PS_MAGE13);
else if (plr[myplr]._pClass == CLASS_MONK) PlaySFX(PS_MONK13);
else if (plr[myplr]._pClass == CLASS_BARD) PlaySFX(PS_BARD13);
else if (plr[myplr]._pClass == CLASS_BARBARIAN) PlaySFX(PS_BARBARIAN13);
#endif
}
return;
}
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE)
return;
if (!deltaload) PlaySfxLoc(IS_CHEST, object[i]._ox, object[i]._oy);
object[i]._oSelFlag = OSEL_NONE;
object[i]._oAnimFrame += 1;
if (deltaload) return;
GetSuperItemLoc(object[i]._ox, object[i]._oy, x, y);
SpawnQuestItem(IDI_MUSHROOM, x,y,0, ISEL_NONE);
quests[Q_BKMUSHRM]._qvar1 = QS_MUSHSPAWNED;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateInnSignChest(int pnum, int i)
{
int x, y;
if (!(quests[Q_LTBANNER]._qvar1 == 2))
{
if (!deltaload && pnum == myplr) {
if (plr[myplr]._pClass == CLASS_WARRIOR) PlaySFX(PS_WARR24);
#if !IS_VERSION(SHAREWARE)
else if (plr[myplr]._pClass == CLASS_ROGUE) PlaySFX(PS_ROGUE24);
else if (plr[myplr]._pClass == CLASS_SORCEROR) PlaySFX(PS_MAGE24);
else if (plr[myplr]._pClass == CLASS_MONK) PlaySFX(PS_MONK24);
else if (plr[myplr]._pClass == CLASS_BARD) PlaySFX(PS_BARD24);
else if (plr[myplr]._pClass == CLASS_BARBARIAN) PlaySFX(PS_BARBARIAN24);
#endif
}
return;
}
if (object[i]._oSelFlag == OSEL_NONE)
return;
if (!deltaload) PlaySfxLoc(IS_CHEST, object[i]._ox, object[i]._oy);
object[i]._oSelFlag = OSEL_NONE;
object[i]._oAnimFrame += 2;
if (deltaload) return;
GetSuperItemLoc(object[i]._ox, object[i]._oy, x, y);
SpawnQuestItem(IDI_BANNER, x,y,0, ISEL_NONE);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateSlainHero(int pnum, int i, bool sendmsg)
{
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
object[i]._oSelFlag = OSEL_NONE;
if (deltaload) return;
if (plr[pnum]._pClass == CLASS_WARRIOR) {
//Create magic breast plate
CreateMagicArmor(object[i]._ox, object[i]._oy, IT_HARMOR, ITEM_BPLATE, FALSE, TRUE);
#if !IS_VERSION(SHAREWARE)
PlaySfxLoc(PS_WARR9, plr[myplr]._px, plr[myplr]._py);
#endif
} else if (plr[pnum]._pClass == CLASS_ROGUE) {
//Create magic long battle bow
CreateMagicWeapon(object[i]._ox, object[i]._oy, IT_BOW, ITEM_STLLONGBOW, FALSE, TRUE);
#if !IS_VERSION(SHAREWARE)
PlaySfxLoc(PS_ROGUE9, plr[myplr]._px, plr[myplr]._py);
#endif
} else if (plr[pnum]._pClass == CLASS_SORCEROR) {
//Create book of lightning
CreateSpellBook(object[i]._ox, object[i]._oy, SPL_LIGHTNING, FALSE, TRUE);
#if !IS_VERSION(SHAREWARE)
PlaySfxLoc(PS_MAGE9, plr[myplr]._px, plr[myplr]._py);
#endif
} else if (plr[pnum]._pClass == CLASS_MONK) {
//Create magic staff
CreateMagicWeapon(object[i]._ox, object[i]._oy, IT_STAFF, ITEM_STLSTAFF, FALSE, TRUE);
#if !IS_VERSION(SHAREWARE)
PlaySfxLoc(PS_MONK9, plr[myplr]._px, plr[myplr]._py);
#endif
} else if (plr[pnum]._pClass == CLASS_BARD) {
//Create special sword.
CreateMagicWeapon(object[i]._ox, object[i]._oy, IT_SWORD, ITEM_BASTSRD, FALSE, TRUE);
#if !IS_VERSION(SHAREWARE)
PlaySfxLoc(PS_BARD9, plr[myplr]._px, plr[myplr]._py);
#endif
} else if (plr[pnum]._pClass == CLASS_BARBARIAN) {
//Create special sword.
CreateMagicWeapon(object[i]._ox, object[i]._oy, IT_AXE, ITEM_BTLAXE, FALSE, TRUE);
#if !IS_VERSION(SHAREWARE)
PlaySfxLoc(PS_BARBARIAN9, plr[myplr]._px, plr[myplr]._py);
#endif
}
if (pnum == myplr) NetSendCmdParam1(FALSE,CMD_OPERATEOBJ,i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateTrapLvr(int i)
{
int j, oi;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oAnimFrame == 1) {
// Toggle to on
++object[i]._oAnimFrame;
for (j = 0; j < numobjects; ++j) {
oi = objectactive[j];
if ((object[oi]._otype == object[i]._oVar2) && (object[oi]._oVar1 == object[i]._oVar1)) {
object[oi]._oVar2 = 1;
object[oi]._oAnimFlag = FALSE;
}
}
} else {
// Toggle to off
--object[i]._oAnimFrame;
for (j = 0; j < numobjects; ++j) {
oi = objectactive[j];
if ((object[oi]._otype == object[i]._oVar2) && (object[oi]._oVar1 == object[i]._oVar1)) {
object[oi]._oVar2 = 0;
if (object[oi]._oVar4 != 0) object[oi]._oAnimFlag = TRUE;
}
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateSarc(int pnum, int i, bool sendmsg)
{
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
if (!deltaload) PlaySfxLoc(IS_SARC, object[i]._ox, object[i]._oy);
object[i]._oSelFlag = OSEL_NONE;
if (deltaload) {
object[i]._oAnimFrame = object[i]._oAnimLen;
return;
} else {
object[i]._oAnimFlag = TRUE;
object[i]._oAnimDelay = 3;
}
SetRndSeed(object[i]._oRndSeed);
if (object[i]._oVar1 <= 2) CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE);
if (object[i]._oVar1 >= 8) SpawnSkeleton(object[i]._oVar2, object[i]._ox, object[i]._oy);
#if CHEATS
if (itemcheat)
CreateMagicWeapon(object[i]._ox, object[i]._oy, IT_STAFF, ITEM_SHRTSTAFF, FALSE, TRUE);
#endif
if (pnum == myplr) NetSendCmdParam1(FALSE,CMD_OPERATEOBJ,i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateL2Door(int pnum, int i, bool sendflag)
{
int dpx, dpy;
app_assert((DWORD)i < MAXOBJECTS);
dpx = abs(object[i]._ox - plr[pnum]._px);
dpy = abs(object[i]._oy - plr[pnum]._py);
if ((dpx == 1) && (dpy <= 1) && (object[i]._otype == OBJ_L2DOORL)) OperateL2LDoor(pnum, i, sendflag);
if ((dpx <= 1) && (dpy == 1) && (object[i]._otype == OBJ_L2DOORR)) OperateL2RDoor(pnum, i, sendflag);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateL3Door(int pnum, int i, bool sendflag)
{
int dpx, dpy;
app_assert((DWORD)i < MAXOBJECTS);
dpx = abs(object[i]._ox - plr[pnum]._px);
dpy = abs(object[i]._oy - plr[pnum]._py);
if ((dpx == 1) && (dpy <= 1) && (object[i]._otype == OBJ_L3DOORR)) OperateL3RDoor(pnum, i, sendflag);
if ((dpx <= 1) && (dpy == 1) && (object[i]._otype == OBJ_L3DOORL)) OperateL3LDoor(pnum, i, sendflag);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperatePedistal(int pnum, int i)
{
int jstn;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oVar6 != 3) {
if (PlrHasItem(pnum, IDI_BLDSTONE, jstn)) {
RemoveInvItem(pnum, jstn);
++object[i]._oAnimFrame;
++object[i]._oVar6;
}
if (object[i]._oVar6 == 1) {
if (!deltaload) PlaySfxLoc(LS_PUDDLE, object[i]._ox, object[i]._oy);
ObjChangeMap(setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7);
}
if (object[i]._oVar6 == 2) {
if (!deltaload) PlaySfxLoc(LS_PUDDLE, object[i]._ox, object[i]._oy);
ObjChangeMap(setpc_x + 6, setpc_y + 3, setpc_x + setpc_w, setpc_y + 7);
}
if (object[i]._oVar6 == 3) {
if (!deltaload) PlaySfxLoc(LS_BLODSTAR, object[i]._ox, object[i]._oy);
ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
byte *setp;
setp = LoadFileInMemSig("Levels\\L2Data\\Blood2.DUN", NULL, 'STPC');
LoadMapObjs(setp, (setpc_x << 1), (setpc_y << 1));
DiabloFreePtr(setp);
CreateItem(UID_ARMOFVAL, (setpc_x << 1) + 9 + DIRTEDGED2, (setpc_y << 1) + 3 + DIRTEDGED2);
object[i]._oSelFlag = OSEL_NONE;
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void TryDisarm(int pnum, int i)
{
int j, oi, oti;
int trapdisper;
bool checkflag;
if (pnum == myplr) NewCursor(GLOVE_CURS);
app_assert((DWORD)i < MAXOBJECTS);
if (!object[i]._oTrapFlag) return;
trapdisper = (plr[pnum]._pDexterity << 1) - (currlevel * 5);
if (random(154,100) > trapdisper) return;
for (j = 0; j < numobjects; ++j) {
oi = objectactive[j];
checkflag = false;
if (object[oi]._otype == OBJ_TRAPL) checkflag = true;
if (object[oi]._otype == OBJ_TRAPR) checkflag = true;
if (checkflag) {
oti = dObject[object[oi]._oVar1][object[oi]._oVar2] - 1;
if (oti == i) {
object[oi]._oVar4 = 1;
object[i]._oTrapFlag = FALSE;
}
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
int ItemMiscIdIdx(int imiscid)
{
int i = 0;
while ((AllItemsList[i].iRnd == IRND_NO) || (AllItemsList[i].iMiscId != imiscid)) ++i;
return(i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateShrine(int pnum, int i, int sType)
{
int r, xx, yy, idata, sc;
int v1, v2, v3, v4;
__int64 lv, t;
bool done;
//Fixes any gold cheats
if (dropGoldFlag) {
dropGoldFlag = FALSE;
dropGoldValue = 0;
}
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
SetRndSeed(object[i]._oRndSeed);
object[i]._oSelFlag = OSEL_NONE;
if (! deltaload) {
PlaySfxLoc(sType, object[i]._ox, object[i]._oy);
object[i]._oAnimFlag = TRUE;
object[i]._oAnimDelay = 1;
} else {
object[i]._oAnimFrame = object[i]._oAnimLen;
object[i]._oAnimFlag = FALSE;
}
switch (object[i]._oVar1) {
case 0 : // Mysterious
if (deltaload) return;
if (pnum != myplr) return;
//Subtract 1 from all attributes
ModifyPlrStr(pnum, -1);
ModifyPlrMag(pnum, -1);
ModifyPlrDex(pnum, -1);
ModifyPlrVit(pnum, -1);
//Add 6 to random attribute. We are actually adding 5 since we
//subtracted 1 above.
switch(random(0, 4)) {
case 0:
ModifyPlrStr(pnum, 6);
break;
case 1:
ModifyPlrMag(pnum, 6);
break;
case 2:
ModifyPlrDex(pnum, 6);
break;
case 3:
ModifyPlrVit(pnum, 6);
break;
}
CheckStats(pnum);
InitDiabloMsg(SHRINE_1);
break;
case 1 : // Hidden
v1 = 0;
if (deltaload) return;
if (pnum != myplr) return;
//Find out if player has any items equipped
for (r = 0; r < NUM_INVLOC; ++r) {
if (plr[pnum].InvBody[r]._itype != -1) ++v1;
}
//Add 10 to max and current durability of all equipped items.
if (v1 > 0) {
for (r = 0; r < NUM_INVLOC; ++r) {
if (plr[pnum].InvBody[r]._itype != -1) {
//Ignore any items which are indestructible.
if ((plr[pnum].InvBody[r]._iMaxDur != INFINITE_DUR) &&
(plr[pnum].InvBody[r]._iMaxDur != 0)) {
plr[pnum].InvBody[r]._iDurability += 10;
plr[pnum].InvBody[r]._iMaxDur += 10;
if (plr[pnum].InvBody[r]._iDurability > plr[pnum].InvBody[r]._iMaxDur)
plr[pnum].InvBody[r]._iDurability = plr[pnum].InvBody[r]._iMaxDur;
}
}
}
done = false;
while (!done) {
// JMM.PATCH3
int numitems = 0;
for( r = 0; r < NUM_INVLOC; ++r ) {
if ( plr[pnum].InvBody[r]._itype != -1 )
++numitems;
}
if( !numitems ) {
done = true;
break;
}
// JMM.ENDPATCH3
r = random(0, NUM_INVLOC);
if (plr[pnum].InvBody[r]._itype != -1) {
//Ignore any items which are indestructible.
if ((plr[pnum].InvBody[r]._iMaxDur != INFINITE_DUR) &&
(plr[pnum].InvBody[r]._iMaxDur != 0)) {
//Subtract 20 from random equipped item. We are actually
//subtracting 10 since we added 10 above.
plr[pnum].InvBody[r]._iDurability -= 20;
plr[pnum].InvBody[r]._iMaxDur -= 20;
if (plr[pnum].InvBody[r]._iDurability <= 0) plr[pnum].InvBody[r]._iDurability = 1;
if (plr[pnum].InvBody[r]._iMaxDur <= 0) plr[pnum].InvBody[r]._iMaxDur = 1;
done = true;
break;
}
}
}
}
InitDiabloMsg(SHRINE_2);
break;
case 2: // Gloomy (Single Player Only)
if (deltaload) return;
if (pnum == myplr) {
if (plr[pnum].HeadItem._itype != -1) plr[pnum].HeadItem._iAC += 2;
if (plr[pnum].BodyItem._itype != -1) plr[pnum].BodyItem._iAC += 2;
if (plr[pnum].Hand1Item._itype != -1) {
if (plr[pnum].Hand1Item._itype == IT_SHIELD)
plr[pnum].Hand1Item._iAC += 2;
else {
--plr[pnum].Hand1Item._iMaxDam;
if (plr[pnum].Hand1Item._iMaxDam < plr[pnum].Hand1Item._iMinDam)
plr[pnum].Hand1Item._iMaxDam = plr[pnum].Hand1Item._iMinDam;
}
}
if (plr[pnum].Hand2Item._itype != -1) {
if (plr[pnum].Hand2Item._itype == IT_SHIELD)
plr[pnum].Hand2Item._iAC += 2;
else {
--plr[pnum].Hand2Item._iMaxDam;
if (plr[pnum].Hand2Item._iMaxDam < plr[pnum].Hand2Item._iMinDam)
plr[pnum].Hand2Item._iMaxDam = plr[pnum].Hand2Item._iMinDam;
}
}
for (r = 0; r < plr[pnum]._pNumInv; ++r) {
switch(plr[pnum].InvList[r]._itype) {
case IT_SHIELD:
case IT_ARMOR:
case IT_MARMOR:
case IT_HARMOR:
case IT_HELM:
plr[pnum].InvList[r]._iAC += 2;
break;
case IT_SWORD:
case IT_AXE:
case IT_BOW:
case IT_MACE:
case IT_STAFF:
--plr[pnum].InvList[r]._iMaxDam;
if (plr[pnum].InvList[r]._iMaxDam < plr[pnum].InvList[r]._iMinDam)
plr[pnum].InvList[r]._iMaxDam = plr[pnum].InvList[r]._iMinDam;
break;
}
}
InitDiabloMsg(SHRINE_3);
}
break;
case 3: // Weird (Single Player Only)
if (deltaload) return;
if (pnum == myplr) {
if ((plr[pnum].Hand1Item._itype != -1) && (plr[pnum].Hand1Item._itype != IT_SHIELD))
++plr[pnum].Hand1Item._iMaxDam;
if ((plr[pnum].Hand2Item._itype != -1) && (plr[pnum].Hand2Item._itype != IT_SHIELD))
++plr[pnum].Hand2Item._iMaxDam;
for (r = 0; r < plr[pnum]._pNumInv; ++r) {
switch(plr[pnum].InvList[r]._itype) {
case IT_SWORD:
case IT_AXE:
case IT_BOW:
case IT_MACE:
case IT_STAFF:
++plr[pnum].InvList[r]._iMaxDam;
break;
}
}
InitDiabloMsg(SHRINE_4);
}
break;
case 4: // Magical
case 11: // Supernatural
if (deltaload) return;
//Cast mana shield
AddMissile(plr[pnum]._px, plr[pnum]._py, plr[pnum]._px, plr[pnum]._py,
plr[pnum]._pdir, MIT_MANASHIELD, -1, pnum, 0,
(leveltype << 1));
if (pnum != myplr) return;
InitDiabloMsg(SHRINE_5);
break;
case 5: // Stone
if (deltaload) return;
if (pnum == myplr) {
for (r = 0; r < NUM_INVLOC; ++r) {
if (plr[pnum].InvBody[r]._itype == IT_STAFF)
plr[pnum].InvBody[r]._iCharges = plr[pnum].InvBody[r]._iMaxCharges;
}
for (r = 0; r < plr[pnum]._pNumInv; ++r) {
if (plr[pnum].InvList[r]._itype == IT_STAFF)
plr[pnum].InvList[r]._iCharges = plr[pnum].InvList[r]._iMaxCharges;
}
for (r = 0; r < MAXSPD; ++r) {
if (plr[pnum].SpdList[r]._itype == IT_STAFF)
plr[pnum].SpdList[r]._iCharges = plr[pnum].SpdList[r]._iMaxCharges;
}
InitDiabloMsg(SHRINE_6);
}
break;
case 6: // Religious
if (deltaload) return;
if (pnum == myplr) {
for (r = 0; r < NUM_INVLOC; ++r) {
plr[pnum].InvBody[r]._iDurability = plr[pnum].InvBody[r]._iMaxDur;
}
for (r = 0; r < plr[pnum]._pNumInv; ++r) {
plr[pnum].InvList[r]._iDurability = plr[pnum].InvList[r]._iMaxDur;
}
for (r = 0; r < MAXSPD; ++r) {
plr[pnum].SpdList[r]._iDurability = plr[pnum].SpdList[r]._iMaxDur;
}
InitDiabloMsg(SHRINE_7);
}
break;
case 7: // Enchanted (Levels 1-8 Only)
if (deltaload) return;
if (pnum != myplr) return;
//Get memorized spell count
sc = 0;
lv = 1;
for (r = 1; r <= MAXSPELLS; ++r) {
if (plr[pnum]._pMemSpells & lv) ++sc;
lv = lv << 1;
}
//Only add and subtract if player has more than 1 spell memorized
if (sc > 1) {
//Add one to all memorized spell levels
lv = 1;
for (r = 1; r <= MAXSPELLS; ++r) {
if (plr[pnum]._pMemSpells & lv) {
if (plr[pnum]._pSplLvl[r] < SPELLCAP) {
++plr[pnum]._pSplLvl[r];
v1 = r;
}
}
lv = lv << 1;
}
//Subtract 2 from random memorized spell. We are actually subtracting
//1 since we added 1 above.
done = false;
while (!done) {
lv = 1;
r = random(0, MAXSPELLS);
lv = lv << r;
if (plr[pnum]._pMemSpells & lv) {
if (plr[pnum]._pSplLvl[r+1] >= 2) plr[pnum]._pSplLvl[r+1] -= 2;
else plr[pnum]._pSplLvl[r+1] = 0;
done = true;
break;
}
}
}
InitDiabloMsg(SHRINE_8);
break;
case 8: // Thaumaturgic (Single Player Only)
//All chests regenerate
for (r = 0; r < numobjects; ++r) {
v1 = objectactive[r];
app_assert((DWORD)v1 < MAXOBJECTS);
if (((object[v1]._otype == OBJ_CHEST1) ||
(object[v1]._otype == OBJ_CHEST2) ||
(object[v1]._otype == OBJ_CHEST3)) &&
(object[v1]._oSelFlag == OSEL_NONE)) {
object[v1]._oRndSeed = GetRndSeed();
object[v1]._oSelFlag = OSEL_FLR;
object[v1]._oAnimFrame -= 2;
}
}
if (deltaload) return;
if (pnum == myplr) InitDiabloMsg(SHRINE_9);
break;
case 9: // Fascinating
if (deltaload) return;
if (pnum != myplr) return;
//Give player fire bolt level +2
t = 1;
plr[pnum]._pMemSpells |= t << (SPL_FIREBOLT-1);
if (plr[pnum]._pSplLvl[SPL_FIREBOLT] < SPELLCAP) ++plr[pnum]._pSplLvl[SPL_FIREBOLT] ;
if (plr[pnum]._pSplLvl[SPL_FIREBOLT] < SPELLCAP) ++plr[pnum]._pSplLvl[SPL_FIREBOLT] ;
//Subtract 1/10 of mana
v1 = plr[pnum]._pMaxManaBase / 10;
v2 = plr[pnum]._pMana - plr[pnum]._pManaBase;
v3 = plr[pnum]._pMaxMana - plr[pnum]._pMaxManaBase;
plr[pnum]._pManaBase -= v1;
plr[pnum]._pMana -= v1;
plr[pnum]._pMaxMana -= v1;
plr[pnum]._pMaxManaBase -= v1;
if ((plr[pnum]._pMana >> MANA_SHIFT) <= 0) {
plr[pnum]._pMana = v2;
plr[pnum]._pManaBase = 0;
}
if ((plr[pnum]._pMaxMana >> MANA_SHIFT) <= 0) {
plr[pnum]._pMaxMana = v3;
plr[pnum]._pMaxManaBase = 0;
}
InitDiabloMsg(SHRINE_10);
break;
case 10: // Cryptic
if (deltaload) return;
//Cast nova
AddMissile(plr[pnum]._px, plr[pnum]._py, plr[pnum]._px, plr[pnum]._py,
plr[pnum]._pdir, MIT_NOVA, -1, pnum, 0, (leveltype << 1));
if (pnum != myplr) return;
//Give full mana
plr[pnum]._pMana = plr[pnum]._pMaxMana;
plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase;
InitDiabloMsg(SHRINE_11);
break;
case 12: // Eldritch
if (deltaload) return;
if (pnum == myplr) {
//All health and mana potions become full rejuv.
for (r = 0; r < plr[pnum]._pNumInv; ++r) {
if (plr[pnum].InvList[r]._itype == IT_MISC) {
if ((plr[pnum].InvList[r]._iMiscId == IMID_PLHEAL) ||
(plr[pnum].InvList[r]._iMiscId == IMID_PMANA)) {
idata = ItemMiscIdIdx(IMID_REJUV);
SetPlrHandItem(&plr[pnum].HoldItem, idata);
GetPlrHandSeed(&plr[pnum].HoldItem);
plr[pnum].HoldItem._iStatFlag = TRUE;
plr[pnum].InvList[r] = plr[pnum].HoldItem;
}
if ((plr[pnum].InvList[r]._iMiscId == IMID_PHEAL) ||
(plr[pnum].InvList[r]._iMiscId == IMID_PFMANA)) {
idata = ItemMiscIdIdx(IMID_FREJUV);
SetPlrHandItem(&plr[pnum].HoldItem, idata);
GetPlrHandSeed(&plr[pnum].HoldItem);
plr[pnum].HoldItem._iStatFlag = TRUE;
plr[pnum].InvList[r] = plr[pnum].HoldItem;
}
}
}
for (r = 0; r < MAXSPD; ++r) {
if (plr[pnum].SpdList[r]._itype == IT_MISC) {
if ((plr[pnum].SpdList[r]._iMiscId == IMID_PLHEAL) ||
(plr[pnum].SpdList[r]._iMiscId == IMID_PMANA)) {
idata = ItemMiscIdIdx(IMID_REJUV);
SetPlrHandItem(&plr[pnum].HoldItem, idata);
GetPlrHandSeed(&plr[pnum].HoldItem);
plr[pnum].HoldItem._iStatFlag = TRUE;
plr[pnum].SpdList[r] = plr[pnum].HoldItem;
}
if ((plr[pnum].SpdList[r]._iMiscId == IMID_PHEAL) ||
(plr[pnum].SpdList[r]._iMiscId == IMID_PFMANA)) {
idata = ItemMiscIdIdx(IMID_FREJUV);
SetPlrHandItem(&plr[pnum].HoldItem, idata);
GetPlrHandSeed(&plr[pnum].HoldItem);
plr[pnum].HoldItem._iStatFlag = TRUE;
plr[pnum].SpdList[r] = plr[pnum].HoldItem;
}
}
}
InitDiabloMsg(SHRINE_13);
}
break;
case 13: // Eerie
if (deltaload) return;
if (pnum != myplr) return;
//Add 2 to magic
ModifyPlrMag(pnum, 2);
CheckStats(pnum);
InitDiabloMsg(SHRINE_14);
break;
case 14: // Divine
if (deltaload) return;
if (pnum != myplr) return;
//Put this in because full rejuvs are only available from level 7 on.
if ((currlevel << 1) < 7) {
//Create 1 full heal and 1 full mana
CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, IT_MISC, IMID_PFMANA, FALSE, TRUE);
CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, IT_MISC, IMID_PHEAL, FALSE, TRUE);
} else {
//Create 2 full rejuv
CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, IT_MISC, IMID_FREJUV, FALSE, TRUE);
CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, IT_MISC, IMID_FREJUV, FALSE, TRUE);
}
//Give full mana and life
plr[pnum]._pMana = plr[pnum]._pMaxMana;
plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase;
plr[pnum]._pHitPoints = plr[pnum]._pMaxHP;
plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase;
InitDiabloMsg(SHRINE_15);
break;
case 15: // Holy
if (deltaload) return;
v4 = 0;
do {
v1 = random(159,DMAXX);
v2 = random(159,DMAXY);
v3 = dPiece[v1][v2];
++v4;
if (v4 > (DMAXX*DMAXY)) break;
} while (nSolidTable[v3] != 0 || dObject[v1][v2] != 0 || dMonster[v1][v2] != 0);
//Cast phase
AddMissile(plr[pnum]._px, plr[pnum]._py, v1, v2, plr[pnum]._pdir,
MIT_PHASE, -1, pnum, 0, (leveltype << 1));
if (pnum != myplr) return;
InitDiabloMsg(SHRINE_16);
break;
case 16: // Sacred
if (deltaload) return;
if (pnum != myplr) return;
//Give player charged bolt level +2
t = 1;
plr[pnum]._pMemSpells |= t << (SPL_CBOLT-1);
if (plr[pnum]._pSplLvl[SPL_CBOLT] < SPELLCAP) ++plr[pnum]._pSplLvl[SPL_CBOLT] ;
if (plr[pnum]._pSplLvl[SPL_CBOLT] < SPELLCAP) ++plr[pnum]._pSplLvl[SPL_CBOLT] ;
//Subtract 1/10 of mana
v1 = plr[pnum]._pMaxManaBase / 10;
v2 = plr[pnum]._pMana - plr[pnum]._pManaBase;
v3 = plr[pnum]._pMaxMana - plr[pnum]._pMaxManaBase;
plr[pnum]._pManaBase -= v1;
plr[pnum]._pMana -= v1;
plr[pnum]._pMaxMana -= v1;
plr[pnum]._pMaxManaBase -= v1;
if ((plr[pnum]._pMana >> MANA_SHIFT) <= 0) {
plr[pnum]._pMana = v2;
plr[pnum]._pManaBase = 0;
}
if ((plr[pnum]._pMaxMana >> MANA_SHIFT) <= 0) {
plr[pnum]._pMaxMana = v3;
plr[pnum]._pMaxManaBase = 0;
}
InitDiabloMsg(SHRINE_17);
break;
case 17: // Spiritual
if (deltaload) return;
if (pnum != myplr) return;
//Fill inventory with gold
for (r = 0; r < MAXINV; ++r) {
if (plr[pnum].InvGrid[r] == 0) {
v2 = (leveltype * 5) + random(160,leveltype * 10);
v1 = plr[pnum]._pNumInv;
plr[pnum].InvList[v1] = golditem;
plr[pnum].InvList[v1]._iSeed = GetRndSeed();
++plr[pnum]._pNumInv;
plr[pnum].InvGrid[r] = plr[pnum]._pNumInv;
plr[pnum].InvList[v1]._ivalue = v2;
plr[pnum]._pGold += v2;
SetGoldCurs(pnum, v1);
}
}
InitDiabloMsg(SHRINE_18);
break;
case 18: // Spooky (Multi Player Only)
if (deltaload) return;
if (pnum == myplr) InitDiabloMsg(SHRINE_19);
else {
//Full rejuv for other players
InitDiabloMsg(SHRINE_19B);
plr[myplr]._pHitPoints = plr[myplr]._pMaxHP;
plr[myplr]._pHPBase = plr[myplr]._pMaxHPBase;
plr[myplr]._pMana = plr[myplr]._pMaxMana;
plr[myplr]._pManaBase = plr[myplr]._pMaxManaBase;
}
break;
case 19: // Abandoned
if (deltaload) return;
if (pnum != myplr) return;
//Add 2 to dexterity
ModifyPlrDex(pnum, 2);
CheckStats(pnum);
if (pnum == myplr) InitDiabloMsg(SHRINE_20);
break;
case 20: // Creepy
if (deltaload) return;
if (pnum != myplr) return;
//Add 2 to strength
ModifyPlrStr(pnum, 2);
CheckStats(pnum);
if (pnum == myplr) InitDiabloMsg(SHRINE_21);
break;
case 21: // Quiet
if (deltaload) return;
if (pnum != myplr) return;
//Add 2 to vitality
ModifyPlrVit(pnum, 2);
CheckStats(pnum);
if (pnum == myplr) InitDiabloMsg(SHRINE_22);
break;
case 22: // Secluded
if (deltaload) return;
if (pnum == myplr) {
//Complete automap for current level
for (yy = 0; yy < AUTOMAPY; ++yy) {
for (xx = 0; xx < AUTOMAPX; ++xx) automapview[xx][yy] = TRUE;
}
InitDiabloMsg(SHRINE_23);
}
break;
case 23: // Ornate
if (deltaload) return;
if (pnum != myplr) return;
//Give player holy bolt level +2
t = 1;
plr[pnum]._pMemSpells |= t << (SPL_HBOLT-1);
if (plr[pnum]._pSplLvl[SPL_HBOLT] < SPELLCAP) ++plr[pnum]._pSplLvl[SPL_HBOLT] ;
if (plr[pnum]._pSplLvl[SPL_HBOLT] < SPELLCAP) ++plr[pnum]._pSplLvl[SPL_HBOLT] ;
//Subtract 1/10 of mana
v1 = plr[pnum]._pMaxManaBase / 10;
v2 = plr[pnum]._pMana - plr[pnum]._pManaBase;
v3 = plr[pnum]._pMaxMana - plr[pnum]._pMaxManaBase;
plr[pnum]._pManaBase -= v1;
plr[pnum]._pMana -= v1;
plr[pnum]._pMaxMana -= v1;
plr[pnum]._pMaxManaBase -= v1;
if ((plr[pnum]._pMana >> MANA_SHIFT) <= 0) {
plr[pnum]._pMana = v2;
plr[pnum]._pManaBase = 0;
}
if ((plr[pnum]._pMaxMana >> MANA_SHIFT) <= 0) {
plr[pnum]._pMaxMana = v3;
plr[pnum]._pMaxManaBase = 0;
}
InitDiabloMsg(SHRINE_24);
break;
case 24: // Glimmering
if (deltaload) return;
if (pnum != myplr) return;
//All items are identified
for (r = 0; r < NUM_INVLOC; ++r) {
if ((plr[pnum].InvBody[r]._iMagical != IMAGIC_NONE) && !plr[pnum].InvBody[r]._iIdentified)
plr[pnum].InvBody[r]._iIdentified = TRUE;
}
for (r = 0; r < plr[pnum]._pNumInv; ++r) {
if ((plr[pnum].InvList[r]._iMagical != IMAGIC_NONE) && !plr[pnum].InvList[r]._iIdentified)
plr[pnum].InvList[r]._iIdentified = TRUE;
}
for (r = 0; r < MAXSPD; ++r) {
if ((plr[pnum].SpdList[r]._iMagical != IMAGIC_NONE) && !plr[pnum].SpdList[r]._iIdentified)
plr[pnum].SpdList[r]._iIdentified = TRUE;
}
InitDiabloMsg(SHRINE_25);
break;
case 25: // Tainted (Multi Player Only)
if (deltaload) return;
if (pnum == myplr) InitDiabloMsg(SHRINE_26);
else {
//All other players get +1 to 3 random stats and -1 to other
InitDiabloMsg(SHRINE_26B);
r = random(155,4);
if (r == 0) v1 = 1;
else v1 = -1;
if (r == 1) v2 = 1;
else v2 = -1;
if (r == 2) v3 = 1;
else v3 = -1;
if (r == 3) v4 = 1;
else v4 = -1;
ModifyPlrStr(myplr, v1);
ModifyPlrMag(myplr, v2);
ModifyPlrDex(myplr, v3);
ModifyPlrVit(myplr, v4);
CheckStats(myplr);
}
break;
case 26: // Oily
// Increase good stats by 1.
if (deltaload) return;
if (pnum != myplr) return;
InitDiabloMsg(SHRINE_27);
switch(plr[myplr]._pClass)
{
case CLASS_SORCEROR:
ModifyPlrMag(myplr,2);
break;
case CLASS_ROGUE:
ModifyPlrDex(myplr,2);
break;
case CLASS_WARRIOR:
ModifyPlrStr(myplr,2);
break;
case CLASS_BARBARIAN:
ModifyPlrVit(myplr,2);
break;
case CLASS_MONK:
ModifyPlrStr(myplr,1);
ModifyPlrDex(myplr,1);
break;
case CLASS_BARD:
ModifyPlrDex(myplr,1);
ModifyPlrMag(myplr,1);
break;
}
CheckStats(pnum);
AddMissile(object[i]._ox, object[i]._oy, plr[myplr]._px, plr[myplr]._py, plr[myplr]._pdir, MIT_FIREWALL, MI_ENEMYPLR, 0, 2 + (2 * currlevel), 0);
break;
case 27: // Glowing
{
if (deltaload) return;
if (pnum != myplr) return;
InitDiabloMsg(SHRINE_28);
long CurrentExp = plr[myplr]._pExperience;
long ModMagic;
if (CurrentExp > 5000)
{
ModMagic = 5;
CurrentExp = (long)(CurrentExp * 0.95);
}
else
{
ModMagic = CurrentExp/1000;
CurrentExp = 0;
}
ModifyPlrMag(myplr, ModMagic);
plr[myplr]._pExperience = CurrentExp;
CheckStats(pnum);
}
break;
case 28: // Mendicant's
{
if (deltaload) return;
if (pnum != myplr) return;
InitDiabloMsg(SHRINE_29);
long const HalfCurrentGold = plr[myplr]._pGold / 2;
AddPlrExperience(myplr, plr[myplr]._pLevel, HalfCurrentGold);
TakePlrsMoney(HalfCurrentGold); // uses global var myplr.
CheckStats(pnum);
}
break;
case 29: // Sparkling
if (deltaload) return;
if (pnum != myplr) return;
InitDiabloMsg(SHRINE_30);
AddPlrExperience(myplr, plr[myplr]._pLevel, 1000 * currlevel);
AddMissile(object[i]._ox, object[i]._oy, plr[myplr]._px, plr[myplr]._py, plr[myplr]._pdir, MIT_FLASH, MI_ENEMYPLR, 0, 2 + (3 * currlevel), 0);
CheckStats(pnum);
break;
case 30: // Town
if (deltaload) return;
if (pnum != myplr) return;
InitDiabloMsg(SHRINE_31);
AddMissile(object[i]._ox, object[i]._oy, plr[myplr]._px, plr[myplr]._py, plr[myplr]._pdir, MIT_TOWN, MI_ENEMYPLR, 0, 0, 0);
break;
case 31: // Shimmering
if (deltaload) return;
if (pnum != myplr) return;
InitDiabloMsg(SHRINE_32);
plr[pnum]._pMana = plr[pnum]._pMaxMana; // restore to full mana.
plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase;
break;
case 32: // Solar
{
if (deltaload) return;
if (pnum != myplr) return;
time_t time_of_day = time(0);
struct tm * const tmbuf = localtime(&time_of_day);
if (tmbuf->tm_hour > 20 || tmbuf->tm_hour < 4)
{
InitDiabloMsg(SHRINE_33D);
ModifyPlrVit(myplr, 2);
}
else if (tmbuf->tm_hour > 18)
{
InitDiabloMsg(SHRINE_33C);
ModifyPlrMag(myplr, 2);
}
else if (tmbuf->tm_hour > 12)
{
InitDiabloMsg(SHRINE_33B);
ModifyPlrStr(myplr, 2);
}
else if (tmbuf->tm_hour > 4)
{
InitDiabloMsg(SHRINE_33A);
ModifyPlrDex(myplr, 2);
}
CheckStats(pnum);
}
break;
case 33: // Murphy's
{
if (deltaload) return;
if (pnum != myplr) return;
InitDiabloMsg(SHRINE_34);
long i;
long broken = 0;
for (i = 0; i < 7; ++i)
{
ItemStruct * const itm = &plr[myplr].InvBody[i];
if (itm->_itype == -1) continue;
if (random(0,3) == 0
&& itm->_iDurability != INFINITE_DUR
&& itm->_iDurability != 0) // There are two values for infinite durablity !!!
{
// Randomly break something.
itm->_iDurability /= 2;
broken = 1;
break;
}
}
if (!broken)
{
long const ThirdCurrentGold = plr[myplr]._pGold / 3;
TakePlrsMoney(ThirdCurrentGold); // uses global var myplr.
}
}
break;
}
CalcPlrInv(pnum, TRUE);
force_redraw = FULLDRAW;
if (pnum == myplr) NetSendCmdParam2(FALSE,CMD_PLROPOBJ,pnum,i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateSkelBook(int pnum, int i, bool sendmsg)
{
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
if (!deltaload) PlaySfxLoc(IS_ISCROL, object[i]._ox, object[i]._oy);
object[i]._oSelFlag = OSEL_NONE;
object[i]._oAnimFrame += 2;
if (deltaload) return;
SetRndSeed(object[i]._oRndSeed);
if (random(161,5)) CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, IT_MISC, IMID_SCROLL, sendmsg, FALSE);
else CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, IT_MISC, IMID_BOOK, sendmsg, FALSE);
if (pnum == myplr) NetSendCmdParam1(FALSE,CMD_OPERATEOBJ,i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateBookCase(int pnum, int i, bool sendmsg)
{
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
if (!deltaload) PlaySfxLoc(IS_ISCROL, object[i]._ox, object[i]._oy);
object[i]._oSelFlag = OSEL_NONE;
object[i]._oAnimFrame -= 2;
if (deltaload) return;
SetRndSeed(object[i]._oRndSeed);
CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, IT_MISC, IMID_BOOK, sendmsg, FALSE);
if (QuestStatus(Q_ZHAR)) {
if (monster[4].mName == UniqMonst[MU_ZHAR].mName) {
if ((monster[4]._msquelch == 255) && (monster[4]._mhitpoints != 0)) {
monster[4].mtalkmsg = TXT_ZHAR2;
M_StartStand(0, monster[4]._mdir);
monster[4]._mgoal = MG_ATTACK2;
monster[4]._mmode = MM_TALK;
}
}
}
if (pnum == myplr) NetSendCmdParam1(FALSE,CMD_OPERATEOBJ,i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateDecap(int pnum, int i, bool sendmsg)
{
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
object[i]._oSelFlag = OSEL_NONE;
if (deltaload) return;
SetRndSeed(object[i]._oRndSeed);
CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE);
if (pnum == myplr) NetSendCmdParam1(FALSE,CMD_OPERATEOBJ,i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateArmorStand(int pnum, int i, bool sendmsg)
{
int uniqueRnd;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
object[i]._oSelFlag = OSEL_NONE;
++object[i]._oAnimFrame;
if (deltaload) return;
SetRndSeed(object[i]._oRndSeed);
//Randomize uniqueness
uniqueRnd = random(0, 2);
//Create an appropriate armor for the current level
if (currlevel <= 5) {
//Create unique only IT_ARMOR
CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, IT_ARMOR, IMID_NONE, sendmsg, FALSE);
} else if (currlevel >= 6 && currlevel <= 9) {
//Create random unique IT_MARMOR
CreateTypeItem(object[i]._ox, object[i]._oy, uniqueRnd, IT_MARMOR, IMID_NONE, sendmsg, FALSE);
} else if (currlevel >= 10 && currlevel <= 12) {
//Create non-unique IT_HARMOR
CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, IT_HARMOR, IMID_NONE, sendmsg, FALSE);
} else if (currlevel >= 13 && currlevel <= 16) {
//Create unique IT_HARMOR
CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, IT_HARMOR, IMID_NONE, sendmsg, FALSE);
} else if (currlevel >= 17) {
//Use the uniques for now, but we will add our own specifics JKE 7/30
CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, IT_HARMOR, IMID_NONE, sendmsg, FALSE);
}
if (pnum == myplr) NetSendCmdParam1(FALSE,CMD_OPERATEOBJ,i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static int FindValidShrine(int i)
/*-----------------------------------------------------------------------*
** Description: Used by OperateGoatShrine and OperateCauldron to find a
** usable shrine function.
** Input: i = Object index
** Return: Shrine function index.
**-----------------------------------------------------------------------*/
{
int rv;
bool done = false;
//Search until we find a valid shrine type. Ignore Thaumaturgic shrine
//because it could possibly screw up the animation.
do {
rv = random(0, NUMSHRINETYPES);
if ((currlevel >= shrineminlvl[rv]) &&
(currlevel <= shrinemaxlvl[rv]) &&
(rv != 8)) {
done = true;
}
if (done) {
if ((gbMaxPlayers != 1) && (shrineavail[rv] == SHRINE_SINGLE)) {
done = FALSE;
} else if ((gbMaxPlayers == 1) && (shrineavail[rv] == SHRINE_MULTI)) {
done = FALSE;
} else done = TRUE; //We found a shrine type we can use.
}
} while (!done);
return rv;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateGoatShrine(int pnum, int i, int sType)
{
app_assert((DWORD)i < MAXOBJECTS);
SetRndSeed(object[i]._oRndSeed);
object[i]._oVar1 = FindValidShrine(i);
OperateShrine(pnum, i, sType);
object[i]._oAnimDelay = 2;
force_redraw = FULLDRAW;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateCauldron(int pnum, int i, int sType)
{
app_assert((DWORD)i < MAXOBJECTS);
SetRndSeed(object[i]._oRndSeed);
object[i]._oVar1 = FindValidShrine(i);
OperateShrine(pnum, i, sType);
object[i]._oAnimFrame = 3;
object[i]._oAnimFlag = FALSE;
force_redraw = FULLDRAW;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static bool OperateFountains(int pnum, int i)
{
int ii;
bool rv = false;
app_assert((DWORD)i < MAXOBJECTS);
SetRndSeed(object[i]._oRndSeed);
switch(object[i]._otype) {
case OBJ_PURIFYINGFTN:
if (deltaload) return rv;
if (pnum != myplr) return rv;
if (plr[pnum]._pMana < plr[pnum]._pMaxMana) {
PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy);
//Add 1 Mana point
plr[pnum]._pMana += (1 << MANA_SHIFT);
plr[pnum]._pManaBase += (1 << MANA_SHIFT);
if (plr[pnum]._pMana > plr[pnum]._pMaxMana) {
plr[pnum]._pMana = plr[pnum]._pMaxMana;
plr[pnum]._pManaBase = plr[pnum]._pMaxManaBase;
}
rv = true;
} else if (!deltaload) PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy);
break;
case OBJ_BLOODFTN:
if (deltaload) return rv;
if (pnum != myplr) return rv;
if (plr[pnum]._pHitPoints < plr[pnum]._pMaxHP) {
PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy);
//Add 1 HP point
plr[pnum]._pHitPoints += (1 << HP_SHIFT);
plr[pnum]._pHPBase += (1 << HP_SHIFT);
if (plr[pnum]._pHitPoints > plr[pnum]._pMaxHP) {
plr[pnum]._pHitPoints = plr[pnum]._pMaxHP;
plr[pnum]._pHPBase = plr[pnum]._pMaxHPBase;
}
rv = true;
} else if (!deltaload) PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy);
break;
case OBJ_MURKYFTN:
if (object[i]._oSelFlag != OSEL_NONE) {
if (!deltaload) PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy);
object[i]._oSelFlag = OSEL_NONE;
if (deltaload) return rv;
//Casts infravision
AddMissile(plr[pnum]._px, plr[pnum]._py, plr[pnum]._px, plr[pnum]._py,
plr[pnum]._pdir, MIT_INFRA, -1, pnum, 0,
(leveltype << 1));
rv = true;
if (pnum == myplr) NetSendCmdParam1(FALSE,CMD_OPERATEOBJ,i);
}
break;
case OBJ_TEARFTN:
if (object[i]._oSelFlag != OSEL_NONE) {
int rndVal;
int statVal = -1;
int saveRnd = -1;
int status = FALSE;
ii = 0;
if (!deltaload) PlaySfxLoc(LS_FOUNTAIN, object[i]._ox, object[i]._oy);
object[i]._oSelFlag = OSEL_NONE;
if (deltaload) return rv;
if (pnum != myplr) return rv;
//-1 to random stat, +1 to another
do {
if ((rndVal = random(0, 4)) != saveRnd) {
switch(rndVal) {
case 0:
ModifyPlrStr(pnum, statVal);
break;
case 1:
ModifyPlrMag(pnum, statVal);
break;
case 2:
ModifyPlrDex(pnum, statVal);
break;
case 3:
ModifyPlrVit(pnum, statVal);
break;
}
saveRnd = rndVal;
statVal = 1;
++ii;
}
if (ii > 1) status = TRUE;
} while(!status);
CheckStats(pnum);
rv = true;
if (pnum == myplr) NetSendCmdParam1(FALSE,CMD_OPERATEOBJ,i);
}
break;
}
force_redraw = FULLDRAW;
return rv;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateWeaponRack(int pnum, int i, bool sendmsg)
{
int weaponType, sfxType;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
SetRndSeed(object[i]._oRndSeed);
//Choose random weapon/sfx type
switch((random(0, 4)+1)) {
case 1:
weaponType = IT_SWORD;
sfxType = IS_FSWOR;
break;
case 2:
weaponType = IT_AXE;
sfxType = IS_FAXE;
break;
case 3:
weaponType = IT_BOW;
sfxType = IS_FBOW;
break;
case 4:
weaponType = IT_MACE;
sfxType = IS_FAXE;
break;
}
object[i]._oSelFlag = OSEL_NONE;
++object[i]._oAnimFrame;
if (deltaload) return;
//Create a random weapon. Create unique weapons from level 4 down.
if (leveltype > 1) CreateTypeItem(object[i]._ox, object[i]._oy, TRUE, weaponType, IMID_NONE, sendmsg, FALSE);
else CreateTypeItem(object[i]._ox, object[i]._oy, FALSE, weaponType, IMID_NONE, sendmsg, FALSE);
if (pnum == myplr) NetSendCmdParam1(FALSE,CMD_OPERATEOBJ,i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateStoryBook(int pnum, int i)
{
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
if (deltaload) return;
if (qtextflag) return;
if (pnum != myplr) return;
object[i]._oAnimFrame = object[i]._oVar4;
PlaySfxLoc(IS_ISCROL, object[i]._ox, object[i]._oy);
if ((object[i]._oVar8 != 0) && (currlevel == NA_KRUL_LEVEL))
{
if ((Na_Krul.Lever_Thrown != TRUE) && (quests[Q_NA_KRUL]._qactive != QUEST_DONE))
if(HCheckSpell(object[i]._oVar8))
{
NetSendCmd(FALSE,CMD_OPEN_NAKRUL);
return;
}
}
else if (currlevel >= CRYPTSTART)
{
quests[Q_NA_KRUL]._qactive = QUEST_NOTDONE;
quests[Q_NA_KRUL]._qlog = TRUE;
quests[Q_NA_KRUL]._qmsg = object[i]._oVar2;
}
InitQTextMsg(object[i]._oVar2);
NetSendCmdParam1(FALSE,CMD_OPERATEOBJ,i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void OperateLazStand(int pnum, int i)
{
int x, y;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return;
if (deltaload) return;
if (qtextflag) return;
if (pnum != myplr) return;
++object[i]._oAnimFrame;
object[i]._oSelFlag = OSEL_NONE;
GetSuperItemLoc(object[i]._ox, object[i]._oy, x, y);
SpawnQuestItem(IDI_LAZSTAFF, x, y, 0, ISEL_NONE);
//quests[Q_BKMUSHRM]._qvar1 = QS_MUSHSPAWNED;
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void OperateObject(int pnum, int i, BOOL TeleFlag)
{
bool senditemmsg;
if (pnum == myplr) senditemmsg = true;
else senditemmsg = false;
app_assert((DWORD)i < MAXOBJECTS);
switch (object[i]._otype) {
case OBJ_L1DOORL :
case OBJ_L1DOORR :
if (TeleFlag) {
if (object[i]._otype == OBJ_L1DOORL) OperateL1LDoor(pnum, i, true);
if (object[i]._otype == OBJ_L1DOORR) OperateL1RDoor(pnum, i, true);
} else {
if (pnum == myplr) OperateL1Door(pnum, i, TRUE);
}
break;
case OBJ_L2DOORL :
case OBJ_L2DOORR :
if (TeleFlag) {
if (object[i]._otype == OBJ_L2DOORL) OperateL2LDoor(pnum, i, true);
if (object[i]._otype == OBJ_L2DOORR) OperateL2RDoor(pnum, i, true);
} else {
if (pnum == myplr) OperateL2Door(pnum, i, TRUE);
}
break;
case OBJ_L3DOORL :
case OBJ_L3DOORR :
if (TeleFlag) {
if (object[i]._otype == OBJ_L3DOORL) OperateL3LDoor(pnum, i, true);
if (object[i]._otype == OBJ_L3DOORR) OperateL3RDoor(pnum, i, true);
} else {
if (pnum == myplr) OperateL3Door(pnum, i, TRUE);
}
break;
case OBJ_SWITCHSKL:
case OBJ_LEVER :
OperateLever(pnum, i);
break;
case OBJ_BOOK2L:
OperateBook(pnum, i);
break;
case OBJ_BOOK2R:
OperateSChambBk(pnum, i);
break;
case OBJ_CHEST1:
case OBJ_CHEST2:
case OBJ_CHEST3:
case OBJ_TCHEST1:
case OBJ_TCHEST2:
case OBJ_TCHEST3:
OperateChest(pnum, i, senditemmsg);
break;
case OBJ_SARC:
OperateSarc(pnum, i, senditemmsg);
break;
case OBJ_FLAMELVR:
OperateTrapLvr(i);
break;
// case OBJ_BOOKLVR:
case OBJ_BLINDBOOK:
case OBJ_BLOODBOOK:
case OBJ_STEELTOME:
OperateBookLever(pnum, i);
break;
case OBJ_SHRINEL:
case OBJ_SHRINER:
OperateShrine(pnum, i, IS_MAGIC);
break;
case OBJ_SKELBOOK:
case OBJ_BOOKSTAND:
OperateSkelBook(pnum, i, senditemmsg);
break;
case OBJ_BOOKCASEL:
case OBJ_BOOKCASER:
OperateBookCase(pnum, i, senditemmsg);
break;
case OBJ_DECAP:
OperateDecap(pnum, i, senditemmsg);
break;
case OBJ_ARMORSTAND:
case OBJ_WARARMOR:
OperateArmorStand(pnum, i, senditemmsg);
break;
case OBJ_GOATSHRINE:
OperateGoatShrine(pnum, i, LS_GSHRINE);
break;
case OBJ_CAULDRON:
OperateCauldron(pnum, i, LS_CALDRON);
break;
case OBJ_MURKYFTN:
case OBJ_TEARFTN:
case OBJ_BLOODFTN:
case OBJ_PURIFYINGFTN:
OperateFountains(pnum, i);
break;
case OBJ_STORYBOOK:
OperateStoryBook(pnum, i);
break;
case OBJ_PEDISTAL:
OperatePedistal(pnum, i);
break;
case OBJ_WARWEAP:
case OBJ_WEAPONRACK:
OperateWeaponRack(pnum, i, senditemmsg);
break;
case OBJ_MUSHPATCH:
OperateMushPatch(pnum, i);
break;
case OBJ_LAZSTAND:
OperateLazStand(pnum, i);
break;
case OBJ_SLAINHERO:
OperateSlainHero(pnum, i, senditemmsg);
break;
case OBJ_SIGNCHEST:
OperateInnSignChest(pnum, i);
break;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void SyncOpL1Door(int pnum, int cmd, int i)
{
if (pnum == myplr) return;
bool opok = false;
app_assert((DWORD)i < MAXOBJECTS);
if ((cmd == CMD_OPENDOOR) && (object[i]._oVar4 == DOOR_CLOSED)) opok = TRUE;
if ((cmd == CMD_CLOSEDOOR) && (object[i]._oVar4 == DOOR_OPEN)) opok = TRUE;
if (opok) {
if (object[i]._otype == OBJ_L1DOORL) OperateL1LDoor(-1, i, false);
if (object[i]._otype == OBJ_L1DOORR) OperateL1RDoor(-1, i, false);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void SyncOpL2Door(int pnum, int cmd, int i)
{
if (pnum == myplr) return;
bool opok = false;
app_assert((DWORD)i < MAXOBJECTS);
if ((cmd == CMD_OPENDOOR) && (object[i]._oVar4 == DOOR_CLOSED)) opok = true;
if ((cmd == CMD_CLOSEDOOR) && (object[i]._oVar4 == DOOR_OPEN)) opok = true;
if (opok) {
if (object[i]._otype == OBJ_L2DOORL) OperateL2LDoor(-1, i, false);
if (object[i]._otype == OBJ_L2DOORR) OperateL2RDoor(-1, i, false);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void SyncOpL3Door(int pnum, int cmd, int i)
{
if (pnum == myplr) return;
bool opok = false;
app_assert((DWORD)i < MAXOBJECTS);
if ((cmd == CMD_OPENDOOR) && (object[i]._oVar4 == DOOR_CLOSED)) opok = true;
if ((cmd == CMD_CLOSEDOOR) && (object[i]._oVar4 == DOOR_OPEN)) opok = true;
if (opok) {
if (object[i]._otype == OBJ_L3DOORL) OperateL3LDoor(-1, i, false);
if (object[i]._otype == OBJ_L3DOORR) OperateL3RDoor(-1, i, false);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void SyncOpObject(int pnum, int cmd, int i)
{
app_assert((DWORD)i < MAXOBJECTS);
switch (object[i]._otype) {
case OBJ_L1DOORL :
case OBJ_L1DOORR :
SyncOpL1Door(pnum, cmd, i);
break;
case OBJ_L2DOORL :
case OBJ_L2DOORR :
SyncOpL2Door(pnum, cmd, i);
break;
case OBJ_L3DOORL :
case OBJ_L3DOORR :
SyncOpL3Door(pnum, cmd, i);
break;
case OBJ_SWITCHSKL:
case OBJ_LEVER :
OperateLever(pnum, i);
break;
case OBJ_CHEST1:
case OBJ_CHEST2:
case OBJ_CHEST3:
case OBJ_TCHEST1:
case OBJ_TCHEST2:
case OBJ_TCHEST3:
OperateChest(pnum, i, FALSE);
break;
case OBJ_SARC:
OperateSarc(pnum, i, FALSE);
break;
// case OBJ_BOOKLVR:
case OBJ_BLINDBOOK:
case OBJ_BLOODBOOK:
case OBJ_STEELTOME:
OperateBookLever(pnum, i);
break;
case OBJ_SHRINEL:
case OBJ_SHRINER:
OperateShrine(pnum, i, IS_MAGIC);
break;
case OBJ_SKELBOOK:
case OBJ_BOOKSTAND:
OperateSkelBook(pnum, i, FALSE);
break;
case OBJ_BOOKCASEL:
case OBJ_BOOKCASER:
OperateBookCase(pnum, i, FALSE);
break;
case OBJ_DECAP:
OperateDecap(pnum, i, FALSE);
break;
case OBJ_ARMORSTAND:
case OBJ_WARARMOR:
OperateArmorStand(pnum, i, FALSE);
break;
case OBJ_GOATSHRINE:
OperateGoatShrine(pnum, i, LS_GSHRINE);
break;
case OBJ_CAULDRON:
OperateCauldron(pnum, i, LS_CALDRON);
break;
case OBJ_MURKYFTN:
case OBJ_TEARFTN:
OperateFountains(pnum, i);
break;
case OBJ_STORYBOOK:
OperateStoryBook(pnum, i);
break;
case OBJ_PEDISTAL:
OperatePedistal(pnum, i);
break;
case OBJ_WARWEAP:
case OBJ_WEAPONRACK:
OperateWeaponRack(pnum, i, FALSE);
break;
case OBJ_MUSHPATCH:
OperateMushPatch(pnum, i);
break;
case OBJ_SLAINHERO:
OperateSlainHero(pnum, i, FALSE);
break;
case OBJ_SIGNCHEST:
OperateInnSignChest(pnum, i);
break;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void BreakCrux(int i)
{
int j, ot, oi;
bool mapflag;
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oAnimFlag = TRUE;
object[i]._oAnimFrame = 1;
object[i]._oAnimDelay = 1;
object[i]._oSolidFlag = TRUE;
object[i]._oMissFlag = TRUE;
object[i]._oBreak = OBJ_BROKEN;
object[i]._oSelFlag = OSEL_NONE;
mapflag = true;
for (j = 0; j < numobjects; ++j) {
oi = objectactive[j];
ot = object[oi]._otype;
if ((ot == OBJ_CRUX1) || (ot == OBJ_CRUX2) || (ot == OBJ_CRUX3)) {
if (object[i]._oVar8 == object[oi]._oVar8) {
if (object[oi]._oBreak != OBJ_BROKEN) mapflag = false;
}
}
}
if (mapflag) {
if (!deltaload) PlaySfxLoc(IS_LEVER, object[i]._ox, object[i]._oy);
ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
// DKT971012: Gary has items.cpp checked out; this should go there
void RndUnique(int x, int y, int level)
{
int uil[MAXUITEMS];
int i, numui = 0;
for (i=UID_LGTFORGE+1; i < MAXUITEMS && UniqueItemList[i].UIItemId != -1; ++i)
{
if (level*2 >= UniqueItemList[i].UIMinLvl)
uil[numui++] = i;
}
if (numui > 0)
{
int uitem = uil[random(0, numui)];
SpawnUnique(uitem, x, y);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void BreakBarrel(int pnum, int i, int dam, BOOL forcebreak, BOOL sendmsg)
{
int x, y, oi;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) return; // already broken?
if (forcebreak) {
object[i]._oVar1 = 0; // force it to bust open
} else {
object[i]._oVar1 -= dam; // normal damage
// if someone else is breaking the object, and it wasn't a force break
// message, then it hasn't broken yet.
if ((pnum != myplr) && (object[i]._oVar1 <= 0)) object[i]._oVar1 = 1;
}
if (object[i]._oVar1 > 0) {
if (!deltaload) PlaySfxLoc(IS_IBOW, object[i]._ox, object[i]._oy);
return;
}
object[i]._oVar1 = 0; // broken
object[i]._oAnimFlag = TRUE;
object[i]._oAnimFrame = 1;
object[i]._oAnimDelay = 1;
object[i]._oSolidFlag = FALSE;
object[i]._oMissFlag = TRUE;
object[i]._oBreak = OBJ_BROKEN;
object[i]._oSelFlag = OSEL_NONE;
object[i]._oPreFlag = TRUE;
if (deltaload) {
object[i]._oAnimFrame = object[i]._oAnimLen;
object[i]._oAnimCnt = 0;
object[i]._oAnimDelay = 1000;
return;
}
if (object[i]._otype == OBJ_BARRELEX) {
bool foo;
if (currlevel >= CRYPTSTART && currlevel <= CRYPTEND)
PlaySfxLoc(IS_URNFIRE, object[i]._ox, object[i]._oy);
else if (currlevel >= HIVESTART && currlevel <= HIVEEND)
PlaySfxLoc(IS_PODFIRE, object[i]._ox, object[i]._oy);
else
PlaySfxLoc(IS_BARLFIRE, object[i]._ox, object[i]._oy);
for (y = object[i]._oy-1; y <= object[i]._oy+1; ++y) {
for (x = object[i]._ox-1; x <= object[i]._ox+1; ++x) {
if (dMonster[x][y] > 0) MonsterTrapHit(dMonster[x][y]-1, 1, 4, 0, MIMT_FIRE, 0);
if (dPlayer[x][y] > 0) PlayerMHit(dPlayer[x][y]-1, -1, 0, 8, 16, MIMT_FIRE, 0, FALSE, &foo);
if (dObject[x][y] > 0) {
oi = dObject[x][y] - 1;
if ((object[oi]._otype == OBJ_BARRELEX) && (object[oi]._oBreak != OBJ_BROKEN))
BreakBarrel(pnum, oi, dam, TRUE, sendmsg);
}
}
}
} else {
if (currlevel >= CRYPTSTART && currlevel <= CRYPTEND)
PlaySfxLoc(IS_URN, object[i]._ox, object[i]._oy);
else if (currlevel >= HIVESTART && currlevel <= HIVEEND)
PlaySfxLoc(IS_POD, object[i]._ox, object[i]._oy);
else
PlaySfxLoc(IS_BARREL, object[i]._ox, object[i]._oy);
SetRndSeed(object[i]._oRndSeed);
#if CHEATS
if (uniqcheat)
RndUnique(object[i]._ox, object[i]._oy, currlevel);
else
#endif
if (object[i]._oVar2 <= 1) {
if (!object[i]._oVar3) CreateRndUseful(pnum, object[i]._ox, object[i]._oy, sendmsg);
else CreateRndItem(object[i]._ox, object[i]._oy, FALSE, sendmsg, FALSE);
}
if (object[i]._oVar2 >= 8) SpawnSkeleton(object[i]._oVar4, object[i]._ox, object[i]._oy);
}
if (pnum == myplr) NetSendCmdParam2(FALSE,CMD_BREAKOBJ,pnum,i);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void BreakObject(int pnum, int oi)
{
int objdam, mind, maxd;
if (pnum != -1) {
mind = plr[pnum]._pIMinDam;
maxd = plr[pnum]._pIMaxDam;
objdam = random(163,maxd - mind + 1) + mind;
objdam += (objdam * plr[pnum]._pIBonusDam) / 100;
objdam += plr[pnum]._pIBonusDamMod + plr[pnum]._pDamageMod;
} else objdam = 10;
app_assert((DWORD)oi < MAXOBJECTS);
switch (object[oi]._otype) {
case OBJ_CRUX1 :
case OBJ_CRUX2 :
case OBJ_CRUX3 :
BreakCrux(oi);
break;
case OBJ_BARREL:
case OBJ_BARRELEX:
BreakBarrel(pnum, oi, objdam, FALSE, TRUE);
break;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void SyncBreakObj(int pnum, int oi)
{
app_assert((DWORD)oi < MAXOBJECTS);
switch (object[oi]._otype) {
case OBJ_BARREL:
case OBJ_BARRELEX:
BreakBarrel(pnum, oi, 0, TRUE, FALSE);
break;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void SyncL1Doors(int i)
{
int dx, dy;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oVar4 == DOOR_CLOSED) {
object[i]._oMissFlag = FALSE;
return;
} else object[i]._oMissFlag = TRUE;
dx = object[i]._ox;
dy = object[i]._oy;
object[i]._oSelFlag = OSEL_TOP;
if (currlevel < HIVESTART)
{
if (object[i]._otype == OBJ_L1DOORL) {
if (object[i]._oVar1 == 214) ObjSetMicro(dx,dy,408); //Blood
else ObjSetMicro(dx,dy,393);
dSpecial[dx][dy] = 7;
ObjSetMicro12(dx-1,dy);
--dy;
} else {
ObjSetMicro(dx,dy,395);
if (currlevel < HIVESTART)
dSpecial[dx][dy] = 8;
ObjSetMicro12(dx,dy-1);
--dx;
}
}
else
{
if (object[i]._otype == OBJ_L1DOORL) {
ObjSetMicro(dx,dy,206);
dSpecial[dx][dy] = 1;
ObjSetMicro12(dx-1,dy);
--dy;
} else {
ObjSetMicro(dx,dy,209);
dSpecial[dx][dy] = 2;
ObjSetMicro12(dx,dy-1);
--dx;
}
}
DoorSet(i, dx, dy);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void SyncCrux(int i)
{
int j, ot, oi;
bool mapflag;
mapflag = TRUE;
for (j = 0; j < numobjects; ++j) {
oi = objectactive[j];
app_assert((DWORD)oi < MAXOBJECTS);
ot = object[oi]._otype;
if ((ot == OBJ_CRUX1) || (ot == OBJ_CRUX2) || (ot == OBJ_CRUX3)) {
if (object[i]._oVar8 == object[oi]._oVar8) {
if (object[oi]._oBreak != OBJ_BROKEN) mapflag = FALSE;
}
}
}
if (mapflag) ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void SyncLever(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oSelFlag == OSEL_NONE) {
ObjChangeMap(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void SyncQSTLever(int i)
{
int tren;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oAnimFrame == object[i]._oVar6) {
ObjChangeMapResync(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
if (object[i]._otype == OBJ_BLINDBOOK) {
tren = TransVal;
TransVal = 9;
DRLG_MRectTrans(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
TransVal = tren;
}
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void SyncPedistal(int i)
{
byte *setp;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oVar6 == 1) {
ObjChangeMapResync(setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7);
}
if (object[i]._oVar6 == 2) {
ObjChangeMapResync(setpc_x, setpc_y + 3, setpc_x + 2, setpc_y + 7);
ObjChangeMapResync(setpc_x + 6, setpc_y + 3, setpc_x + setpc_w, setpc_y + 7);
}
if (object[i]._oVar6 == 3) {
ObjChangeMapResync(object[i]._oVar1, object[i]._oVar2, object[i]._oVar3, object[i]._oVar4);
setp = LoadFileInMemSig("Levels\\L2Data\\Blood2.DUN", NULL, 'STPC');
LoadMapObjs(setp, (setpc_x << 1), (setpc_y << 1));
DiabloFreePtr(setp);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void SyncL2Doors(int i)
{
int dx, dy;
app_assert((DWORD)i < MAXOBJECTS);
if (object[i]._oVar4 == DOOR_CLOSED) object[i]._oMissFlag = FALSE;
else object[i]._oMissFlag = TRUE;
dx = object[i]._ox;
dy = object[i]._oy;
object[i]._oSelFlag = OSEL_TOP;
//Fix doors upon returning to level or loading level
if ((object[i]._otype == OBJ_L2DOORL) &&
(object[i]._oVar4 == DOOR_CLOSED)) {
ObjSetMicro(dx,dy,538);
} else if ((object[i]._otype == OBJ_L2DOORL) &&
((object[i]._oVar4 == DOOR_OPEN) ||
(object[i]._oVar4 == DOOR_BLOCKED))) {
ObjSetMicro(dx,dy,13);
} else if ((object[i]._otype == OBJ_L2DOORR) &&
(object[i]._oVar4 == DOOR_CLOSED)) {
ObjSetMicro(dx,dy,540);
} else if ((object[i]._otype == OBJ_L2DOORR) &&
((object[i]._oVar4 == DOOR_OPEN) ||
(object[i]._oVar4 == DOOR_BLOCKED))) {
ObjSetMicro(dx,dy,17);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
static void SyncL3Doors(int i)
{
int dx, dy;
app_assert((DWORD)i < MAXOBJECTS);
object[i]._oMissFlag = TRUE;
dx = object[i]._ox;
dy = object[i]._oy;
object[i]._oSelFlag = OSEL_TOP;
//Fix doors upon returning to level or loading level
if ((object[i]._otype == OBJ_L3DOORL) &&
(object[i]._oVar4 == DOOR_CLOSED)) {
ObjSetMicro(dx,dy,531);
} else if ((object[i]._otype == OBJ_L3DOORL) &&
((object[i]._oVar4 == DOOR_OPEN) ||
(object[i]._oVar4 == DOOR_BLOCKED))) {
ObjSetMicro(dx,dy,538);
} else if ((object[i]._otype == OBJ_L3DOORR) &&
(object[i]._oVar4 == DOOR_CLOSED)) {
ObjSetMicro(dx,dy,534);
} else if ((object[i]._otype == OBJ_L3DOORR) &&
((object[i]._oVar4 == DOOR_OPEN) ||
(object[i]._oVar4 == DOOR_BLOCKED))) {
ObjSetMicro(dx,dy,541);
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void SyncObjectAnim(int o)
{
int ai, ot, j;
app_assert((DWORD)o < MAXOBJECTS);
ot = object[o]._otype;
ai = AllObjects[ot].ofindex;
for (j = 0; ObjFileList[j] != ai; ++j);
object[o]._oAnimData = pObjCels[j];
switch (object[o]._otype) {
case OBJ_L1DOORL :
case OBJ_L1DOORR :
SyncL1Doors(o);
break;
case OBJ_L2DOORL :
case OBJ_L2DOORR :
SyncL2Doors(o);
break;
case OBJ_L3DOORL :
case OBJ_L3DOORR :
SyncL3Doors(o);
break;
case OBJ_CRUX1 :
case OBJ_CRUX2 :
case OBJ_CRUX3 :
SyncCrux(o);
break;
case OBJ_SWITCHSKL:
case OBJ_LEVER :
case OBJ_BOOK2L:
SyncLever(o);
break;
case OBJ_BLINDBOOK:
case OBJ_STEELTOME:
case OBJ_BOOK2R:
SyncQSTLever(o);
break;
case OBJ_PEDISTAL:
SyncPedistal(o);
break;
}
}
/*-----------------------------------------------------------------------*
**-----------------------------------------------------------------------*/
void GetObjectStr(int i)
{
app_assert((DWORD)i < MAXOBJECTS);
switch (object[i]._otype) {
case OBJ_CRUX1 :
case OBJ_CRUX2 :
case OBJ_CRUX3 :
strcpy(infostr, "Crucified Skeleton");
break;
case OBJ_LEVER :
case OBJ_FLAMELVR:
strcpy(infostr, "Lever");
break;
case OBJ_L1DOORL :
case OBJ_L1DOORR :
case OBJ_L2DOORL :
case OBJ_L2DOORR :
case OBJ_L3DOORL :
case OBJ_L3DOORR :
if (object[i]._oVar4 == DOOR_OPEN) strcpy(infostr, "Open Door");
if (object[i]._oVar4 == DOOR_CLOSED) strcpy(infostr, "Closed Door");
if (object[i]._oVar4 == DOOR_BLOCKED) strcpy(infostr, "Blocked Door");
break;
case OBJ_BOOK2L:
if (setlevel) {
if (setlvlnum == SL_BONECHAMB)
strcpy(infostr, "Ancient Tome");
else if (setlvlnum == SL_VILEBETRAYER)
strcpy(infostr, "Book of Vileness");
}
break;
case OBJ_SWITCHSKL:
strcpy(infostr, "Skull Lever");
break;
// case OBJ_BOOKLVR:
// strcpy(infostr, "Tome");
// break;
case OBJ_BOOK2R:
strcpy(infostr, "Mythical Book");
break;
case OBJ_CHEST1:
case OBJ_TCHEST1:
strcpy(infostr, "Small Chest");
break;
case OBJ_CHEST2:
case OBJ_TCHEST2:
strcpy(infostr, "Chest");
break;
case OBJ_CHEST3:
case OBJ_TCHEST3:
case OBJ_SIGNCHEST:
strcpy(infostr, "Large Chest");
break;
case OBJ_SARC:
strcpy(infostr, "Sarcophagus");
break;
case OBJ_BOOKSHELF:
strcpy(infostr, "Bookshelf");
break;
case OBJ_BOOKCASEL:
case OBJ_BOOKCASER:
strcpy(infostr, "Bookcase");
break;
case OBJ_BARREL:
case OBJ_BARRELEX:
if (currlevel >= HIVESTART && currlevel <= HIVEEND)
strcpy(infostr, "Pod");
else if (currlevel >= CRYPTSTART && currlevel <= CRYPTEND)
strcpy(infostr, "Urn");
else
strcpy(infostr, "Barrel");
break;
case OBJ_SHRINEL:
case OBJ_SHRINER:
sprintf(tempstr, "%s Shrine", shrinestrs[object[i]._oVar1]);
strcpy(infostr, tempstr);
break;
case OBJ_SKELBOOK:
strcpy(infostr, "Skeleton Tome");
break;
case OBJ_BOOKSTAND:
strcpy(infostr, "Library Book");
break;
case OBJ_BLOODFTN:
strcpy(infostr, "Blood Fountain");
break;
case OBJ_DECAP:
strcpy(infostr, "Decapitated Body");
break;
case OBJ_BLINDBOOK:
strcpy(infostr, "Book of the Blind");
break;
case OBJ_STEELTOME:
strcpy(infostr, "Steel Tome");
break;
case OBJ_BLOODBOOK:
strcpy(infostr, "Book of Blood");
break;
case OBJ_PURIFYINGFTN:
strcpy(infostr, "Purifying Spring");
break;
case OBJ_ARMORSTAND:
case OBJ_WARARMOR:
strcpy(infostr, "Armor");
break;
case OBJ_WARWEAP:
strcpy(infostr, "Weapon Rack");
break;
case OBJ_GOATSHRINE:
strcpy(infostr, "Goat Shrine");
break;
case OBJ_CAULDRON:
strcpy(infostr, "Cauldron");
break;
case OBJ_MURKYFTN:
strcpy(infostr, "Murky Pool");
break;
case OBJ_TEARFTN:
strcpy(infostr, "Fountain of Tears");
break;
case OBJ_PEDISTAL:
strcpy(infostr, "Pedestal of Blood");
break;
case OBJ_STORYBOOK:
strcpy(infostr, StoryBookName[object[i]._oVar3]);
break;
case OBJ_WEAPONRACK:
strcpy(infostr, "Weapon Rack");
break;
case OBJ_MUSHPATCH:
strcpy(infostr, "Mushroom Patch");
break;
case OBJ_LAZSTAND:
strcpy(infostr, "Vile Stand");
break;
case OBJ_SLAINHERO:
strcpy(infostr, "Slain Hero");
break;
}
if ((plr[myplr]._pClass == CLASS_ROGUE) && (object[i]._oTrapFlag)) {
sprintf(tempstr, "Trapped %s", infostr);
strcpy(infostr, tempstr);
infoclr = ICOLOR_RED;
}
}
static void SpellBook (int number, int locx, int locy)
{
AddSkulkenObject(OBJ_STORYBOOK, number, locx, locy);
}
static void AddNa_Krul_Stuff()
{
int spell;
AddNaKrulLeverObj();
spell = random(0, 6);
switch (spell)
{
case 0:
SpellBook(6, Na_Krul.x + 3, Na_Krul.y);
SpellBook(7, Na_Krul.x + 2, Na_Krul.y - 3);
SpellBook(8, Na_Krul.x + 2, Na_Krul.y + 2);
break;
case 1:
SpellBook(6, Na_Krul.x + 3, Na_Krul.y);
SpellBook(8, Na_Krul.x + 2, Na_Krul.y - 3);
SpellBook(7, Na_Krul.x + 2, Na_Krul.y + 2);
break;
case 2:
SpellBook(7, Na_Krul.x + 3, Na_Krul.y);
SpellBook(6, Na_Krul.x + 2, Na_Krul.y - 3);
SpellBook(8, Na_Krul.x + 2, Na_Krul.y + 2);
break;
case 3:
SpellBook(7, Na_Krul.x + 3, Na_Krul.y);
SpellBook(8, Na_Krul.x + 2, Na_Krul.y - 3);
SpellBook(6, Na_Krul.x + 2, Na_Krul.y + 2);
break;
case 4:
SpellBook(8, Na_Krul.x + 3, Na_Krul.y);
SpellBook(7, Na_Krul.x + 2, Na_Krul.y - 3);
SpellBook(6, Na_Krul.x + 2, Na_Krul.y + 2);
break;
case 5:
SpellBook(8, Na_Krul.x + 3, Na_Krul.y);
SpellBook(6, Na_Krul.x + 2, Na_Krul.y - 3);
SpellBook(7, Na_Krul.x + 2, Na_Krul.y + 2);
break;
}
}
static bool HCheckSpell(int number)
{
switch (number)
{
case 6:
SpellProgress = 1;
break;
case 7:
if (SpellProgress == 1)
SpellProgress = 2;
else
SpellProgress = 0;
break;
case 8:
if (SpellProgress == 2)
{
// qtextflag = FALSE;
// stream_stop();
return true;
}
else
SpellProgress = 0;
}
return false;
}
void OpenNaKrul()
{
if (currlevel == NA_KRUL_LEVEL)
{
PlaySfxLoc(CR_DOOROPEN, Na_Krul.x, Na_Krul.y);
dPiece[Na_Krul.x][Na_Krul.y] = 298;
dPiece[Na_Krul.x][Na_Krul.y - 1] = 301;
dPiece[Na_Krul.x][Na_Krul.y - 2] = 300;
dPiece[Na_Krul.x][Na_Krul.y + 1] = 299;
SetDungeonMicros();
}
}
void OpenNaKrul2()
{
dPiece[Na_Krul.x][Na_Krul.y] = 298;
dPiece[Na_Krul.x][Na_Krul.y - 1] = 301;
dPiece[Na_Krul.x][Na_Krul.y - 2] = 300;
dPiece[Na_Krul.x][Na_Krul.y + 1] = 299;
SetDungeonMicros();
}
static void AddNaKrulLeverObj()
{
int xp, yp;
while (1) {
xp = random(141,80) + DIRTEDGED2;
yp = random(141,80) + DIRTEDGED2;
if (! RndLocOk(xp-1, yp-1)) continue;
if (! RndLocOk(xp+0, yp-1)) continue;
if (! RndLocOk(xp+1, yp-1)) continue;
if (! RndLocOk(xp-1, yp+0)) continue;
if (! RndLocOk(xp+0, yp+0)) continue;
if (! RndLocOk(xp+1, yp+0)) continue;
if (! RndLocOk(xp-1, yp+1)) continue;
if (! RndLocOk(xp+0, yp+1)) continue;
if (! RndLocOk(xp+1, yp+1)) continue;
break;
}
// temp test
xp = Na_Krul.x + 3;
yp = Na_Krul.y - 1;
Na_Krul.LeverX = xp;
Na_Krul.LeverY = yp;
AddObject(OBJ_LEVER, xp, yp);
}