From 96637a25d15500b6a89fe689b3b5e0165bee5836 Mon Sep 17 00:00:00 2001 From: Christoph Oelckers Date: Fri, 2 Oct 2020 22:22:46 +0200 Subject: [PATCH] - importing Witchaven code from GDX This is a straight port of the GDX Java code to C++ with as few changes made as possible. Part 1: AI code. --- source/CMakeLists.txt | 1 + source/core/ns.h | 3 + source/games/whaven/CMakeLists.txt | 31 + source/games/whaven/src/ai.cpp | 1213 ++++++++++++++++++++++++ source/games/whaven/src/ai.h | 142 +++ source/games/whaven/src/aidemon.cpp | 231 +++++ source/games/whaven/src/aidevil.cpp | 280 ++++++ source/games/whaven/src/aidragon.cpp | 420 ++++++++ source/games/whaven/src/aifatwitch.cpp | 288 ++++++ source/games/whaven/src/aifish.cpp | 196 ++++ source/games/whaven/src/aifred.cpp | 332 +++++++ source/games/whaven/src/aigoblin.cpp | 581 ++++++++++++ source/games/whaven/src/aigonzo.cpp | 783 +++++++++++++++ source/games/whaven/src/aigron.cpp | 529 +++++++++++ source/games/whaven/src/aiguardian.cpp | 249 +++++ source/games/whaven/src/aiimp.cpp | 340 +++++++ source/games/whaven/src/aijudy.cpp | 423 +++++++++ source/games/whaven/src/aikatie.cpp | 284 ++++++ source/games/whaven/src/aikobold.cpp | 363 +++++++ source/games/whaven/src/aikurt.cpp | 103 ++ source/games/whaven/src/aiminotaur.cpp | 362 +++++++ source/games/whaven/src/ainewguy.cpp | 479 ++++++++++ source/games/whaven/src/airat.cpp | 111 +++ source/games/whaven/src/aiskeleton.cpp | 388 ++++++++ source/games/whaven/src/aiskully.cpp | 258 +++++ source/games/whaven/src/aispider.cpp | 322 +++++++ source/games/whaven/src/aiwillow.cpp | 291 ++++++ source/games/whaven/src/globals.h | 207 ++++ source/games/whaven/src/names.cpp | 501 ++++++++++ source/games/whaven/src/names.h | 388 ++++++++ source/games/whaven/src/player.h | 90 ++ source/games/whaven/src/wh.h | 17 + source/games/whaven/src/wh1names.h | 266 ++++++ source/games/whaven/src/wh2names.h | 389 ++++++++ 34 files changed, 10861 insertions(+) create mode 100644 source/games/whaven/CMakeLists.txt create mode 100644 source/games/whaven/src/ai.cpp create mode 100644 source/games/whaven/src/ai.h create mode 100644 source/games/whaven/src/aidemon.cpp create mode 100644 source/games/whaven/src/aidevil.cpp create mode 100644 source/games/whaven/src/aidragon.cpp create mode 100644 source/games/whaven/src/aifatwitch.cpp create mode 100644 source/games/whaven/src/aifish.cpp create mode 100644 source/games/whaven/src/aifred.cpp create mode 100644 source/games/whaven/src/aigoblin.cpp create mode 100644 source/games/whaven/src/aigonzo.cpp create mode 100644 source/games/whaven/src/aigron.cpp create mode 100644 source/games/whaven/src/aiguardian.cpp create mode 100644 source/games/whaven/src/aiimp.cpp create mode 100644 source/games/whaven/src/aijudy.cpp create mode 100644 source/games/whaven/src/aikatie.cpp create mode 100644 source/games/whaven/src/aikobold.cpp create mode 100644 source/games/whaven/src/aikurt.cpp create mode 100644 source/games/whaven/src/aiminotaur.cpp create mode 100644 source/games/whaven/src/ainewguy.cpp create mode 100644 source/games/whaven/src/airat.cpp create mode 100644 source/games/whaven/src/aiskeleton.cpp create mode 100644 source/games/whaven/src/aiskully.cpp create mode 100644 source/games/whaven/src/aispider.cpp create mode 100644 source/games/whaven/src/aiwillow.cpp create mode 100644 source/games/whaven/src/globals.h create mode 100644 source/games/whaven/src/names.cpp create mode 100644 source/games/whaven/src/names.h create mode 100644 source/games/whaven/src/player.h create mode 100644 source/games/whaven/src/wh.h create mode 100644 source/games/whaven/src/wh1names.h create mode 100644 source/games/whaven/src/wh2names.h diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index c7dcb5863..964a006ab 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1339,3 +1339,4 @@ add_subdirectory( games/duke ) add_subdirectory( blood ) add_subdirectory( sw ) add_subdirectory( exhumed ) +add_subdirectory( games/whaven ) diff --git a/source/core/ns.h b/source/core/ns.h index 82d397fd3..b03b19327 100644 --- a/source/core/ns.h +++ b/source/core/ns.h @@ -20,6 +20,9 @@ #define BEGIN_PS_NS namespace Exhumed { #define END_PS_NS } +#define BEGIN_WH_NS namespace Witchaven { +#define END_WH_NS } + #else #define BEGIN_EDUKE_NS diff --git a/source/games/whaven/CMakeLists.txt b/source/games/whaven/CMakeLists.txt new file mode 100644 index 000000000..90b0f9d23 --- /dev/null +++ b/source/games/whaven/CMakeLists.txt @@ -0,0 +1,31 @@ + +set( PCH_SOURCES + src/ai.cpp + src/aidemon.cpp + src/aidevil.cpp + src/aidragon.cpp + src/aifatwitch.cpp + src/aifish.cpp + src/aifred.cpp + src/aigoblin.cpp + src/aigonzo.cpp + src/aigron.cpp + src/aiguardian.cpp + src/aiimp.cpp + src/aijudy.cpp + src/aikatie.cpp + src/aikobold.cpp + src/aikurt.cpp + src/aiminotaur.cpp + src/ainewguy.cpp + src/airat.cpp + src/aiskeleton.cpp + src/aiskully.cpp + src/aispider.cpp + src/aiwillow.cpp + src/names.cpp + ) + +add_game_library2( whaven ) + +include_directories( src ) diff --git a/source/games/whaven/src/ai.cpp b/source/games/whaven/src/ai.cpp new file mode 100644 index 000000000..cc1221c25 --- /dev/null +++ b/source/games/whaven/src/ai.cpp @@ -0,0 +1,1213 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +Enemy enemy[MAXTYPES]; + + +int checksight_ang = 0; + +void skeletonChill(PLAYER& plr, short i); +void goblinChill(PLAYER& plr, short i); + + +void createDemonAI(); +void createDevilAI(); +void createDragonAI(); +void createFishAI(); +void createFatwitchAI(); +void createFredAI(); +void createGoblinAI(); +void createGonzoAI(); +void createGronAI(); +void createGuardianAI(); +void createImpAI(); +void createJudyAI(); +void createKatieAI(); +void createKoboldAI(); +void createKurtAI(); +void createMinotaurAI(); +void createNewGuyAI(); +void createRatAI(); +void createSkeletonAI(); +void createSkullyAI(); +void createSpiderAI(); +void createWillowAI(); + +void premapDemon(short i); +void premapDevil(short i); +void premapDragon(short i); +void premapFatwitch(short i); +void premapFish(short i); +void premapFred(short i); +void premapGoblin(short i); +void premapGonzo(short i); +void premapGron(short i); +void premapGuardian(short i); +void premapImp(short i); +void premapJudy(short i); +void premapKatie(short i); +void premapKobold(short i); +void premapKurt(short i); +void premapMinotaur(short i); +void premapNewGuy(short i); +void premapRat(short i); +void premapSkeleton(short i); +void premapSkully(short i); +void premapSpider(short i); +void premapWillow(short i); + + +void initAI() +{ + + + /* + * ai attack ai resurect from enemyInfo goblin imp etc patrol point search + * + * + * AMBUSH -> LAND + * + * case KOBOLD: case IMP: case MINOTAUR: case SKELETON: case GRONSW: case + * NEWGUY: + * + * PATROL + */ + + if (game.WH2) + createImpAI(); + else + createGoblinAI(); + createDevilAI(); + createSkeletonAI(); + createDragonAI(); + createKoboldAI(); + createGuardianAI(); + createWillowAI(); + createRatAI(); + createFredAI(); + createFishAI(); + createSpiderAI(); + createMinotaurAI(); + createGronAI(); + createFatwitchAI(); + createSkullyAI(); + createJudyAI(); + createDemonAI(); + createKatieAI(); + createNewGuyAI(); + createGonzoAI(); + createKurtAI(); // kurt must be initialized after gonzo +} + +static void aiInit() { + for (short i = 0; i < MAXSPRITES; i++) { + if (sprite[i].statnum >= MAXSTATUS) + continue; + + SPRITE& spr = sprite[i]; + int pic = spr.picnum; + switch (spr.picnum) { + default: + if (pic == SKELETON || pic == HANGMAN) { + premapSkeleton(i); + killcnt++; + } + else if (pic == GUARDIAN) { + premapGuardian(i); + killcnt++; + } + else if (pic == WILLOW) { + premapWillow(i); + killcnt++; + } + else if (pic == RAT) { + .premapRat(i); + } + else if (pic == FISH) { + premapFish(i); + } + else if (pic == GRONHAL || pic == GRONMU || pic == GRONSW) { + premapGron(i); + killcnt++; + } + break; + case GOBLIN: // IMP + case GOBLINSTAND: + case GOBLINCHILL: + killcnt++; + if (game.WH2 && spr.picnum == IMP) { + premapImp(i); + break; + } + + if (!game.WH2) + premapGoblin(i); + break; + case DEVIL: + case DEVILSTAND: + if (sprite[i].pal != 8) { + premapDevil(i); + killcnt++; + } + break; + case DRAGON: + premapDragon(i); + killcnt++; + break; + case KOBOLD: + premapKobold(i); + killcnt++; + break; + case FRED: + case FREDSTAND: + premapFred(i); + killcnt++; + break; + case SPIDER: + premapSpider(i); + killcnt++; + break; + case MINOTAUR: + premapMinotaur(i); + killcnt++; + break; + case FATWITCH: + premapFatwitch(i); + killcnt++; + break; + case SKULLY: + premapSkully(i); + killcnt++; + break; + case JUDY: + case JUDYSIT: + premapJudy(i); + killcnt++; + break; + case DEMON: + premapDemon(i); + killcnt++; + break; + case KATIE: + premapKatie(i); + killcnt++; + break; + case KURTSTAND: + case KURTKNEE: + premapKurt(i); + killcnt++; + break; + case NEWGUYSTAND: + case NEWGUYKNEE: + case NEWGUYCAST: + case NEWGUYBOW: + case NEWGUYMACE: + case NEWGUYPUNCH: + case NEWGUY: + premapNewGuy(i); + killcnt++; + break; + case KURTAT: + case KURTPUNCH: + case GONZOCSW: + case GONZOGSW: + case GONZOGHM: + case GONZOGSH: + premapGonzo(i); + killcnt++; + break; + } + } +} + +void aiProcess() { + + PLAYER& plr = player[0]; + + // short daang = (short) plr.ang; + // int daz2 = (int) (100 - plr.horiz) * 2000; + // hitscan(plr.x, plr.y, plr.z, plr.sector, // Start position + // sintable[(daang + 2560) & 2047], // X vector of 3D ang + // sintable[(daang + 2048) & 2047], // Y vector of 3D ang + // daz2, // Z vector of 3D ang + // pHitInfo, CLIPMASK0); + // + // if(pHitInfo.hitsprite != -1) + // { + // int sprid = pHitInfo.hitsprite; + // System.err.println(sprite[sprid].statnum); + // } + + judyOperate(plr); + gonzoProcess(plr); + goblinWarProcess(plr); + dragonProcess(plr); + willowProcess(plr); + + short i, nextsprite; + + for (i = headspritestat[PATROL]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + + SPRITE spr = sprite[i]; + short movestat = (short)movesprite((short)i, ((sintable[(spr.ang + 512) & 2047]) * TICSPERFRAME) << 3, + ((sintable[spr.ang]) * TICSPERFRAME) << 3, 0, 4 << 8, 4 << 8, 0); + if (zr_florz > spr.z + (48 << 8)) { + setsprite(i, spr.x, spr.y, spr.z); + movestat = 1; + } + else { + spr.z = zr_florz; + } + short j = headspritesect[spr.sectnum]; + while (j != -1) { + short nextj = nextspritesect[j]; + SPRITE tspr = sprite[j]; + if (tspr.picnum == PATROLPOINT) { + int dx = klabs(spr.x - tspr.x); // x distance to sprite + int dy = klabs(spr.y - tspr.y); // y distance to sprite + int dz = klabs((spr.z >> 8) - (tspr.z >> 8)); // z distance to sprite + int dh = tilesizy[tspr.picnum] >> 4; // height of sprite + if (dx + dy < PICKDISTANCE && dz - dh <= getPickHeight()) { + spr.ang = tspr.ang; + } + } + j = nextj; + } + if (sintable[(spr.ang + 2560) & 2047] * (plr.x - spr.x) + + sintable[(spr.ang + 2048) & 2047] * (plr.y - spr.y) >= 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum)) { + newstatus(i, CHASE); + } + } + else if (movestat != 0) { + if ((movestat & 0xc000) == 32768) { // hit a wall + actoruse(i); + } + newstatus(i, FINDME); + } + } + + for (i = headspritestat[CHASE]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + if (enemy[spr.detail] != null && enemy[spr.detail].chase != null) + enemy[spr.detail].chase.process(plr, i); + } + + for (i = headspritestat[RESURECT]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + if (enemy[spr.detail] != null && enemy[spr.detail].resurect != null) { + enemy[spr.detail].resurect.process(plr, i); + } + } + + for (i = headspritestat[FINDME]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + + if (enemy[spr.detail] != null && enemy[spr.detail].search != null) + enemy[spr.detail].search.process(plr, i); + } + + for (i = headspritestat[NUKED]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + + if (spr.picnum == ZFIRE) { + spr.lotag -= TICSPERFRAME; + if (spr.lotag <= 0) + deletesprite(i); + } + else { + if (enemy[spr.detail] != null && enemy[spr.detail].nuked != null) + enemy[spr.detail].nuked.process(plr, i); + } + } + + for (i = headspritestat[FROZEN]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + if (enemy[spr.detail] != null && enemy[spr.detail].frozen != null) + enemy[spr.detail].frozen.process(plr, i); + } + + for (i = headspritestat[PAIN]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + + if (enemy[spr.detail] != null && enemy[spr.detail].pain != null) + enemy[spr.detail].pain.process(plr, i); + } + + for (i = headspritestat[FACE]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + + if (enemy[spr.detail] != null && enemy[spr.detail].face != null) + enemy[spr.detail].face.process(plr, i); + } + + for (i = headspritestat[ATTACK]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + + if (game.WH2 && attacktheme == 0) { + attacktheme = 1; + startsong((rand() % 2) + 2); + } + + if (enemy[spr.detail] != null && enemy[spr.detail].attack != null) + enemy[spr.detail].attack.process(plr, i); + } + + for (i = headspritestat[FLEE]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + + if (enemy[spr.detail] != null && enemy[spr.detail].flee != null) + enemy[spr.detail].flee.process(plr, i); + } + + for (i = headspritestat[CAST]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + + if (enemy[spr.detail] != null && enemy[spr.detail].cast != null) + enemy[spr.detail].cast.process(plr, i); + } + + for (i = headspritestat[DIE]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + if (enemy[spr.detail] != null && enemy[spr.detail].die != null) + enemy[spr.detail].die.process(plr, i); + } + + for (i = headspritestat[SKIRMISH]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + + if (enemy[spr.detail] != null && enemy[spr.detail].skirmish != null) + enemy[spr.detail].skirmish.process(plr, i); + } + + for (i = headspritestat[STAND]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + + if (enemy[spr.detail] != null && enemy[spr.detail].stand != null) + enemy[spr.detail].stand.process(plr, i); + } + + for (i = headspritestat[CHILL]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + switch (spr.detail) { + case GOBLINTYPE: + goblinChill(plr, i); + break; + case SKELETONTYPE: + skeletonChill(plr, i); + break; + } + } + + for (i = headspritestat[DEAD]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + case TYPEWATER: + spr.z = zr_florz + (tilesizy[spr.picnum] << 5); + break; + } + } +} + +int aimove(short i) { + int ox = sprite[i].x; + int oy = sprite[i].y; + int oz = sprite[i].z; + // short osect = sprite[i].sectnum; + + int movestate = movesprite(i, ((sintable[(sprite[i].ang + 512) & 2047]) * TICSPERFRAME) << 3, + ((sintable[sprite[i].ang & 2047]) * TICSPERFRAME) << 3, 0, 4 << 8, 4 << 8, CLIFFCLIP); + + if (((zr_florz - oz) >> 4) > tilesizy[sprite[i].picnum] + sprite[i].yrepeat << 2 + || (movestate & kHitTypeMask) == kHitWall) { + // changespritesect(i, osect); + // setsprite(i, ox + mulscale((sprite[i].clipdist) << 2, sintable[(sprite[i].ang + 1536) & 2047], 16), + // oy + mulscale((sprite[i].clipdist) << 2, sintable[(sprite[i].ang + 1024) & 2047], 16), oz); + + setsprite(i, ox, oy, oz); + + if ((movestate & kHitTypeMask) != kHitWall) { + if (game.WH2) + sprite[i].z += WH2GRAVITYCONSTANT; + else + sprite[i].z += GRAVITYCONSTANT; + return 16384 | zr_florhit; + } + } + + sprite[i].z = zr_florz; + + return movestate; +} + +int aifly(short i) { + SPRITE spr = sprite[i]; + int movestate = movesprite(i, ((sintable[(sprite[i].ang + 512) & 2047]) * TICSPERFRAME) << 3, + ((sintable[sprite[i].ang & 2047]) * TICSPERFRAME) << 3, 0, 4 << 8, 4 << 8, CLIFFCLIP); + + spr.z -= TICSPERFRAME << 8; + short ocs = spr.cstat; + spr.cstat = 0; + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.cstat = ocs; + if (spr.z > zr_florz) + spr.z = zr_florz; + if (spr.z - (tilesizy[spr.picnum] << 7) < zr_ceilz) + spr.z = zr_ceilz + (tilesizy[spr.picnum] << 7); + + return movestate; +} + +void aisearch(PLAYER& plr, short i, boolean fly) { + SPRITE spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + // if (plr.invisibletime > 0) { + // newstatus(i, FACE); + // return; + // } + + short osectnum = spr.sectnum; + + int movestat; + if (fly) + movestat = aifly(i); + else + movestat = aimove(i); + + if (checkdist(plr, i)) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, ATTACK); + return; + } + + if (movestat != 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && spr.lotag < 0) { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + if (spr.lotag < 0) { + if (krand() % 100 > 50) + spr.ang = (short)((spr.ang + 512) & 2047); + else + spr.ang = (short)((spr.ang + 1024) & 2047); + + spr.lotag = 30; + } + else { + spr.ang += (TICSPERFRAME << 4) & 2047; + } + } + + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && movestat == 0 && spr.lotag < 0) { + newstatus(i, FACE); + return; + } + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + processfluid(i, zr_florhit, fly); + + setsprite(i, spr.x, spr.y, spr.z); +} + +boolean checksector6(short i) { + SPRITE spr = sprite[i]; + if (sector[spr.sectnum].floorz - (32 << 8) < sector[spr.sectnum].ceilingz) { + if (sector[spr.sectnum].lotag == 6) + newstatus(i, DIE); + else { + deletesprite(i); + return true; + } + } + + return false; +} + +int checkfluid(int i, int zr_florhit) { + SPRITE spr = sprite[i]; + if (isValidSector(spr.sectnum) && (zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == WATER + /* || sector[spr.sectnum].floorpicnum == LAVA2 */ || sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == SLIME || sector[spr.sectnum].floorpicnum == FLOORMIRROR + /* + * || sector[spr.sectnum].floorpicnum == LAVA1 || + * sector[spr.sectnum].floorpicnum == ANILAVA + */)) { + if (sector[spr.sectnum].floorpicnum == WATER || sector[spr.sectnum].floorpicnum == SLIME + || sector[spr.sectnum].floorpicnum == FLOORMIRROR) { + return TYPEWATER; + } + else { + return TYPELAVA; + } + } + + return TYPENONE; +} + +void processfluid(int i, int zr_florhit, boolean fly) { + SPRITE spr = sprite[i]; + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + if (!fly) { + spr.z += tilesizy[spr.picnum] << 5; + trailingsmoke(i, true); + makemonstersplash(LAVASPLASH, i); + } + break; + case TYPEWATER: + if (!fly) { + spr.z += tilesizy[spr.picnum] << 5; + if (krand() % 100 > 60) + makemonstersplash(SPLASHAROO, i); + } + break; + } +} + +void castspell(PLAYER& plr, int i) { + int j = insertsprite(sprite[i].sectnum, MISSILE); + + sprite[j].x = sprite[i].x; + sprite[j].y = sprite[i].y; + if (game.WH2 || sprite[i].picnum == SPAWNFIREBALL) + sprite[j].z = sprite[i].z - ((tilesizy[sprite[i].picnum] >> 1) << 8); + else + sprite[j].z = getflorzofslope(sprite[i].sectnum, sprite[i].x, sprite[i].y) - ((tilesizy[sprite[i].picnum] >> 1) << 8); + sprite[j].cstat = 0; // Hitscan does not hit other bullets + sprite[j].picnum = MONSTERBALL; + sprite[j].shade = -15; + sprite[j].xrepeat = 64; + sprite[j].yrepeat = 64; + if (sprite[i].picnum == SPAWNFIREBALL) + sprite[j].ang = (short)((getangle(plr.x - sprite[j].x, plr.y - sprite[j].y) + 2048) & 2047); + else + sprite[j].ang = (short)(((getangle(plr.x - sprite[j].x, plr.y - sprite[j].y) + (krand() & 15) + - 8) + 2048) & 2047); + sprite[j].xvel = (short)(sintable[(sprite[j].ang + 2560) & 2047] >> 6); + sprite[j].yvel = (short)(sintable[(sprite[j].ang + 2048) & 2047] >> 6); + + int discrim = ksqrt((plr.x - sprite[j].x) * (plr.x - sprite[j].x) + (plr.y - sprite[j].y) * (plr.y - sprite[j].y)); + if (discrim == 0) + discrim = 1; + if (game.WH2) + sprite[j].zvel = (short)(((plr.z + (8 << 8) - sprite[j].z) << 7) / discrim); + else + sprite[j].zvel = (short)(((plr.z + (48 << 8) - sprite[j].z) << 7) / discrim); + + sprite[j].owner = (short)i; + sprite[j].clipdist = 16; + sprite[j].lotag = 512; + sprite[j].hitag = 0; + + game.pInt.setsprinterpolate(j, sprite[j]); +} + +void skullycastspell(PLAYER& plr, int i) { + int j = insertsprite(sprite[i].sectnum, MISSILE); + + sprite[j].x = sprite[i].x; + sprite[j].y = sprite[i].y; + if (sprite[i].picnum == SPAWNFIREBALL) + sprite[j].z = sprite[i].z - ((tilesizy[sprite[i].picnum] >> 1) << 8); + else + sprite[j].z = getflorzofslope(sprite[i].sectnum, sprite[i].x, sprite[i].y) - ((tilesizy[sprite[i].picnum] >> 1) << 8); + sprite[j].cstat = 0; // Hitscan does not hit other bullets + sprite[j].picnum = PLASMA; + sprite[j].shade = -15; + sprite[j].xrepeat = 64; + sprite[j].yrepeat = 64; + if (sprite[i].picnum == SPAWNFIREBALL) + sprite[j].ang = (short)((getangle(plr.x - sprite[j].x, plr.y - sprite[j].y) + 2048) & 2047); + else + sprite[j].ang = (short)(((getangle(plr.x - sprite[j].x, plr.y - sprite[j].y) + (krand() & 15) + - 8) + 2048) & 2047); + sprite[j].xvel = (short)(sintable[(sprite[j].ang + 2560) & 2047] >> 6); + sprite[j].yvel = (short)(sintable[(sprite[j].ang + 2048) & 2047] >> 6); + + int discrim = ksqrt((plr.x - sprite[j].x) * (plr.x - sprite[j].x) + (plr.y - sprite[j].y) * (plr.y - sprite[j].y)); + if (discrim == 0) + discrim = 1; + sprite[j].zvel = (short)(((plr.z + (48 << 8) - sprite[j].z) << 7) / discrim); + + sprite[j].owner = (short)i; + sprite[j].clipdist = 16; + sprite[j].lotag = 512; + sprite[j].hitag = 0; + sprite[j].pal = 7; + + game.pInt.setsprinterpolate(j, sprite[j]); +} + +void attack(PLAYER& plr, int i) { + int s = 0; + if (plr.invincibletime > 0 || plr.godMode) + return; + + if (plr.treasure[TADAMANTINERING] == 1 && (krand() & 1) != 0) + return; + + // if ((krand() & (15 < plr.armortype ? 11 : 10)) != 0) + // return; + + if (!droptheshield && plr.shieldpoints > 0 && plr.selectedgun > 0 && plr.selectedgun < 5) { + short a = getangle(sprite[i].x - plr.x, sprite[i].y - plr.y); + if ((a < plr.ang && plr.ang - a < 128) || (a > plr.ang && (((short)plr.ang + a) & 2047) < 128)) { + if (krand() % 100 > 80) { + playsound_loc(S_SWORD1 + krand() % 3, plr.x, plr.y); + return; + } + else { + s = krand() % 50; + plr.shieldpoints -= s; + if (krand() % 100 > 50) { + playsound_loc(S_SWORD1 + krand() % 3, plr.x, plr.y); + return; + } + } + } + if (plr.shieldpoints <= 0) { + showmessage("Shield useless", 360); + } + } + + int k = 5; + if (!game.WH2) { + k = krand() % 100; + if (k > (plr.armortype << 3)) + k = 15; + else + k = 5; + } + + switch (sprite[i].detail) { + case SPIDER: + k = 5; + break; + case FISHTYPE: + case RATTYPE: + k = 3; + break; + case SKELETONTYPE: + playsound_loc(S_RIP1 + (krand() % 3), sprite[i].x, sprite[i].y); + if ((krand() % 2) != 0) + playsound_loc(S_GORE1 + (krand() % 4), sprite[i].x, sprite[i].y); + if ((krand() % 2) != 0) + playsound_loc(S_BREATH1 + (krand() % 6), sprite[i].x, sprite[i].y); + + if (game.WH2) + k = (krand() % 5) + 5; + else + k >>= 2; + break; + case KATIETYPE: // damage 5 - 50 + playsound_loc(S_DEMONTHROW, sprite[i].x, sprite[i].y); + k = (krand() % 45) + 5; + break; + + case DEVILTYPE: + playsound_loc(S_DEMONTHROW, sprite[i].x, sprite[i].y); + if (!game.WH2) + k >>= 2; + break; + + case KOBOLDTYPE: + playsound_loc(S_GENSWING, sprite[i].x, sprite[i].y); + if ((krand() % 10) > 4) { + playsound_loc(S_KOBOLDHIT, plr.x, plr.y); + playsound_loc(S_BREATH1 + (krand() % 6), plr.x, plr.y); + } + if (game.WH2) + k = (krand() % 5) + 5; + else + k >>= 2; + break; + case FREDTYPE: + + /* Sounds for Fred (currently copied from Goblin) */ + playsound_loc(S_GENSWING, sprite[i].x, sprite[i].y); + if (rand() % 10 > 4) + playsound_loc(S_SWORD1 + (rand() % 6), sprite[i].x, sprite[i].y); + + k >>= 3; + break; + case IMPTYPE: + if (!game.WH2) + break; + playsound_loc(S_RIP1 + (krand() % 3), sprite[i].x, sprite[i].y); + if ((krand() % 2) != 0) { + playsound_loc(S_GORE1 + (krand() % 4), sprite[i].x, sprite[i].y); + } + if ((krand() % 2) != 0) { + playsound_loc(S_BREATH1 + (krand() % 6), sprite[i].x, sprite[i].y); + } + + k = (krand() % 5) + 5; + if (k > 8) { + plr.poisoned = 1; + } + break; + case GOBLINTYPE: + if (game.WH2) + break; + + playsound_loc(S_GENSWING, sprite[i].x, sprite[i].y); + if ((krand() % 10) > 4) + playsound_loc(S_SWORD1 + (krand() % 6), sprite[i].x, sprite[i].y); + k >>= 2; + break; + case NEWGUYTYPE: + if (sprite[i].picnum == NEWGUYMACE) { // damage 5 - 20 + playsound_loc(S_PLRWEAPON2, sprite[i].x, sprite[i].y); + if (krand() % 10 > 4) { + playsound_loc(S_KOBOLDHIT, plr.x, plr.y); + playsound_loc(S_BREATH1 + (krand() % 6), plr.x, plr.y); + } + k = (krand() % 15) + 5; + break; + } + case KURTTYPE: + case GONZOTYPE: + playsound_loc(S_GENSWING, sprite[i].x, sprite[i].y); + if (sprite[i].picnum == GONZOCSWAT || sprite[i].picnum == GONZOGSWAT) { // damage 5 - 15 + if (krand() % 10 > 6) + playsound_loc(S_SWORD1 + (krand() % 6), sprite[i].x, sprite[i].y); + k = (krand() % 15) + 5; + } + else if (sprite[i].picnum == GONZOGHMAT) { // damage 5 - 15 + if (krand() % 10 > 6) + playsound_loc(S_SWORD1 + (krand() % 6), sprite[i].x, sprite[i].y); + k = (krand() % 10) + 5; + } + else if (sprite[i].picnum == GONZOGSHAT) { // damage 5 - 20 + if (krand() % 10 > 3) + playsound_loc(S_SWORD1 + (krand() % 6), sprite[i].x, sprite[i].y); + k = (krand() % 15) + 5; + } + else if (sprite[i].picnum == KURTAT) { // damage 5 - 15 + playsound_loc(S_GENSWING, sprite[i].x, sprite[i].y); + if (krand() % 10 > 3) { + playsound_loc(S_SWORD1 + (krand() % 6), sprite[i].x, sprite[i].y); + } + k = (krand() % 10) + 5; + } + else { + playsound_loc(S_GENSWING, sprite[i].x, sprite[i].y); + if (krand() % 10 > 4) { + playsound_loc(S_SOCK1 + (krand() % 4), plr.x, plr.y); + playsound_loc(S_BREATH1 + (krand() % 6), plr.x, plr.y); + } + k = (krand() % 4) + 1; + } + break; + + case GRONTYPE: + if (sprite[i].picnum != GRONSWATTACK) + break; + + if (game.WH2) { + k = (krand() % 20) + 5; + if (sprite[i].shade > 30) { + k += krand() % 10; + } + } + else { + if (sprite[i].shade > 30) + k >>= 1; + } + playsound_loc(S_GENSWING, sprite[i].x, sprite[i].y); + if ((krand() % 10) > 3) + playsound_loc(S_SWORD1 + (krand() % 6), sprite[i].x, sprite[i].y); + + break; + case MINOTAURTYPE: + playsound_loc(S_GENSWING, sprite[i].x, sprite[i].y); + if (krand() % 10 > 4) + playsound_loc(S_SWORD1 + (krand() % 6), sprite[i].x, sprite[i].y); + if (game.WH2) + k = (krand() % 25) + 5; + break; + } + + if (plr.shieldpoints > 0) { + if (s > k) + k = 0; + else + k -= s; + } + + int a; + switch (plr.armortype) { + case 0: // none + addhealth(plr, -k); + break; + case 1: // leather + a = krand() % 5; + if (a > k) { + k = 0; + } + else { + k -= a; + } + addarmor(plr, -a); + addhealth(plr, -k); + break; + case 2: // chain + a = krand() % 10; + if (a > k) { + k = 0; + } + else { + k -= a; + } + addarmor(plr, -a); + addhealth(plr, -k); + break; + case 3: // plate + a = krand() % 20; + if (a > k) { + k = 0; + } + else { + k -= a; + } + addarmor(plr, -a); + addhealth(plr, -k); + break; + } + + startredflash(3 * k); + + if (k == 0) + k = 1; + + k = krand() % k; + + damage_angvel += k << 3; + damage_svel += k << 3; + damage_vel -= k << 3; + + plr.hvel += k << 2; +} + +int checkmove(short i, int dax, int day) { + int movestat = movesprite(i, dax, day, 0, 4 << 8, 4 << 8, CLIFFCLIP); + + if (movestat != 0) + sprite[i].ang = (short)((sprite[i].ang + TICSPERFRAME) & 2047); + + return movestat; +} + +boolean checkdist(PLAYER& plr, int i) { + if (plr.invisibletime > 0 || plr.health <= 0) + return false; + + return checkdist(i, plr.x, plr.y, plr.z); +} + +boolean checkdist(int i, int x, int y, int z) { + SPRITE spr = sprite[i]; + + int attackdist = 512; + int attackheight = 120; + if (spr.detail > 0) { + attackdist = enemy[spr.detail].info.getAttackDist(spr); + attackheight = enemy[spr.detail].info.attackheight; + } + + switch (spr.picnum) { + case LFIRE: + case SFIRE: + attackdist = 1024; + break; + } + + if ((klabs(x - spr.x) + klabs(y - spr.y) < attackdist) + && (klabs((z >> 8) - ((spr.z >> 8) - (tilesizy[spr.picnum] >> 1))) <= attackheight)) + return true; + + return false; +} + +boolean checksight(PLAYER& plr, int i) { + if (plr.invisibletime > 0) { + checksight_ang = ((krand() & 512) - 256) & 2047; + return false; + } + + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum) && plr.invisibletime < 0) { + checksight_ang = (getangle(plr.x - sprite[i].x, plr.y - sprite[i].y) & 2047); + if (((sprite[i].ang + 2048 - checksight_ang) & 2047) < 1024) + sprite[i].ang = (short)((sprite[i].ang + 2048 - (TICSPERFRAME << 1)) & 2047); + else + sprite[i].ang = (short)((sprite[i].ang + (TICSPERFRAME << 1)) & 2047); + + return true; + } + else + checksight_ang = 0; + + return false; +} + +void monsterweapon(int i) { + + if (sprite[i].shade > 20) + return; + + if (sprite[i].picnum == SKELETONDEAD || sprite[i].picnum == KOBOLDDEAD) + return; + + if ((krand() % 100) < 75) + return; + + int j = insertsprite(sprite[i].sectnum, (short)0); + + SPRITE weap = sprite[j]; + weap.x = sprite[i].x; + weap.y = sprite[i].y; + weap.z = sprite[i].z - (24 << 8); + weap.shade = -15; + weap.cstat = 0; + weap.cstat &= ~3; + weap.pal = 0; + + int type = (krand() % 4); + weap.picnum = (short)(FLASKBLUE + type); + weap.detail = (short)(FLASKBLUETYPE + type); + weap.xrepeat = 25; + weap.yrepeat = 20; + + game.pInt.setsprinterpolate(j, weap);// XXX + + switch (sprite[i].picnum) { + case NEWGUYDEAD: + weap.xrepeat = 25; + weap.yrepeat = 20; + if (weap.extra < 20) { + weap.picnum = WEAPON2; + weap.detail = WEAPON2TYPE; + } + else { + weap.picnum = QUIVER; + weap.detail = QUIVERTYPE; + } + + weap.pal = 0; + break; + + case MINOTAURDEAD: + weap.xrepeat = 25; + weap.yrepeat = 20; + if (!game.WH2) { + if (krand() % 100 > 50) { + weap.picnum = WEAPON4; + } + else { + weap.xrepeat = 20; + weap.yrepeat = 15; + weap.picnum = WEAPON6; + weap.detail = WEAPON6TYPE; + } + } + else { + weap.picnum = WEAPON4; + weap.detail = WEAPON4TYPE; + } + break; + + case GONZOBSHDEAD: + weap.picnum = GONZOBSHIELD; + weap.detail = GONZOSHIELDTYPE; + weap.xrepeat = 12; + weap.yrepeat = 12; + break; + + case GONZOCSWDEAD: + if (weap.extra > 10) { + weap.picnum = WEAPON6; + weap.detail = WEAPON6TYPE; + weap.xrepeat = 25; + weap.yrepeat = 20; + } + else if (weap.extra > 0) { + weap.picnum = GOBWEAPON; + weap.detail = GOBWEAPONTYPE; + weap.xrepeat = 25; + weap.yrepeat = 20; + } + else { + weap.picnum = WEAPON1; + weap.detail = WEAPON1TYPE; + weap.xrepeat = 25; + weap.yrepeat = 20; + } + break; + case GONZOCSHDEAD: + weap.picnum = GONZOCSHIELD; + weap.detail = GONZOSHIELDTYPE; + weap.xrepeat = 12; + weap.yrepeat = 12; + break; + + case GONZOGSWDEAD: + weap.picnum = WEAPON8; + weap.detail = WEAPON8TYPE; + weap.xrepeat = 25; + weap.yrepeat = 20; + break; + case GONZOGHMDEAD: + weap.picnum = PLATEARMOR; + weap.detail = PLATEARMORTYPE; + weap.xrepeat = 26; + weap.yrepeat = 26; + break; + case GONZOGSHDEAD: + weap.picnum = GONZOGSHIELD; + weap.detail = GONZOSHIELDTYPE; + weap.xrepeat = 12; + weap.yrepeat = 12; + break; + case GOBLINDEAD: + weap.xrepeat = 16; + weap.yrepeat = 16; + weap.picnum = GOBWEAPON; + weap.detail = GOBWEAPONTYPE; + break; + default: + if (sprite[i].picnum == GRONDEAD) { + if (netgame) { + weap.x = sprite[i].x; + weap.y = sprite[i].y; + weap.z = sprite[i].z - (24 << 8); + weap.shade = -15; + weap.cstat = 0; + weap.cstat &= ~3; + weap.xrepeat = 25; + weap.yrepeat = 20; + int k = krand() % 4; + switch (k) { + case 0: + weap.picnum = WEAPON3; + weap.detail = WEAPON3TYPE; + weap.xrepeat = 25; + weap.yrepeat = 20; + break; + case 1: + weap.picnum = WEAPON5; + weap.detail = WEAPON5TYPE; + weap.xrepeat = 25; + weap.yrepeat = 20; + break; + case 2: + weap.picnum = WEAPON6; + weap.detail = WEAPON6TYPE; + weap.xrepeat = 20; + weap.yrepeat = 15; + break; + case 3: + weap.picnum = SHIELD; + weap.detail = SHIELDTYPE; + weap.xrepeat = 32; + weap.yrepeat = 32; + break; + } + } + else { + switch (weap.pal) { + case 0: + weap.picnum = WEAPON3; + weap.detail = WEAPON3TYPE; + weap.xrepeat = 25; + weap.yrepeat = 20; + break; + case 10: + weap.picnum = WEAPON5; + weap.detail = WEAPON5TYPE; + weap.xrepeat = 25; + weap.yrepeat = 20; + break; + case 11: + weap.picnum = WEAPON6; + weap.detail = WEAPON6TYPE; + weap.xrepeat = 20; + weap.yrepeat = 15; + break; + case 12: + weap.picnum = SHIELD; + weap.detail = SHIELDTYPE; + weap.xrepeat = 32; + weap.yrepeat = 32; + break; + } + } + weap.pal = 0; + break; + } + treasurescnt++; + break; + } +} + +PLAYER& aiGetPlayerTarget(short i) { + if (sprite[i].owner >= 0 && sprite[i].owner < MAXSPRITES) { + int playernum = sprite[sprite[i].owner].owner; + if (playernum >= 4096) + return player[playernum - 4096]; + } + + return null; +} + +boolean actoruse(short i) { + SPRITE spr = sprite[i]; + + neartag(spr.x, spr.y, spr.z, spr.sectnum, spr.ang, neartag, 1024, 3); + + if (neartag.tagsector >= 0) { + if (sector[neartag.tagsector].hitag == 0) { + if (sector[neartag.tagsector].floorz != sector[neartag.tagsector].ceilingz) { + operatesector(player[pyrn], neartag.tagsector); + return true; + } + } + } + + return false; +} + + +END_WH_NS \ No newline at end of file diff --git a/source/games/whaven/src/ai.h b/source/games/whaven/src/ai.h new file mode 100644 index 000000000..33dc5635c --- /dev/null +++ b/source/games/whaven/src/ai.h @@ -0,0 +1,142 @@ +#pragma once +#include "wh.h" + +BEGIN_WH_NS + +struct EnemyInfo +{ + short sizx, sizy; + int attackdist; + int attackdamage; + int attackheight; + short health; + bool fly; + int clipdist; + int score; + + void Init(int sizx, int sizy, int dist, int height, int damage, int clipdist, bool fly, int health, int score) + { + this->sizx = (short) sizx; + this->sizy = (short) sizy; + this->attackdist = dist; + this->attackheight = height; + this->attackdamage = damage; + this->clipdist = clipdist; + this->fly = fly; + this->health = (short) health; + this->score = score; + } + + short (*getHealth)(EnemyInfo& e, SPRITE& spr) = [](EnemyInfo& e, SPRITE& spr) + { + return adjusthp(e.health); + }; + + int (*getAttackDist)(EnemyInfo& e, SPRITE& spr) = [](EnemyInfo &e, SPRITE& spr) + { + return e.attackdist; + }; + + void set(SPRITE &spr) + { + spr.clipdist = clipdist; + spr.hitag = getHealth(*this, spr); + if(sizx != -1) + spr.xrepeat = sizx; + if(sizy != -1) + spr.yrepeat = sizy; + spr.lotag = 100; + + int tflag = 0; + if((spr.cstat & 514) != 0) + tflag = spr.cstat & 514; + + spr.cstat = (short) (0x101 | tflag); + } +}; + + +using AIState = void (*)(PLAYER &plr, short i); + + +struct Enemy +{ + EnemyInfo info; + + AIState patrol; + AIState chase; + AIState resurect; + AIState nuked; + AIState frozen; + AIState pain; + AIState face; + AIState attack; + AIState flee; + AIState cast; + AIState die; + AIState skirmish; + AIState stand; + AIState search; +}; + + +enum EEnemy +{ + DEMONTYPE = 1, // ok + DEVILTYPE = 2, // nuked ok, frozen no + DRAGONTYPE = 3, // wh1 + FATWITCHTYPE = 4, // wh1 + FISHTYPE = 5, + FREDTYPE = 6, + GOBLINTYPE = 7, // wh1 + GONZOTYPE = 8, // freeze nuke ok + GRONTYPE = 9, // ok + GUARDIANTYPE = 10, // nuke ok + IMPTYPE = 11, // freeze nuke ok + JUDYTYPE = 12, // wh1 + KATIETYPE = 13, // ok + KOBOLDTYPE = 14, // freeze nuke ok + KURTTYPE = 15, + MINOTAURTYPE = 16, // freeze nuke ok + NEWGUYTYPE = 17, // freeze nuke ok + RATTYPE = 18, + SKELETONTYPE = 19, // freezee nuke ok + SKULLYTYPE = 20, // wh1 + SPIDERTYPE = 21, // wh1 + WILLOWTYPE = 22, //nuke ok + MAXTYPES = 23, +}; + +enum EAIConst +{ + TYPENONE = 0, + TYPEWATER = 1, + TYPELAVA = 2, +}; + +extern Enemy enemy[MAXTYPES]; + +void aiProcess(); +int aimove(short i); +int aifly(short i); +void aisearch(PLAYER& plr, short i, boolean fly); +boolean checksector6(short i); +int checkfluid(int i, int zr_florhit); +void processfluid(int i, int zr_florhit, boolean fly); +void castspell(PLAYER& plr, int i); +void skullycastspell(PLAYER& plr, int i); +void attack(PLAYER& plr, int i); +int checkmove(short i, int dax, int day); +boolean checkdist(PLAYER& plr, int i); +boolean checkdist(int i, int x, int y, int z); +extern int checksight_ang; +boolean checksight(PLAYER& plr, int i); +void monsterweapon(int i); +PLAYER& aiGetPlayerTarget(short i); +boolean actoruse(short i); + +inline int findplayer() { + return 0; // no multiplayer support, apparently... +} + +END_WH_NS diff --git a/source/games/whaven/src/aidemon.cpp b/source/games/whaven/src/aidemon.cpp new file mode 100644 index 000000000..b8a26591e --- /dev/null +++ b/source/games/whaven/src/aidemon.cpp @@ -0,0 +1,231 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + if (plr.z < spr.z) { + spr.z -= TICSPERFRAME << 8; + } + if (plr.z > spr.z) { + spr.z += TICSPERFRAME << 8; + } + + short osectnum = spr.sectnum; + if (krand() % 63 == 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum) && plr.invisibletime < 0) + newstatus(i, ATTACK); + return; + } + else { + if (totalclock % 100 > 70) + trailingsmoke(i, true); + + int dax = ((sintable[(sprite[i].ang + 512) & 2047] * TICSPERFRAME) << 2); + int day = ((sintable[sprite[i].ang & 2047] * TICSPERFRAME) << 2); + checksight(plr, i); + + + if (!checkdist(plr, i)) { + checkmove(i, dax, day); + } + else { + if (plr.invisibletime < 0) { + if (krand() % 8 == 0) // NEW + newstatus(i, ATTACK); // NEW + else { // NEW + sprite[i].ang = (short)(((krand() & 512 - 256) + sprite[i].ang + 1024) & 2047); // NEW + newstatus(i, CHASE); // NEW + } + } + } + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + checksector6(i); + + processfluid(i, zr_florhit, true); + + if (sector[osectnum].lotag == KILLSECTOR && spr.z + (8 << 8) >= sector[osectnum].floorz) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + if (spr.z + (8 << 8) >= sector[osectnum].floorz) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + } +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, true); + checksector6(i); +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = DEMON; + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aifly(i); + setsprite(i, spr.x, spr.y, spr.z); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047); + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); +} + + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + if (plr.z < spr.z) { + spr.z -= TICSPERFRAME << 8; + } + if (plr.z > spr.z) { + spr.z += TICSPERFRAME << 8; + } + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum)) + newstatus(i, CAST); + else + newstatus(i, CHASE); + } + else + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aifly(i); + + if (movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, true); + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void cast(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + + if (plr.z < spr.z) { + spr.z -= TICSPERFRAME << 8; + } + if (plr.z > spr.z) { + spr.z += TICSPERFRAME << 8; + } + + if (spr.lotag < 0) { + castspell(plr, i); + newstatus(i, CHASE); + } +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + chunksofmeat(plr, i, spr.x, spr.y, spr.z, spr.sectnum, spr.ang); + trailingsmoke(i, false); + newstatus((short)i, DIE); +} + + +void createDemonAI() { + auto& e = enemy[DEMONTYPE]; + enemy[DEMONTYPE].info.Init(38, 41, 4096 + 2048, 120, 0, 64, true, 300, 0); + + e.chase = chase; + e.resurect; + e.nuked = nuked; + e.frozen; + e.pain = pain; + e.face = face; + e.attack = attack; + e.flee = flee; + e.cast = cast; + e.die; + e.skirmish; + e.stand; + e.search = search; +} + + +void premapDemon(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = DEMONTYPE; + changespritestat(i, FACE); + enemy[DEMONTYPE].info.set(spr); +} diff --git a/source/games/whaven/src/aidevil.cpp b/source/games/whaven/src/aidevil.cpp new file mode 100644 index 000000000..1f7c93521 --- /dev/null +++ b/source/games/whaven/src/aidevil.cpp @@ -0,0 +1,280 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + + if (krand() % 63 == 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum) && plr.invisibletime < 0) + newstatus(i, ATTACK); + } + else { + checksight(plr, i); + if (!checkdist(plr, i)) { + if ((aimove(i) & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + } + else { + if (plr.invisibletime < 0) { + if (krand() % 8 == 0) // NEW + newstatus(i, ATTACK); // NEW + else { // NEW + sprite[i].ang = (short)(((krand() & 512 - 256) + sprite[i].ang + 1024) & 2047); // NEW + newstatus(i, FLEE); // NEW + } + } + } + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == DEVILDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = DEVIL; + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + sprite[i].extra -= TICSPERFRAME; + sprite[i].lotag -= TICSPERFRAME; + if (sprite[i].lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum)) + newstatus(i, CAST); + else + newstatus(i, CHASE); + } + else + sprite[i].ang = getangle(plr.x - sprite[i].x, plr.y - sprite[i].y); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + spr.picnum = DEVIL; + spr.hitag = (short)adjusthp(60); + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + checksector6(i); +} + +static void frozen(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.pal = 0; + spr.picnum = DEVIL; + newstatus(i, FACE); + } +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + if (game.WH2) { + chunksofmeat(plr, i, spr.x, spr.y, spr.z, spr.sectnum, spr.ang); + trailingsmoke(i, false); + newstatus((short)i, DIE); + return; + } + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 24; + if (spr.picnum == DEVILCHAR + 4) { + trailingsmoke(i, false); + deletesprite(i); + } + } +} + +static void cast(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 12; + } + + if (spr.picnum == DEVILATTACK + 2) { + spr.picnum = DEVIL; + playsound_loc(S_FIREBALL, sprite[i].x, sprite[i].y); + castspell(plr, i); + newstatus(i, CHASE); + } + checksector6(i); +} + + +void createDevilAI() { + auto &e = enemy[DEVILTYPE]; + e.info.Init(game.WH2 ? 50 : 36, game.WH2 ? 50 : 36, 2048, 120, 0, 64, false, 50, 0); + e.chase = chase; + e.die = die; + e.pain = pain; + e.face = face; + e.flee = flee; + e.attack = attack; + e.resurect = resurect; + e.search = search; + e.frozen = frozen; + e.nuked = nuked; + e.cast = cast; +} + +void premapDevil(short i) { + SPRITE& spr = sprite[i]; + spr.detail = DEVILTYPE; + changespritestat(i, FACE); + enemy[DEVILTYPE].info.set(spr); + if (spr.pal == 2) + spr.hitag = adjusthp(60); +} + +END_WH_NS diff --git a/source/games/whaven/src/aidragon.cpp b/source/games/whaven/src/aidragon.cpp new file mode 100644 index 000000000..e994e9801 --- /dev/null +++ b/source/games/whaven/src/aidragon.cpp @@ -0,0 +1,420 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static int checksight_x, checksight_y = 0; + +static void checkspeed(int i, int speed); +static void dragonAttack2(PLAYER& plr, short i); +static void firebreath(PLAYER& plr, int i, int a, int b, int c); + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + // int speed = 10; + if ((krand() % 16) == 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) + if (plr.z < spr.z) + newstatus(i, ATTACK2); + else + newstatus(i, ATTACK); + return; + } + else { + int dax = (sintable[(sprite[i].ang + 512) & 2047] * TICSPERFRAME) << 3; + int day = (sintable[sprite[i].ang & 2047] * TICSPERFRAME) << 3; + // checkspeed(i, speed); + checksight(plr, i); + if (!checkdist(plr, i)) { + // checkmove(i, checksight_x, checksight_y); + checkmove(i, dax, day); + } + else { + if (plr.invisibletime < 0) { + if (krand() % 8 == 0) { // NEW + if (plr.z < spr.z) + newstatus(i, ATTACK2); + else + newstatus(i, ATTACK); + } + else { // NEW + newstatus(i, FACE); // NEW + } + } + } + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + if (spr.picnum == DRAGONDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +static void cast(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 12; + } + + switch (spr.picnum) { + case DRAGONATTACK + 17: + case DRAGONATTACK + 4: + if ((krand() % 2) != 0) + playsound_loc(S_FLAME1, spr.x, spr.y); + else + playsound_loc(S_FIREBALL, spr.x, spr.y); + + firebreath(plr, i, 1, 2, LOW); + break; + case DRAGONATTACK + 18: + case DRAGONATTACK + 5: + if ((krand() % 2) != 0) + playsound_loc(S_FLAME1, spr.x, spr.y); + else + playsound_loc(S_FIREBALL, spr.x, spr.y); + + firebreath(plr, i, 2, 1, LOW); + break; + case DRAGONATTACK + 19: + case DRAGONATTACK + 6: + if ((krand() % 2) != 0) + playsound_loc(S_FLAME1, spr.x, spr.y); + else + playsound_loc(S_FIREBALL, spr.x, spr.y); + + firebreath(plr, i, 4, 0, LOW); + break; + case DRAGONATTACK + 20: + case DRAGONATTACK + 7: + firebreath(plr, i, 2, -1, LOW); + break; + case DRAGONATTACK + 21: + case DRAGONATTACK + 8: + firebreath(plr, i, 1, -2, LOW); + break; + + case DRAGONATTACK2 + 2: + if ((krand() % 2) != 0) + playsound_loc(S_FLAME1, spr.x, spr.y); + else + playsound_loc(S_FIREBALL, spr.x, spr.y); + + firebreath(plr, i, 1, -1, HIGH); + break; + case DRAGONATTACK2 + 3: + firebreath(plr, i, 2, 0, HIGH); + break; + + case DRAGONATTACK2 + 5: + spr.picnum = DRAGON; + newstatus(i, CHASE); + break; + case DRAGONATTACK + 22: + spr.picnum = DRAGONATTACK; + newstatus(i, CHASE); + break; + } + + checksector6(i); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum)) + newstatus(i, CAST); + else + newstatus(i, CHASE); + } + else + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + spr.picnum = DRAGON; + spr.hitag = (short)adjusthp(900); + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, true); + checksector6(i); +} + +static void frozen(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.pal = 0; + spr.picnum = DRAGON; + newstatus(i, FACE); + } +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 24; + if (spr.picnum == DRAGONCHAR + 4) { + trailingsmoke(i, false); + deletesprite(i); + } + } +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); +} + + +void dragonProcess(PLAYER& plr) +{ + for (short i = headspritestat[ATTACK2], nextsprite; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE& spr = sprite[i]; + + switch (spr.detail) { + case DRAGON: + dragonAttack2(plr, i); + break; + } + } +} + +static void dragonAttack2(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) + newstatus(i, CAST); + else + newstatus(i, CHASE); + return; + } + else + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + + checksector6(i); +} + +void dragonProcess(PLAYER& plr) +{ + for (short i = headspritestat[ATTACK2], nextsprite; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE& spr = sprite[i]; + + switch (spr.detail) { + case DRAGON: + dragonAttack2(plr, i); + break; + } + } +} + +static void dragonAttack2(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) + newstatus(i, CAST); + else + newstatus(i, CHASE); + return; + } + else + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + + checksector6(i); +} + +static void firebreath(PLAYER& plr, int i, int a, int b, int c) { + for (int k = 0; k <= a; k++) { + int j = insertsprite(sprite[i].sectnum, MISSILE); + if (j == -1) + return; + + sprite[j].x = sprite[i].x; + sprite[j].y = sprite[i].y; + if (c == LOW) + sprite[j].z = sector[sprite[i].sectnum].floorz - (32 << 8); + else + sprite[j].z = sector[sprite[i].sectnum].floorz - (tilesizy[sprite[i].picnum] << 7); + sprite[j].cstat = 0; + sprite[j].picnum = MONSTERBALL; + sprite[j].shade = -15; + sprite[j].xrepeat = 128; + sprite[j].yrepeat = 128; + sprite[j].ang = (short)((((getangle(plr.x - sprite[j].x, plr.y - sprite[j].y) + + (krand() & 15) - 8) + 2048) + ((b * 22) + (k * 10))) & 2047); + sprite[j].xvel = (short)(sintable[(sprite[j].ang + 2560) & 2047] >> 6); + sprite[j].yvel = (short)(sintable[(sprite[j].ang + 2048) & 2047] >> 6); + int discrim = ksqrt( + (plr.x - sprite[j].x) * (plr.x - sprite[j].x) + (plr.y - sprite[j].y) * (plr.y - sprite[j].y)); + if (discrim == 0) + discrim = 1; + if (c == HIGH) + sprite[j].zvel = (short)(((plr.z + (32 << 8) - sprite[j].z) << 7) / discrim); + else + sprite[j].zvel = (short)((((plr.z + (8 << 8)) - sprite[j].z) << 7) / discrim);// NEW + + sprite[j].owner = (short)i; + sprite[j].clipdist = 16; + sprite[j].lotag = 512; + sprite[j].hitag = 0; + } +} + +static void checkspeed(int i, int speed) { + checksight_x = (sintable[(sprite[i].ang + 512) & 2047] >> speed); + checksight_y = (sintable[sprite[i].ang & 2047] >> speed); +} + + +void createDragonAI() { + auto& e = enemy[DRAGONTYPE]; + e.info.Init(54, 54, 512, 120, 0, 128, false, 900, 0); + e.chase = chase; + e.flee = flee; + e.die = die; + e.cast = cast; + e.attack = attack; + e.resurect = resurect; + e.search = search; + e.frozen = frozen; + e.nuked = nuked; + e.pain = pain; + e.face = face; +} + +void premapDragon(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = DRAGONTYPE; + changespritestat(i, FACE); + enemy[DRAGONTYPE].info.set(spr); +} diff --git a/source/games/whaven/src/aifatwitch.cpp b/source/games/whaven/src/aifatwitch.cpp new file mode 100644 index 000000000..d778567a3 --- /dev/null +++ b/source/games/whaven/src/aifatwitch.cpp @@ -0,0 +1,288 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + + if (krand() % 63 == 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum))// && invisibletime < 0) + newstatus(i, ATTACK); + } + else { + checksight(plr, i); + if (!checkdist(i, plr.x, plr.y, plr.z)) { + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + } + else { + if (krand() % 8 == 0) // NEW + newstatus(i, ATTACK); // NEW + else { // NEW + sprite[i].ang = (short)(((krand() & 512 - 256) + sprite[i].ang + 1024) & 2047); // NEW + newstatus(i, FLEE); // NEW + } + } + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + spr.picnum = FATWITCH; + spr.hitag = (short)adjusthp(90); + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + checksector6(i); +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 24; + if (spr.picnum == FATWITCHCHAR + 4) { + trailingsmoke(i, false); + deletesprite(i); + } + } +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = FATWITCH; + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(i, plr.x, plr.y, plr.z)) + newstatus(i, ATTACK); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + sprite[i].lotag -= TICSPERFRAME; + if (sprite[i].lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum)) + newstatus(i, CAST); + else + newstatus(i, CHASE); + } + else + sprite[i].ang = getangle(plr.x - sprite[i].x, plr.y - sprite[i].y); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void cast(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 12; + } + + if (spr.picnum == FATWITCHATTACK + 3) { + sprite[i].picnum = FATWITCH; + throwspank(plr, i); + newstatus(i, CHASE); + } + checksector6(i); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == FATWITCHDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + + +void throwspank(PLAYER& plr, int i) { + int j = insertsprite(sprite[i].sectnum, MISSILE); + if (j == -1) + return; + playsound_loc(S_WITCHTHROW, sprite[i].x, sprite[i].y); + + sprite[j].x = sprite[i].x; + sprite[j].y = sprite[i].y; + sprite[j].z = sector[sprite[i].sectnum].floorz - ((tilesizy[sprite[i].picnum] >> 1) << 8); + sprite[j].cstat = 0; // Hitscan does not hit other bullets + sprite[j].picnum = FATSPANK; + sprite[j].shade = -15; + sprite[j].xrepeat = 64; + sprite[j].yrepeat = 64; + sprite[j].ang = (short)(((getangle(plr.x - sprite[j].x, plr.y - sprite[j].y) + (krand() & 15) + - 8) + 2048) & 2047); + sprite[j].xvel = (short)(sintable[(sprite[j].ang + 2560) & 2047] >> 6); + sprite[j].yvel = (short)(sintable[(sprite[j].ang + 2048) & 2047] >> 6); + long discrim = ksqrt((plr.x - sprite[j].x) * (plr.x - sprite[j].x) + (plr.y - sprite[j].y) * (plr.y - sprite[j].y)); + if (discrim == 0) + discrim = 1; + sprite[j].zvel = (short)(((plr.z + (48 << 8) - sprite[j].z) << 7) / discrim); + sprite[j].owner = (short)i; + sprite[j].clipdist = 16; + sprite[j].lotag = 512; + sprite[j].hitag = 0; + sprite[j].pal = 0; +} + +void createFatwitchAI() { + auto& e = enemy[FATWITCHTYPE]; + e.info.Init(32, 32, 2048, 120, 0, 64, false, 280, 0); + e.chase = chase; + e.resurect = resurect; + e.search = search; + e.nuked = nuked; + e.pain = pain; + e.face = face; + e.attack = attack; + e.flee = flee; + e.cast = cast; + e.die = die; +} + +void premapFatwitch(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = FATWITCHTYPE; + changespritestat(i, FACE); + enemy[FATWITCHTYPE].info.set(spr); + if (spr.pal == 7) + spr.hitag = (short)adjusthp(290); + if (krand() % 100 > 50) + spr.extra = 1; + +} + +END_WH_NS diff --git a/source/games/whaven/src/aifish.cpp b/source/games/whaven/src/aifish.cpp new file mode 100644 index 000000000..1328c1503 --- /dev/null +++ b/source/games/whaven/src/aifish.cpp @@ -0,0 +1,196 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + if (checkdist(plr, i)) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, ATTACK); + } + else if (krand() % 63 > 60) { + spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + int movestat = aimove(i); + + if ((movestat & kHitTypeMask) == kHitSprite) { + if ((movestat & kHitIndexMask) != plr.spritenum) { + short daang = (short)((spr.ang - 256) & 2047); + spr.ang = daang; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, SKIRMISH); + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, SKIRMISH); + } + } + } + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } +} + +static void die(PLAYER& plr, short i) { + deletesprite(i); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.z = sector[sprite[i].sectnum].floorz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + sprite[i].hitag--; + if (sprite[i].hitag < 0) + newstatus(i, DIE); + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + if (spr.lotag >= 64) { + if (checksight(plr, i)) + if (checkdist(plr, i)) { + spr.ang = (short)checksight_ang; + attack(plr, i); + } + } + else if (spr.lotag < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } + spr.lotag -= TICSPERFRAME; + + checksector6(i); +} + +static void skirmish(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + + if (spr.lotag < 0) + newstatus(i, FACE); + short osectnum = spr.sectnum; + if (aimove(i) != 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + if (checksector6(i)) + return; +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + checksector6(i); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047); + + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); +} + +void createFishAI() { + auto &e = enemy[FISHTYPE]; + e.info.Init(1, 1, 512, 120, 0, 32, false, 10, 0); + e.chase = chase; + e.die = die; + e.attack = attack; + e.skirmish = skirmish; + e.search = search; + e.face = face; +} + +void premapFish(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = FISHTYPE; + changespritestat(i, FACE); + enemy[FISHTYPE].info.set(spr); +} + +END_WH_NS diff --git a/source/games/whaven/src/aifred.cpp b/source/games/whaven/src/aifred.cpp new file mode 100644 index 000000000..76736ddc4 --- /dev/null +++ b/source/games/whaven/src/aifred.cpp @@ -0,0 +1,332 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void checkexpl(PLAYER& plr, short i); + + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + if (checkdist(plr, i)) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, ATTACK); + } + else if (krand() % 63 > 60) { + spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + int movestat = aimove(i); + + if ((movestat & kHitTypeMask) == kHitSprite) { + if ((movestat & kHitIndexMask) != plr.spritenum) { + short daang = (short)((spr.ang - 256) & 2047); + spr.ang = daang; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, SKIRMISH); + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, SKIRMISH); + } + } + } + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + checkexpl(plr, i); +} + +static void skirmish(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + + if (spr.lotag < 0) + newstatus(i, FACE); + short osectnum = spr.sectnum; + if (aimove(i) != 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + if (checksector6(i)) + return; + + checkexpl(plr, i); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == FREDDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + if (!checksector6(i)) + checkexpl(plr, i); +} + +static void frozen(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.pal = 0; + spr.picnum = FRED; + newstatus(i, FACE); + } +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047); + + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); + + checkexpl(plr, i); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + sprite[i].hitag--; + if (sprite[i].hitag < 0) + newstatus(i, DIE); + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + if (spr.lotag >= 64) { + if (checksight(plr, i)) + if (checkdist(plr, i)) { + spr.ang = (short)checksight_ang; + attack(plr, i); + } + } + else if (spr.lotag < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } + spr.lotag -= TICSPERFRAME; + + checksector6(i); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + + if (movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = FRED; + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + spr.picnum = FRED; + spr.hitag = (short)adjusthp(40); + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void checkexpl(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + short j = headspritesect[spr.sectnum]; + while (j != -1) { + short nextj = nextspritesect[j]; + long dx = klabs(spr.x - sprite[j].x); // x distance to sprite + long dy = klabs(spr.y - sprite[j].y); // y distance to sprite + long dz = klabs((spr.z >> 8) - (sprite[j].z >> 8)); // z distance to sprite + long dh = tilesizy[sprite[j].picnum] >> 1; // height of sprite + if (dx + dy < PICKDISTANCE && dz - dh <= getPickHeight()) { + if (sprite[j].picnum == EXPLO2 + || sprite[j].picnum == SMOKEFX + || sprite[j].picnum == MONSTERBALL) { + spr.hitag -= TICSPERFRAME << 2; + if (spr.hitag < 0) { + newstatus(i, DIE); + } + } + } + j = nextj; + } +} + +void createFredAI() { + auto &e = enemy[FREDTYPE]; + e.info.Init(48, 48, 1024 + 256, 120, 0, 64, false, 40, 0); + e.chase = chase; + e.skirmish = skirmish; + e.die = die; + e.search = search; + e.frozen = frozen; + e.face = face; + e.attack = attack; + e.flee = flee; + e.pain = pain; + e.resurect = resurect; +} + + +void premapFred(short i) { + SPRITE& spr = sprite[i]; + if (spr.picnum == FRED && spr.pal == 1) { + deletesprite(i); + return; + } + spr.detail = FREDTYPE; + changespritestat(i, FACE); + enemy[FREDTYPE].info.set(spr); + + if (krand() % 100 > 50) + spr.extra = 1; +} + +END_WH_NS diff --git a/source/games/whaven/src/aigoblin.cpp b/source/games/whaven/src/aigoblin.cpp new file mode 100644 index 000000000..52ba88876 --- /dev/null +++ b/source/games/whaven/src/aigoblin.cpp @@ -0,0 +1,581 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void checkexpl(PLAYER& plr, short i); + + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + if (checkdist(plr, i)) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, ATTACK); + } + else if (krand() % 63 > 60) { + spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + + if ((movestat & kHitTypeMask) == kHitSprite) { + if ((movestat & kHitIndexMask) != plr.spritenum) { + short daang = (short)((spr.ang - 256) & 2047); + spr.ang = daang; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, SKIRMISH); + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, SKIRMISH); + } + } + } + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + checkexpl(plr, i); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == GOBLINDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = GOBLIN; + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + spr.picnum = GOBLIN; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); + + checkexpl(plr, i); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void stand(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + if (sintable[(spr.ang + 2560) & 2047] * (plr.x - spr.x) + + sintable[(spr.ang + 2048) & 2047] * (plr.y - spr.y) >= 0) + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + switch (spr.picnum) { + case GOBLINCHILL: + spr.picnum = GOBLINSURPRISE; + playsound_loc(S_GOBPAIN1 + (krand() % 2), spr.x, spr.y); + newstatus(i, CHILL); + break; + default: + spr.picnum = GOBLIN; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + break; + } + } + + checksector6(i); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + sprite[i].hitag--; + if (sprite[i].hitag < 0) + newstatus(i, DIE); + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + if (spr.lotag == 31) { + if (checksight(plr, i)) + if (checkdist(plr, i)) { + spr.ang = (short)checksight_ang; + attack(plr, i); + } + } + else if (spr.lotag < 0) { + spr.picnum = GOBLIN; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } + spr.lotag -= TICSPERFRAME; + + checksector6(i); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + spr.picnum = GOBLIN; + spr.hitag = (short)adjusthp(35); + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + if (!checksector6(i)) + checkexpl(plr, i); +} + +static void frozen(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.pal = 0; + spr.picnum = GOBLIN; + newstatus(i, FACE); + } +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 24; + if (spr.picnum == GOBLINCHAR + 4) { + trailingsmoke(i, false); + deletesprite(i); + } + } +} + +static void skirmish(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + + if (spr.lotag < 0) + newstatus(i, FACE); + short osectnum = spr.sectnum; + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + if (checksector6(i)) + return; + + checkexpl(plr, i); +} + +void goblinChill(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 18; + if (spr.picnum == GOBLINSURPRISE + 5) { + spr.picnum = GOBLIN; + newstatus(i, FACE); + } + } +} + +static void goblinWar(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + short k; + + if (spr.lotag > 256) { + spr.lotag = 100; + spr.extra = 0; + } + + switch (spr.extra) { + case 0: // find new target + long olddist = 1024 << 4; + boolean found = false; + for (k = 0; k < MAXSPRITES; k++) { + if (sprite[k].picnum == GOBLIN && spr.pal != sprite[k].pal && spr.hitag == sprite[k].hitag) { + long dist = klabs(spr.x - sprite[k].x) + klabs(spr.y - sprite[k].y); + if (dist < olddist) { + found = true; + olddist = dist; + spr.owner = k; + spr.ang = getangle(sprite[k].x - spr.x, sprite[k].y - spr.y); + spr.extra = 1; + } + } + } + if (!found) { + if (spr.pal == 5) + spr.hitag = (short)adjusthp(35); + else if (spr.pal == 4) + spr.hitag = (short)adjusthp(25); + else + spr.hitag = (short)adjusthp(15); + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, FACE); + } + break; + case 1: // chase + k = spr.owner; + + int movehit = aimove(i); + if (movehit == 0) + spr.ang = getangle(sprite[k].x - spr.x, sprite[k].y - spr.y); + else if ((movehit & kHitTypeMask) == kHitWall) { + spr.extra = 3; + spr.ang = (short)((spr.ang + (krand() & 256 - 128)) & 2047); + spr.lotag = 60; + } + else if ((movehit & kHitTypeMask) == kHitSprite) { + int sprnum = movehit & kHitIndexMask; + if (sprnum != k) { + spr.extra = 3; + spr.ang = (short)((spr.ang + (krand() & 256 - 128)) & 2047); + spr.lotag = 60; + } + else spr.ang = getangle(sprite[k].x - spr.x, sprite[k].y - spr.y); + } + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + if (checkdist(i, sprite[k].x, sprite[k].y, sprite[k].z)) { + spr.extra = 2; + } + else + spr.picnum = GOBLIN; + + if (checksector6(i)) + return; + + break; + case 2: // attack + k = spr.owner; + if (checkdist(i, sprite[k].x, sprite[k].y, sprite[k].z)) { + if ((krand() & 1) != 0) { + // goblins are fighting + // JSA_DEMO + if (krand() % 10 > 6) + playsound_loc(S_GENSWING, spr.x, spr.y); + if (krand() % 10 > 6) + playsound_loc(S_SWORD1 + (krand() % 6), spr.x, spr.y); + + if (checkdist(plr, i)) + addhealth(plr, -(krand() & 5)); + + if (krand() % 100 > 90) { // if k is dead + spr.extra = 0; // needs to + spr.picnum = GOBLIN; + sprite[k].extra = 4; + sprite[k].picnum = GOBLINDIE; + sprite[k].lotag = 20; + sprite[k].hitag = 0; + newstatus(k, DIE); + } + else { // i attack k flee + spr.extra = 0; + sprite[k].extra = 3; + sprite[k].ang = (short)((spr.ang + (krand() & 256 - 128)) & 2047); + sprite[k].lotag = 60; + } + } + } + else { + spr.extra = 1; + } + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + if (checksector6(i)) + return; + + break; + case 3: // flee + spr.lotag -= TICSPERFRAME; + + if (aimove(i) != 0) + spr.ang = (short)(krand() & 2047); + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + if (spr.lotag < 0) { + spr.lotag = 0; + spr.extra = 0; + } + + if (checksector6(i)) + return; + + break; + case 4: // pain + spr.picnum = GOBLINDIE; + break; + case 5: // cast + break; + } + + checkexpl(plr, i); +} + +void goblinWarProcess(PLAYER& plr) +{ + for (short i = headspritestat[WAR], nextsprite; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE& spr = sprite[i]; + switch (spr.detail) { + case GOBLINTYPE: + goblinWar(plr, i); + break; + } + } +} + +static void checkexpl(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + short j = headspritesect[spr.sectnum]; + while (j != -1) { + short nextj = nextspritesect[j]; + long dx = klabs(spr.x - sprite[j].x); // x distance to sprite + long dy = klabs(spr.y - sprite[j].y); // y distance to sprite + long dz = klabs((spr.z >> 8) - (sprite[j].z >> 8)); // z distance to sprite + long dh = tilesizy[sprite[j].picnum] >> 1; // height of sprite + if (dx + dy < PICKDISTANCE && dz - dh <= getPickHeight()) { + if (sprite[j].picnum == EXPLO2 + || sprite[j].picnum == SMOKEFX + || sprite[j].picnum == MONSTERBALL) { + spr.hitag -= TICSPERFRAME << 2; + if (spr.hitag < 0) { + newstatus(i, DIE); + } + } + } + j = nextj; + } +} + +void createGoblinAI() { + auto& e = enemy[GOBLINTYPE]; + e.info.Init(36, 36, 1024, 120, 0, 64, false, 15, 0); + e.chase = chase; + e.die = die; + e.pain = pain; + e.face = face; + e.flee = flee; + e.stand = stand; + e.attack = attack; + e.resurect = resurect; + e.search = search; + e.frozen = frozen; + e.nuked = nuked; + e.skirmish = skirmish; + e.info.getHealth = [](EnemyInfo& e, SPRITE& spr) + { + if (spr.pal == 5) + return adjusthp(35); + else if (spr.pal == 4) + return adjusthp(25); + + return adjusthp(e.health); + }; +} + + +void premapGoblin(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = GOBLINTYPE; + + if (spr.hitag < 90 || spr.hitag > 99) + enemy[GOBLINTYPE].info.set(spr); + else { + short ohitag = spr.hitag; + enemy[GOBLINTYPE].info.set(spr); + if (spr.pal != 0) + spr.xrepeat = 30; + spr.extra = 0; + spr.owner = 0; + spr.hitag = ohitag; + return; + } + + if (spr.picnum == GOBLINCHILL) { + changespritestat(i, STAND); + spr.lotag = 30; + if (krand() % 100 > 50) + spr.extra = 1; + return; + } + + changespritestat(i, FACE); + if (krand() % 100 > 50) + spr.extra = 1; +} + +END_WH_NS diff --git a/source/games/whaven/src/aigonzo.cpp b/source/games/whaven/src/aigonzo.cpp new file mode 100644 index 000000000..3ff78b177 --- /dev/null +++ b/source/games/whaven/src/aigonzo.cpp @@ -0,0 +1,783 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void gonzopike(short s, PLAYER& plr); +static void checkexpl(PLAYER& plr, short i); +static boolean patrolprocess(PLAYER& plr, short i); + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + + switch (spr.picnum) { + case GONZOGHM: + case GONZOGSH: + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + if (checkdist(plr, i)) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + newstatus(i, ATTACK); + } + break; + } + else if ((krand() & 0) == 1) { + spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + if (krand() % 63 > 60) { + spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + break; + } + + int dax = spr.x; // Back up old x&y if stepping off cliff + int day = spr.y; + int daz = spr.z; + + osectnum = spr.sectnum; + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + + if (zr_florz > spr.z + (48 << 8)) { + spr.x = dax; + spr.y = day; + spr.z = daz; + setsprite(i, spr.x, spr.y, spr.z); + movestat = 1; + + if (rand() % 100 > 80 && sector[plr.sector].lotag == 25) { + newstatus(i, AMBUSH); + sprite[i].z -= (getPlayerHeight() << 6); + sprite[i].lotag = 60; + sprite[i].extra = 1; + sprite[i].picnum = GONZOHMJUMP; + return; + + } + + } + + if ((movestat & 0xc000) == 32768 && sector[plr.sector].lotag == 25) { + newstatus(i, AMBUSH); + sprite[i].z -= (getPlayerHeight() << 6); + sprite[i].lotag = 90; + sprite[i].extra = 3; + sprite[i].picnum = GONZOHMJUMP; + return; + } + + if (movestat != 0) { + if ((movestat & 4095) != plr.spritenum) { + int daang; + if ((krand() & 0) == 1) + daang = (spr.ang + 256) & 2047; + else + daang = (spr.ang - 256) & 2047; + spr.ang = (short)daang; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + newstatus(i, SKIRMISH); + } + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, SKIRMISH); + } + } + break; + } + else { + if (!patrolprocess(plr, i)) + newstatus(i, FLEE); + } + break; + case GONZOCSW: + case GONZOGSW: + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + if (checkdist(plr, i)) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, ATTACK); + } + else if (krand() % 63 > 60) { + spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + + if ((movestat & kHitTypeMask) == kHitSprite) { + if ((movestat & kHitIndexMask) != plr.spritenum) { + short daang = (short)((spr.ang - 256) & 2047); + spr.ang = daang; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, SKIRMISH); + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, SKIRMISH); + } + } + } + } + else { + if (!patrolprocess(plr, i)) + newstatus(i, FLEE); + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + } + + checkexpl(plr, i); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + switch (spr.picnum) { + case GONZOCSWDEAD: + spr.picnum = GONZOCSW; + spr.hitag = (short)adjusthp(50); + break; + case GONZOGSWDEAD: + spr.picnum = GONZOGSW; + spr.hitag = (short)adjusthp(100); + break; + case GONZOGHMDEAD: + spr.picnum = GONZOGHM; + spr.hitag = (short)adjusthp(40); + break; + case GONZOGSHDEAD: + spr.picnum = GONZOGSH; + spr.hitag = (short)adjusthp(50); + break; + } + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void skirmish(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + + if (spr.lotag < 0) + newstatus(i, FACE); + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + if (checksector6(i)) + return; + + checkexpl(plr, i); +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + if (!checksector6(i)) + checkexpl(plr, i); +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + chunksofmeat(plr, i, spr.x, spr.y, spr.z, spr.sectnum, spr.ang); + trailingsmoke(i, false); + newstatus(i, DIE); +} + +static void frozen(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.pal = 0; + switch (sprite[i].picnum) { + case GONZOCSWPAIN: + spr.picnum = GONZOCSW; + break; + case GONZOGSWPAIN: + spr.picnum = GONZOGSW; + break; + case GONZOGHMPAIN: + spr.picnum = GONZOGHM; + break; + case GONZOGSHPAIN: + spr.picnum = GONZOGSH; + break; + } + newstatus(i, FACE); + } +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + switch (sprite[i].picnum) { + case GONZOCSWPAIN: + spr.picnum = GONZOCSW; + break; + case GONZOGSWPAIN: + spr.picnum = GONZOGSW; + break; + case GONZOGHMPAIN: + spr.picnum = GONZOGHM; + break; + case GONZOGSHPAIN: + spr.picnum = GONZOGSH; + break; + } + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047); + + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (plr.invisibletime < 0 && checkdist(plr, i)) + newstatus(i, ATTACK); + + checkexpl(plr, i); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + switch (spr.picnum) { + // WANGO + case KURTREADY: + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 24; + } + break; + case KURTREADY + 1: + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = KURTAT; + spr.lotag = 64; + } + break; + case KURTAT: + case KURTPUNCH: + if (spr.lotag == 46) { + if (checksight(plr, i)) + if (checkdist(plr, i)) { + spr.ang = (short)checksight_ang; + attack(plr, i); + } + } + else if (spr.lotag < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } + spr.lotag -= TICSPERFRAME; + break; + case GONZOCSWAT: + sprite[i].lotag -= TICSPERFRAME; + if (sprite[i].lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum)) + newstatus(i, CAST); + else + newstatus(i, CHASE); + } + else + sprite[i].ang = getangle(plr.x - sprite[i].x, plr.y - sprite[i].y); + break; + case GONZOGSWAT: + case GONZOGHMAT: + case GONZOGSHAT: + if (spr.lotag == 31) { + if (checksight(plr, i)) + if (checkdist(plr, i)) { + spr.ang = (short)checksight_ang; + attack(plr, i); + } + } + else if (spr.lotag < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } + spr.lotag -= TICSPERFRAME; + break; + } + + checksector6(i); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + if (plr.invisibletime < 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void cast(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 12; + } + + if (spr.picnum == GONZOCSWAT) { + spr.extra--; + playsound_loc(S_GENTHROW, spr.x, spr.y); + gonzopike(i, plr); + newstatus(i, CHASE); + } +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + switch (sprite[i].picnum) { + case GONZOBSHDEAD: + case GONZOCSWDEAD: + case GONZOGSWDEAD: + case GONZOGHMDEAD: + case GONZOGSHDEAD: + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + break; + } + } +} + +void gonzoProcess(PLAYER& plr) +{ + short nextsprite; + for (short i = headspritestat[LAND]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.lotag = 12; + spr.picnum++; + } + + switch (spr.picnum) { + case GONZOHMJUMPEND: + spr.picnum = GONZOGSH; + spr.detail = GONZOTYPE; + enemy[GONZOTYPE].info.set(spr); + sprite[i].hitag = adjusthp(100); + newstatus(i, FACE); + break; + case GONZOSHJUMPEND: + spr.picnum = GONZOGSH; + spr.detail = GONZOTYPE; + enemy[GONZOTYPE].info.set(spr); + sprite[i].hitag = adjusthp(100); + newstatus(i, FACE); + break; + } + } + + short movestat; + for (short i = headspritestat[AMBUSH]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + + SPRITE& spr = sprite[i]; + switch (spr.extra) { + case 1: // forward + spr.zvel += TICSPERFRAME << 3; + + movestat = (short)movesprite(i, ((sintable[(spr.ang + 512) & 2047]) * TICSPERFRAME) << 3, + ((sintable[spr.ang]) * TICSPERFRAME) << 3, spr.zvel, 4 << 8, 4 << 8, 0); + + spr.lotag -= TICSPERFRAME; + + if (zr_florz <= spr.z && spr.lotag < 0) { + spr.z = zr_florz; + changespritestat(i, LAND); + } + + if ((movestat & 0xc000) == 49152) { // Bullet hit a sprite + int k = (movestat & 4095); + for (int j = 0; j < 15; j++) { + shards(k, 1); + } + damageactor(plr, movestat, i); + } + + break; + case 2: // fall + spr.zvel += TICSPERFRAME << 4; + + movestat = (short)movesprite(i, ((sintable[(spr.ang + 512) & 2047]) * TICSPERFRAME) << 1, + ((sintable[spr.ang]) * TICSPERFRAME) << 1, spr.zvel, 4 << 8, 4 << 8, 0); + + spr.lotag -= TICSPERFRAME; + + if (zr_florz <= spr.z && spr.lotag < 0) { + spr.z = zr_florz; + changespritestat(i, LAND); + } + + break; + case 3: // jumpup + + spr.zvel -= TICSPERFRAME << 4; + + movestat = (short)movesprite(i, ((sintable[(spr.ang + 512) & 2047]) * TICSPERFRAME) << 3, + ((sintable[spr.ang]) * TICSPERFRAME) << 3, spr.zvel, 4 << 8, 4 << 8, 0); + + spr.lotag -= TICSPERFRAME; + + setsprite(i, spr.x, spr.y, spr.z); + + if (spr.lotag < 0) { + spr.extra = 2; + spr.lotag = 20; + } + + break; + } + } +} + +static short searchpatrol(SPRITE& spr) { + long mindist = 0x7fffffff; + short target = -1; + short j = headspritestat[APATROLPOINT]; + while (j != -1) { + short nextj = nextspritestat[j]; + SPRITE tspr = sprite[j]; + long dist = klabs(tspr.x - spr.x) + klabs(tspr.y - spr.y); + if (dist < mindist) { + mindist = dist; + target = j; + } + j = nextj; + } + + return target; +} + +static boolean patrolprocess(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + short target = searchpatrol(spr); + if (target != -1) { + SPRITE tspr = sprite[target]; + if (cansee(tspr.x, tspr.y, tspr.z, tspr.sectnum, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum)) { + spr.ang = getangle(tspr.x - spr.x, tspr.y - spr.y); + newstatus(i, PATROL); + } + } + + return target != -1; +} + +static void gonzopike(short s, PLAYER& plr) { + int j = insertsprite(sprite[s].sectnum, JAVLIN); + if (j == -1) + return; + + SPRITE& spr = sprite[j]; + + spr.x = sprite[s].x; + spr.y = sprite[s].y; + spr.z = sprite[s].z - (40 << 8); + + spr.cstat = 21; + spr.picnum = THROWPIKE; + spr.ang = (short)(((sprite[s].ang + 2048 + 96) - 512) & 2047); + spr.xrepeat = 24; + spr.yrepeat = 24; + spr.clipdist = 32; + + spr.extra = sprite[s].ang; + spr.shade = -15; + spr.xvel = (short)((krand() & 256) - 128); + spr.yvel = (short)((krand() & 256) - 128); + + spr.zvel = (short)(((plr.z + (8 << 8) - sprite[s].z) << 7) / engine + .ksqrt((plr.x - sprite[s].x) * (plr.x - sprite[s].x) + (plr.y - sprite[s].y) * (plr.y - sprite[s].y))); + + spr.zvel += ((krand() % 256) - 128); + + spr.owner = s; + spr.lotag = 1024; + spr.hitag = 0; + spr.pal = 0; + +} + +static void checkexpl(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + short j = headspritesect[spr.sectnum]; + while (j != -1) { + short nextj = nextspritesect[j]; + long dx = klabs(spr.x - sprite[j].x); // x distance to sprite + long dy = klabs(spr.y - sprite[j].y); // y distance to sprite + long dz = klabs((spr.z >> 8) - (sprite[j].z >> 8)); // z distance to sprite + long dh = tilesizy[sprite[j].picnum] >> 1; // height of sprite + if (dx + dy < PICKDISTANCE && dz - dh <= getPickHeight()) { + if (sprite[j].picnum == EXPLO2 + || sprite[j].picnum == MONSTERBALL) { + spr.hitag -= TICSPERFRAME << 2; + if (spr.hitag < 0) { + newstatus(i, DIE); + } + } + } + j = nextj; + } +} + +void createGonzoAI() { + auto &e = enemy[GONZOTYPE]; + e.info.Init(35, 35, 1024 + 256, 120, 0, 48, false, 50, 0); + e.info.getAttackDist = [](EnemyInfo& e, SPRITE& spr) + { + int out = e.attackdist; + switch (spr.picnum) { + case KURTAT: + case GONZOCSW: + case GONZOCSWAT: + if (spr.extra > 10) + out = 2048 << 1; + break; + } + + return out; + }; + + e.info.getHealth = [](EnemyInfo& e, SPRITE& spr) + { + switch (spr.picnum) { + case KURTAT: + return 10; + case KURTPUNCH: + return adjusthp(15); + case GONZOGSW: + return adjusthp(100); + case GONZOGHM: + return adjusthp(40); + } + + return adjusthp(e.health); + }; + e.chase = chase; + e.resurect = resurect; + e.skirmish = skirmish; + e.search = search; + e.nuked = nuked; + e.frozen = frozen; + e.pain = pain; + e.face = face; + e.attack = attack; + e.flee = flee; + e.cast = cast; + e.die = die; +} + + +void premapGonzo(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = GONZOTYPE; + enemy[GONZOTYPE].info.set(spr); + changespritestat(i, FACE); + + switch (spr.picnum) { + case KURTAT: + spr.picnum = GONZOCSW; + break; + case KURTPUNCH: + spr.extra = 0; + spr.picnum = GONZOCSW; + break; + case GONZOCSW: + spr.extra = 20; + break; + case GONZOGSW: + case GONZOGHM: + case GONZOGSH: + spr.clipdist = 32; + spr.extra = 0; + break; + } +} + +void deaddude(short sn) { + int j = insertsprite(sprite[sn].sectnum, DEAD); + sprite[j].x = sprite[sn].x; + sprite[j].y = sprite[sn].y; + sprite[j].z = sprite[sn].z; + sprite[j].cstat = 0; + sprite[j].picnum = GONZOBSHDEAD; + sprite[j].shade = sector[sprite[sn].sectnum].floorshade; + sprite[j].pal = 0; + sprite[j].xrepeat = sprite[sn].xrepeat; + sprite[j].yrepeat = sprite[sn].yrepeat; + sprite[j].owner = 0; + sprite[j].lotag = 0; + sprite[j].hitag = 0; +} + +END_WH_NS diff --git a/source/games/whaven/src/aigron.cpp b/source/games/whaven/src/aigron.cpp new file mode 100644 index 000000000..7ad1f5f24 --- /dev/null +++ b/source/games/whaven/src/aigron.cpp @@ -0,0 +1,529 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void checkexpl(PLAYER& plr, short i); +static void throwhalberd(int s); + + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + + if (spr.picnum == GRONSW) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + if (checkdist(plr, i)) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, ATTACK); + } + else if (krand() % 63 > 60) { + spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + + if ((movestat & kHitTypeMask) == kHitSprite) { + if ((movestat & kHitIndexMask) != plr.spritenum) { + short daang = (short)((spr.ang - 256) & 2047); + spr.ang = daang; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, SKIRMISH); + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, SKIRMISH); + } + } + } + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + } + else { + if (krand() % 63 == 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum))// && invisibletime < 0) + newstatus(i, ATTACK); + } + else { + checksight(plr, i); + if (!checkdist(plr, i)) { + if ((aimove(i) & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + } + else { + if (krand() % 8 == 0) // NEW + newstatus(i, ATTACK); // NEW + else { // NEW + sprite[i].ang = (short)(((krand() & 512 - 256) + sprite[i].ang + 1024) & 2047); // NEW + newstatus(i, FLEE); // NEW + } + } + } + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + checkexpl(plr, i); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + switch (krand() % 3) { + case 0: + sprite[i].picnum = GRONHAL; + sprite[i].hitag = (short)adjusthp(120); + sprite[i].extra = 3; + break; + case 1: + sprite[i].picnum = GRONSW; + sprite[i].hitag = (short)adjusthp(120); + sprite[i].extra = 0; + break; + case 2: + sprite[i].picnum = GRONMU; + sprite[i].hitag = (short)adjusthp(120); + sprite[i].extra = 2; + break; + } + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void skirmish(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + + if (spr.lotag < 0) + newstatus(i, FACE); + short osectnum = spr.sectnum; + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + if (checksector6(i)) + return; + + checkexpl(plr, i); +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + if (!checksector6(i)) + checkexpl(plr, i); +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + if (game.WH2) { + chunksofmeat(plr, i, spr.x, spr.y, spr.z, spr.sectnum, spr.ang); + trailingsmoke(i, false); + newstatus((short)i, DIE); + return; + } + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 24; + if (spr.picnum == GRONCHAR + 4) { + trailingsmoke(i, false); + deletesprite(i); + } + } +} + +static void frozen(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.pal = 0; + if (sprite[i].picnum == GRONHALDIE) + sprite[i].picnum = GRONHAL; + else if (sprite[i].picnum == GRONSWDIE) + sprite[i].picnum = GRONSW; + else if (sprite[i].picnum == GRONMUDIE) + sprite[i].picnum = GRONMU; + newstatus(i, FACE); + } +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + if (sprite[i].picnum == GRONHALPAIN) + sprite[i].picnum = GRONHAL; + else if (sprite[i].picnum == GRONSWPAIN) + sprite[i].picnum = GRONSW; + else if (sprite[i].picnum == GRONMUPAIN) + sprite[i].picnum = GRONMU; + + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047); + + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); + + checkexpl(plr, i); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + if (spr.picnum == GRONSWATTACK) { + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + sprite[i].hitag--; + if (sprite[i].hitag < 0) + newstatus(i, DIE); + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + if (spr.lotag == 31) { + if (checksight(plr, i)) + if (checkdist(plr, i)) { + spr.ang = (short)checksight_ang; + attack(plr, i); + } + } + else if (spr.lotag < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } + spr.lotag -= TICSPERFRAME; + } + else { + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + spr.z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum)) + newstatus(i, CAST); + else + newstatus(i, CHASE); + } + else + spr.ang = getangle(plr.x - sprite[i].x, plr.y - sprite[i].y); + } + + checksector6(i); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void cast(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + if (spr.picnum == GRONHALATTACK) { + spr.extra--; + playsound_loc(S_THROWPIKE, sprite[i].x, sprite[i].y); + throwhalberd(i); + newstatus(i, CHASE); + } + else if (spr.picnum == GRONMUATTACK) { + spr.extra--; + playsound_loc(S_SPELL2, sprite[i].x, sprite[i].y); + castspell(plr, i); + newstatus(i, CHASE); + } + } + + checksector6(i); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.picnum == GRONSWDIE || spr.picnum == GRONHALDIE || spr.picnum == GRONMUDIE) + { + if (spr.lotag < 0) { + spr.picnum = GRONDIE; + spr.lotag = 20; + } + else + return; + } + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == GRONDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +static void checkexpl(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + short j = headspritesect[spr.sectnum]; + while (j != -1) { + short nextj = nextspritesect[j]; + long dx = klabs(spr.x - sprite[j].x); // x distance to sprite + long dy = klabs(spr.y - sprite[j].y); // y distance to sprite + long dz = klabs((spr.z >> 8) - (sprite[j].z >> 8)); // z distance to sprite + long dh = tilesizy[sprite[j].picnum] >> 1; // height of sprite + if (dx + dy < PICKDISTANCE && dz - dh <= getPickHeight()) { + if (sprite[j].picnum == EXPLO2 + || sprite[j].picnum == MONSTERBALL) { + spr.hitag -= TICSPERFRAME << 2; + if (spr.hitag < 0) { + newstatus(i, DIE); + } + } + } + j = nextj; + } +} + +static void throwhalberd(int s) { + int j = insertsprite(sprite[s].sectnum, JAVLIN); + + if (j == -1) + return; + SPRITE& spr = sprite[j]; + spr.x = sprite[s].x; + spr.y = sprite[s].y; + spr.z = sprite[s].z - (40 << 8); + + spr.cstat = 17; + + spr.picnum = THROWHALBERD; + spr.detail = THROWHALBERDTYPE; + spr.ang = (short)(((sprite[s].ang + 2048) - 512) & 2047); + spr.xrepeat = 8; + spr.yrepeat = 16; + spr.clipdist = 32; + + spr.extra = sprite[s].ang; + spr.shade = -15; + spr.xvel = (short)((krand() & 256) - 128); + spr.yvel = (short)((krand() & 256) - 128); + spr.zvel = (short)((krand() & 256) - 128); + spr.owner = (short)s; + spr.lotag = 0; + spr.hitag = 0; + spr.pal = 0; + + spr.cstat = 0; + int daz = (((spr.zvel) * TICSPERFRAME) >> 3); + movesprite((short)j, ((sintable[(spr.extra + 512) & 2047]) * TICSPERFRAME) << 7, + ((sintable[spr.extra & 2047]) * TICSPERFRAME) << 7, daz, 4 << 8, 4 << 8, 1); + spr.cstat = 21; +} + +void createGronAI() { + auto& e = enemy[GRONTYPE]; + e.info.Init(game.WH2 ? 35 : 30, game.WH2 ? 35 : 30, -1, 120, 0, 64, false, 300, 0); + e.info.getAttackDist = [](EnemyInfo& e, SPRITE& spr) + { + int out = e.attackdist; + int pic = spr.picnum; + + if (pic == GRONHAL || pic == GRONHALATTACK) + out = 1024 + 512; + else if (pic == GRONMU || pic == GRONMUATTACK) + out = 2048; + else if (pic == GRONSW || pic == GRONSWATTACK) + out = 1024 + 256; + + return out; + }; + + e.info.getHealth = [](EnemyInfo& e, SPRITE& spr) + { + if (game.WH2) { + if (spr.picnum == GRONHAL) + return adjusthp(65); + if (spr.picnum == GRONMU) + return adjusthp(70); + } + return adjusthp(e.health); + }; + e.chase = chase; + e.resurect = resurect; + e.skirmish = skirmish; + e.search = search; + e.nuked = nuked; + e.frozen = frozen; + e.pain = pain; + e.face = face; + e.attack = attack; + e.flee = flee; + e.cast = cast; + e.die = die; +} + + +void premapGron(short i) { + SPRITE& spr = sprite[i]; + + if (spr.picnum == GRONSW && spr.pal == 10) + deletesprite(i); + + spr.detail = GRONTYPE; + enemy[GRONTYPE].info.set(spr); + changespritestat(i, FACE); + + if (spr.picnum == GRONHAL) + spr.extra = 4; + else if (spr.picnum == GRONSW) + spr.extra = 0; + else if (spr.picnum == GRONMU) + spr.extra = 2; +} + +END_WH_NS diff --git a/source/games/whaven/src/aiguardian.cpp b/source/games/whaven/src/aiguardian.cpp new file mode 100644 index 000000000..966de1c67 --- /dev/null +++ b/source/games/whaven/src/aiguardian.cpp @@ -0,0 +1,249 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + if (plr.z < spr.z) + spr.z -= TICSPERFRAME << 8; + if (plr.z > spr.z) + spr.z += TICSPERFRAME << 8; + + if (krand() % 63 == 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum) && plr.invisibletime < 0) + newstatus(i, ATTACK); + return; + } + else { + int dax = (sintable[(sprite[i].ang + 512) & 2047] * TICSPERFRAME) << 3; + int day = (sintable[sprite[i].ang & 2047] * TICSPERFRAME) << 3; + checksight(plr, i); + + if (totalclock % 100 > 70) + trailingsmoke(i, true); + + if (!checkdist(plr, i)) { + checkmove(i, dax, day); + } + else { + if (krand() % 8 == 0) // NEW + newstatus(i, ATTACK); // NEW + else { // NEW + sprite[i].ang = (short)(((krand() & 512 - 256) + sprite[i].ang + 1024) & 2047); // NEW + newstatus(i, CHASE); // NEW + } + } + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, true); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if (!isValidSector(spr.sectnum)) + return; + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + if (game.WH2) { + chunksofmeat(plr, i, spr.x, spr.y, spr.z, spr.sectnum, spr.ang); + trailingsmoke(i, false); + newstatus((short)i, DIE); + return; + } + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 24; + if (spr.picnum == GUARDIANCHAR + 4) { + trailingsmoke(i, false); + deletesprite(i); + } + } +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + if (plr.z < spr.z) { + spr.z -= TICSPERFRAME << 8; + } + if (plr.z > spr.z) { + spr.z += TICSPERFRAME << 8; + } + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum)) + newstatus(i, CAST); + else + newstatus(i, CHASE); + } + else + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047); + + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, true); + checksector6(i); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + if (totalclock % 100 > 70) + trailingsmoke(i, true); + + int movestat = aifly(i); + + if (movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, true); + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = GUARDIAN; + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + // aifly(i); + // setsprite(i, spr.x, spr.y, spr.z); +} + +static void cast(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + + if (plr.z < spr.z) { + spr.z -= TICSPERFRAME << 8; + } + if (plr.z > spr.z) { + spr.z += TICSPERFRAME << 8; + } + + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 12; + } + + if (spr.picnum == GUARDIANATTACK + 6) { + spr.picnum = GUARDIAN; + playsound_loc(S_FIREBALL, sprite[i].x, sprite[i].y); + castspell(plr, i); + newstatus(i, CHASE); + } + checksector6(i); +} + + +void createGuardianAI() { + auto& e = enemy[GUARDIANTYPE]; + e.info.Init(game.WH2 ? 35 : 32, game.WH2 ? 35 : 32, 4096, 120, 0, 64, true, game.WH2 ? 100 : 200, 0); + e.chase = chase; + e.nuked = nuked; + e.attack = attack; + e.face = face; + e.search = search; + e.flee = flee; + e.pain = pain; + e.cast = cast; +} + +void premapGuardian(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = GUARDIANTYPE; + enemy[GUARDIANTYPE].info.set(spr); + changespritestat(i, FACE); +} + +END_WH_NS diff --git a/source/games/whaven/src/aiimp.cpp b/source/games/whaven/src/aiimp.cpp new file mode 100644 index 000000000..fbf5d7aff --- /dev/null +++ b/source/games/whaven/src/aiimp.cpp @@ -0,0 +1,340 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void checkexpl(PLAYER& plr, short i); + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + if (checkdist(plr, i)) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, ATTACK); + } + else if (krand() % 63 > 60) { + spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + + if ((movestat & kHitTypeMask) == kHitSprite) { + if ((movestat & kHitIndexMask) != plr.spritenum) { + short daang = (short)((spr.ang - 256) & 2047); + spr.ang = daang; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, SKIRMISH); + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, SKIRMISH); + } + } + } + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + checkexpl(plr, i); +} + +static void frozen(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.pal = 0; + spr.picnum = IMP; + newstatus(i, FACE); + } +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = IMP; + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == IMPDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + chunksofmeat(plr, i, spr.x, spr.y, spr.z, spr.sectnum, spr.ang); + trailingsmoke(i, false); + newstatus((short)i, DIE); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + spr.picnum = IMP; + spr.hitag = (short)adjusthp(20); + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047); + + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); + + checkexpl(plr, i); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + sprite[i].hitag--; + if (sprite[i].hitag < 0) + newstatus(i, DIE); + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + if (spr.lotag == 32) { //original 64 + if (checksight(plr, i)) + if (checkdist(plr, i)) { + spr.ang = (short)checksight_ang; + attack(plr, i); + } + } + else if (spr.lotag < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } + spr.lotag -= TICSPERFRAME; + + checksector6(i); +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + if (!checksector6(i)) + checkexpl(plr, i); +} + +static void skirmish(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + + if (spr.lotag < 0) + newstatus(i, FACE); + short osectnum = spr.sectnum; + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + if (checksector6(i)) + return; + + checkexpl(plr, i); +} + +static void checkexpl(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + short j = headspritesect[spr.sectnum]; + while (j != -1) { + short nextj = nextspritesect[j]; + long dx = klabs(spr.x - sprite[j].x); // x distance to sprite + long dy = klabs(spr.y - sprite[j].y); // y distance to sprite + long dz = klabs((spr.z >> 8) - (sprite[j].z >> 8)); // z distance to sprite + long dh = tilesizy[sprite[j].picnum] >> 1; // height of sprite + if (dx + dy < PICKDISTANCE && dz - dh <= getPickHeight()) { + if (sprite[j].picnum == EXPLO2 + || sprite[j].picnum == SMOKEFX + || sprite[j].picnum == MONSTERBALL) { + spr.hitag -= TICSPERFRAME << 2; + if (spr.hitag < 0) { + newstatus(i, DIE); + } + } + } + j = nextj; + } +} + + void createImpAI() { + auto &e = enemy[IMPTYPE]; + e.info.Init(25, 25, 1024, 120, 0, 64, false, 20, 0); + e.chase = chase; + e.frozen = frozen; + e.pain = pain; + e.die = die; + e.nuked = nuked; + e.resurect = resurect; + e.face = face; + e.flee = flee; + e.attack = attack; + e.search = search; + e.skirmish = skirmish; + } + + + void premapImp(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = IMPTYPE; + enemy[IMPTYPE].info.set(spr); + changespritestat(i, FACE); + spr.shade = -4; + } +} +END_WH_NS diff --git a/source/games/whaven/src/aijudy.cpp b/source/games/whaven/src/aijudy.cpp new file mode 100644 index 000000000..6a72e94ef --- /dev/null +++ b/source/games/whaven/src/aijudy.cpp @@ -0,0 +1,423 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void spawnabaddy(int i, int monster); + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + + if (mapon < 24) { + sprite[i].extra -= TICSPERFRAME; + if (sprite[i].extra < 0) { + for (int j = 0; j < 8; j++) + trailingsmoke(i, true); + deletesprite((short)i); + return; + } + } + + if (krand() % 63 == 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum))// && invisibletime < 0) + newstatus(i, ATTACK); + } + else { + checksight(plr, i); + if (!checkdist(i, plr.x, plr.y, plr.z)) { + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + } + else { + if (krand() % 8 == 0) // NEW + newstatus(i, ATTACK); // NEW + else { // NEW + sprite[i].ang = (short)(((krand() & 512 - 256) + sprite[i].ang + 1024) & 2047); // NEW + newstatus(i, FLEE); // NEW + } + } + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + spr.picnum = JUDY; + spr.hitag = (short)adjusthp(200); + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + checksector6(i); +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 24; + if (spr.picnum == JUDYCHAR + 4) { + trailingsmoke(i, false); + deletesprite(i); + } + } +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = JUDY; + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(i, plr.x, plr.y, plr.z)) + newstatus(i, ATTACK); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + sprite[i].extra -= TICSPERFRAME; + sprite[i].lotag -= TICSPERFRAME; + if (sprite[i].lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum)) + newstatus(i, CAST); + else + newstatus(i, CHASE); + } + else + sprite[i].ang = getangle(plr.x - sprite[i].x, plr.y - sprite[i].y); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void cast(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 12; + } + + if (spr.picnum == JUDYATTACK1 + 3) { + sprite[i].picnum = JUDYATTACK1; + playsound_loc(S_JUDY1 + krand() % 4, sprite[i].x, sprite[i].y); + if (krand() % 100 > 70) { + castspell(plr, i); + } + else { + if (krand() % 100 > 40) { + // raise the dead + short j = headspritestat[DEAD]; + while (j >= 0) { + short nextj = nextspritestat[j]; + sprite[j].lotag = (short)((krand() % 120) + 120); + kills--; + newstatus(j, RESURECT); + j = nextj; + } + } + else { + if (krand() % 100 > 50) { + // curse + for (int j = 1; j < 9; j++) { + plr.ammo[j] = 3; + } + } + else { + int j = krand() % 5; + switch (j) { + case 0:// SPAWN WILLOW + spawnabaddy(i, WILLOW); + break; + case 1:// SPAWN 10 SPIDERS + for (j = 0; j < 4; j++) { + spawnabaddy(i, SPIDER); + } + break; + case 2:// SPAWN 2 GRONSW + for (j = 0; j < 2; j++) { + spawnabaddy(i, GRONSW); + } + break; + case 3:// SPAWN SKELETONS + for (j = 0; j < 4; j++) { + spawnabaddy(i, SKELETON); + } + break; + case 4: + castspell(plr, i); + break; + } + } + } + } + newstatus(i, CHASE); + } + else if (spr.picnum == JUDYATTACK2 + 8) { + sprite[i].picnum = JUDYATTACK2; + playsound_loc(S_JUDY1 + krand() % 4, sprite[i].x, sprite[i].y); + if (krand() % 100 > 50) + skullycastspell(plr, i); + else { + if (krand() % 100 > 70) { + if (krand() % 100 > 50) { + plr.health = 0; + addhealth(plr, 1); + } + else { + addarmor(plr, -(plr.armor)); + plr.armortype = 0; + } + } + else { + int j = krand() % 5; + switch (j) { + case 0:// SPAWN WILLOW + spawnabaddy(i, WILLOW); + break; + case 1:// SPAWN 6 SPIDERS + for (j = 0; j < 4; j++) { + spawnabaddy(i, SPIDER); + } + break; + case 2:// SPAWN 2 GRONSW + for (j = 0; j < 2; j++) { + spawnabaddy(i, GRONSW); + } + break; + case 3:// SPAWN SKELETONS + for (j = 0; j < 4; j++) { + spawnabaddy(i, SKELETON); + } + break; + case 4: + castspell(plr, i); + break; + } + } + + } + newstatus(i, CHASE); + } + checksector6(i); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == JUDYDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +void judyOperate(PLAYER& plr) +{ + short nextsprite; + for (short i = headspritestat[WITCHSIT]; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + + sprite[i].ang = (short)(getangle(plr.x - sprite[i].x, plr.y - sprite[i].y) & 2047); + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum)) { + sprite[i].lotag -= TICSPERFRAME; + if (sprite[i].lotag < 0) { + sprite[i].picnum++; + sprite[i].lotag = 12; + if (sprite[i].picnum == JUDYSIT + 4) { + sprite[i].picnum = JUDY; + newstatus(i, FACE); + } + } + } + } +} + +static void spawnabaddy(int i, int monster) { + short j = insertsprite(sprite[i].sectnum, FACE); + + sprite[j].x = sprite[i].x + (krand() & 2048) - 1024; + sprite[j].y = sprite[i].y + (krand() & 2048) - 1024; + sprite[j].z = sprite[i].z; + + sprite[j].pal = 0; + sprite[j].shade = 0; + sprite[j].cstat = 0; + + if(monster == WILLOW) + premapWillow(j); + else if(monster == SPIDER) + premapSpider(j); + else if(monster == GRONSW) + premapGron(j); + else if(monster == SKELETON) + premapSkeleton(j); + else if(monster == GONZOGSH) + premapGonzo(j); + + sprite[j].picnum = (short) monster; + killcnt++; + + setsprite(j, sprite[j].x, sprite[j].y, sprite[j].z); + //game.pInt.setsprinterpolate(j, sprite[j]); + } + + + void createJudyAI() { + auto &e = enemy[JUDYTYPE]; + e.info.Init(32, 32, 2048, 120, 0, 64, false, 500, 0); + e.chase = chase; + e.resurect = resurect; + e.search = search; + e.nuked = nuked; + e.pain = pain; + e.face = face; + e.attack = attack; + e.flee = flee; + e.cast = cast; + e.die = die; + } + + void premapJudy(short i) { + SPRITE& spr = sprite[i]; + spr.detail = JUDYTYPE; + + enemy[JUDYTYPE].info.set(spr); + + if (mapon > 24) + spr.hitag = adjusthp(700); + + if (spr.picnum == JUDYSIT) { + changespritestat(i, WITCHSIT); + spr.extra = 1200; + } else + changespritestat(i, FACE); + } +} +END_WH_NS diff --git a/source/games/whaven/src/aikatie.cpp b/source/games/whaven/src/aikatie.cpp new file mode 100644 index 000000000..70038eced --- /dev/null +++ b/source/games/whaven/src/aikatie.cpp @@ -0,0 +1,284 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + + if (krand() % 63 == 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum))// && invisibletime < 0) + newstatus(i, ATTACK); + } + else { + checksight(plr, i); + if (!checkdist(i, plr.x, plr.y, plr.z)) { + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + } + else { + if (krand() % 8 == 0) // NEW + newstatus(i, ATTACK); // NEW + else { // NEW + sprite[i].ang = (short)(((krand() & 512 - 256) + sprite[i].ang + 1024) & 2047); // NEW + newstatus(i, FLEE); // NEW + } + } + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + spr.picnum = KATIE; + spr.hitag = (short)adjusthp(200); + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + checksector6(i); +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = KATIE; + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047); + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(i, plr.x, plr.y, plr.z)) + newstatus(i, ATTACK); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + sprite[i].lotag -= TICSPERFRAME; + if (sprite[i].lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum)) + newstatus(i, CAST); + else + newstatus(i, CHASE); + } + else + sprite[i].ang = getangle(plr.x - sprite[i].x, plr.y - sprite[i].y); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + + if (movestat != 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void cast(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 12; + } + + if (spr.picnum == KATIEAT + 2) { + if (spr.extra >= 2) { + if (rand() % 100 > 50) { + for (int j = 0; j < 4; j++) { + spawnabaddy(i, GONZOGSH); + } + } + else { + for (int j = 0; j < 6; j++) { + spawnabaddy(i, GRONSW); + } + } + spr.picnum = KATIE; + spr.extra--; + playsound_loc(S_FIREBALL, spr.x, spr.y); + newstatus(i, CHASE); + } + } + + if (spr.picnum == KATIEAT + 6) { + if (spr.extra == 1) { + for (short j = 0; j < MAXSPRITES; j++) { + if (sprite[j].pal == 8) { + sprite[j].picnum--; + sprite[j].pal = 0; + sprite[j].shade = 0; + changespritestat(j, FACE); + } + } + spr.picnum = KATIE; + playsound_loc(S_FIREBALL, spr.x, spr.y); + newstatus(i, CHASE); + spr.extra--; + } + } + + if (spr.picnum == KATIEAT + 16) { + spr.picnum = KATIE; + playsound_loc(S_FIREBALL, spr.x, spr.y); + castspell(plr, i); + newstatus(i, CHASE); + spr.extra++; + } + checksector6(i); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == KATIEDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +void createKatieAI() { + auto& e = enemy[KATIETYPE]; + e.info.Init(35, 35, 2048, 120, 0, 64, false, 200, 0); + e.chase = chase; + e.resurect = resurect; + e.search = search; + e.pain = pain; + e.face = face; + e.attack = attack; + e.flee = flee; + e.cast = cast; + e.die = die; +} + +void premapKatie(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = KATIETYPE; + changespritestat(i, FACE); + enemy[KATIETYPE].info.set(spr); + spr.extra = 5; +} + +END_WH_NS diff --git a/source/games/whaven/src/aikobold.cpp b/source/games/whaven/src/aikobold.cpp new file mode 100644 index 000000000..9edb5889f --- /dev/null +++ b/source/games/whaven/src/aikobold.cpp @@ -0,0 +1,363 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void checkexpl(PLAYER& plr, short i); + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + if ((krand() % 100) > 98) + playsound_loc(S_KSNARL1 + (krand() % 4), sprite[i].x, sprite[i].y); + + short osectnum = spr.sectnum; + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + if (checkdist(plr, i)) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, ATTACK); + } + else if (krand() % 63 > 60) { + spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + + if ((movestat & kHitTypeMask) == kHitSprite) { + if ((movestat & kHitIndexMask) != plr.spritenum) { + short daang = (short)((spr.ang - 256) & 2047); + spr.ang = daang; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, SKIRMISH); + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, SKIRMISH); + } + } + } + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + checkexpl(plr, i); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == KOBOLDDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = KOBOLD; + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047); + + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); + + checkexpl(plr, i); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) + { + case TYPELAVA: + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + if (spr.lotag == 34) { + if (checksight(plr, i)) + if (checkdist(plr, i)) { + spr.ang = (short)checksight_ang; + attack(plr, i); + } + } + else if (spr.lotag < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } + spr.lotag -= TICSPERFRAME; + + checksector6(i); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + spr.picnum = KOBOLD; + spr.hitag = (short)adjusthp(30); + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void search(PLAYER& plr, short i) { + if ((krand() % 100) > 98) + playsound_loc(S_KSNARL1 + (krand() % 4), sprite[i].x, sprite[i].y); + aisearch(plr, i, false); + if (!checksector6(i)) + checkexpl(plr, i); +} + +static void frozen(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.pal = 0; + spr.picnum = KOBOLD; + newstatus(i, FACE); + } +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + if (game.WH2) { + chunksofmeat(plr, i, spr.x, spr.y, spr.z, spr.sectnum, spr.ang); + trailingsmoke(i, false); + newstatus((short)i, DIE); + return; + } + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 24; + if (spr.picnum == KOBOLDCHAR + 4) { + trailingsmoke(i, false); + deletesprite(i); + } + } +} + +static void skirmish(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + + if (spr.lotag < 0) + newstatus(i, FACE); + short osectnum = spr.sectnum; + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + if (checksector6(i)) + return; + + checkexpl(plr, i); +} + + +static void checkexpl(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + short j = headspritesect[spr.sectnum]; + while (j != -1) { + short nextj = nextspritesect[j]; + long dx = klabs(spr.x - sprite[j].x); // x distance to sprite + long dy = klabs(spr.y - sprite[j].y); // y distance to sprite + long dz = klabs((spr.z >> 8) - (sprite[j].z >> 8)); // z distance to sprite + long dh = tilesizy[sprite[j].picnum] >> 1; // height of sprite + if (dx + dy < PICKDISTANCE && dz - dh <= getPickHeight()) { + if (sprite[j].picnum == EXPLO2 + || sprite[j].picnum == SMOKEFX + || sprite[j].picnum == MONSTERBALL) { + spr.hitag -= TICSPERFRAME << 2; + if (spr.hitag < 0) { + newstatus(i, DIE); + } + } + } + j = nextj; + } +} + +void createKoboldAI() { + auto& e = enemy[KOBOLDTYPE]; + e.info.Init(game.WH2 ? 60 : 54, game.WH2 ? 60 : 54, 1024, 120, 0, 64, false, 20, 0); + e.chase = chase; + e.die = die; + e.pain = pain; + e.face = face; + e.flee = flee; + e.attack = attack; + e.resurect = resurect; + e.search = search; + e.frozen = frozen; + e.nuked = nuked; + e.skirmish = skirmish; +} + +void premapKobold(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = KOBOLDTYPE; + enemy[KOBOLDTYPE].info.set(spr); + changespritestat(i, FACE); + + if (spr.pal == 8) + spr.hitag = adjusthp(40); + else if (spr.pal == 7) + spr.hitag = adjusthp(60); +} + +END_WH_NS diff --git a/source/games/whaven/src/aikurt.cpp b/source/games/whaven/src/aikurt.cpp new file mode 100644 index 000000000..94edd327a --- /dev/null +++ b/source/games/whaven/src/aikurt.cpp @@ -0,0 +1,103 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + + +static void stand(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + if (sintable[(spr.ang + 512) & 2047] * (plr.x - spr.x) + + sintable[spr.ang & 2047] * (plr.y - spr.y) >= 0) + if (cansee(spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), spr.sectnum, plr.x, plr.y, + plr.z, plr.sector) && plr.invisibletime < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + chunksofmeat(plr, i, spr.x, spr.y, spr.z, spr.sectnum, spr.ang); + trailingsmoke(i, false); + newstatus(i, DIE); +} + +static void kurtExplo(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + spr.picnum++; + if (spr.lotag < 0) + spr.lotag = 12; + + short j = headspritesect[spr.sectnum]; + while (j != -1) { + short nextj = nextspritesect[j]; + long dx = klabs(spr.x - sprite[j].x); // x distance to sprite + long dy = klabs(spr.y - sprite[j].y); // y distance to sprite + long dz = klabs((spr.z >> 8) - (sprite[j].z >> 8)); // z distance to sprite + long dh = tilesizy[sprite[j].picnum] >> 1; // height of sprite + if (dx + dy < PICKDISTANCE && dz - dh <= getPickHeight()) { + if (sprite[j].detail == KURTTYPE) { + sprite[j].hitag -= TICSPERFRAME << 4; + if (sprite[j].hitag < 0) { + newstatus(j, DIE); + } + } + } + j = nextj; + } +} + +void createKurtAI() { + auto& e = enemy[KURTTYPE]; + e.info.Init(35, 35, 1024 + 256, 120, 0, 48, false, 50, 0); + e.info.getAttackDist = [](EnemyInfo& e, SPRITE& spr) { + int out = e.attackdist; + switch (spr.picnum) { + case KURTAT: + case GONZOCSW: + case GONZOCSWAT: + if (spr.extra > 10) + out = 2048 << 1; + break; + } + + return out; + }; + e.stand = stand; + e.nuked = nuked; + e.chase = enemy[GONZOTYPE].chase; + e.resurect = enemy[GONZOTYPE].resurect; + e.skirmish = enemy[GONZOTYPE].skirmish; + e.search = enemy[GONZOTYPE].search; + e.frozen = enemy[GONZOTYPE].frozen; + e.pain = enemy[GONZOTYPE].pain; + e.face = enemy[GONZOTYPE].face; + e.attack = enemy[GONZOTYPE].attack; + e.cast = enemy[GONZOTYPE].cast; + e.flee = enemy[GONZOTYPE].flee; + e.die = enemy[GONZOTYPE].die; +} + +void premapKurt(short i) { + SPRITE& spr = sprite[i]; + spr.detail = KURTTYPE; + enemy[KURTTYPE].info.set(spr); + changespritestat(i, STAND); + + switch (spr.picnum) { + case KURTSTAND: + spr.extra = 20; + break; + case KURTKNEE: + spr.extra = 10; + break; + } +} + +END_WH_NS diff --git a/source/games/whaven/src/aiminotaur.cpp b/source/games/whaven/src/aiminotaur.cpp new file mode 100644 index 000000000..148ee91f2 --- /dev/null +++ b/source/games/whaven/src/aiminotaur.cpp @@ -0,0 +1,362 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void checkexpl(PLAYER& plr, short i); + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + if (checkdist(plr, i)) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, ATTACK); + } + else if (krand() % 63 > 60) { + spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + + if ((movestat & kHitTypeMask) == kHitSprite) { + if ((movestat & kHitIndexMask) != plr.spritenum) { + short daang = (short)((spr.ang - 256) & 2047); + spr.ang = daang; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, SKIRMISH); + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, SKIRMISH); + } + } + } + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + checkexpl(plr, i); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + spr.picnum = MINOTAUR; + spr.hitag = (short)adjusthp(100); + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void skirmish(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + + if (spr.lotag < 0) + newstatus(i, FACE); + short osectnum = spr.sectnum; + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + if (checksector6(i)) + return; + + checkexpl(plr, i); +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + if (game.WH2) { + chunksofmeat(plr, i, spr.x, spr.y, spr.z, spr.sectnum, spr.ang); + trailingsmoke(i, false); + newstatus((short)i, DIE); + return; + } + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 24; + if (spr.picnum == MINOTAURCHAR + 4) { + trailingsmoke(i, false); + deletesprite(i); + } + } +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = MINOTAUR; + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047); + + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); + + checkexpl(plr, i); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + sprite[i].hitag--; + if (sprite[i].hitag < 0) + newstatus(i, DIE); + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + if (spr.lotag == 31) { + if (checksight(plr, i)) + if (checkdist(plr, i)) { + spr.ang = (short)checksight_ang; + attack(plr, i); + } + } + else if (spr.lotag < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } + spr.lotag -= TICSPERFRAME; + + checksector6(i); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == MINOTAURDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void frozen(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.pal = 0; + spr.picnum = MINOTAUR; + newstatus(i, FACE); + } +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + if (!checksector6(i)) + checkexpl(plr, i); +} + + +static void checkexpl(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + short j = headspritesect[spr.sectnum]; + while (j != -1) { + short nextj = nextspritesect[j]; + long dx = klabs(spr.x - sprite[j].x); // x distance to sprite + long dy = klabs(spr.y - sprite[j].y); // y distance to sprite + long dz = klabs((spr.z >> 8) - (sprite[j].z >> 8)); // z distance to sprite + long dh = tilesizy[sprite[j].picnum] >> 1; // height of sprite + if (dx + dy < PICKDISTANCE && dz - dh <= getPickHeight()) { + if (sprite[j].picnum == EXPLO2 + || sprite[j].picnum == SMOKEFX + || sprite[j].picnum == MONSTERBALL) { + spr.hitag -= TICSPERFRAME << 2; + if (spr.hitag < 0) { + newstatus(i, DIE); + } + } + } + j = nextj; + } +} + +void createMinotaurAI() { + + //picanm[MINOTAUR + 16] = 0; + + auto& e = enemy[MINOTAURTYPE]; + e.info.Init(64, 64, 1024 + 512, 120, 0, 64, false, game.WH2 ? 80 : 100, 0); + e.chase = chase; + e.resurect = resurect; + e.skirmish = skirmish; + e.nuked = nuked; + e.pain = pain; + e.face = face; + e.attack = attack; + e.die = die; + e.flee = flee; + e.frozen = frozen; + e.search = search; +} + + +void premapMinotaur(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = MINOTAURTYPE; + enemy[MINOTAURTYPE].info.set(spr); + changespritestat(i, FACE); + + if (krand() % 100 > 50) + spr.extra = 1; +} + +END_WH_NS diff --git a/source/games/whaven/src/ainewguy.cpp b/source/games/whaven/src/ainewguy.cpp new file mode 100644 index 000000000..acfda082d --- /dev/null +++ b/source/games/whaven/src/ainewguy.cpp @@ -0,0 +1,479 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void newguyarrow(short s, PLAYER& plr); + +static void stand(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + if (sintable[(spr.ang + 512) & 2047] * (plr.x - spr.x) + + sintable[spr.ang & 2047] * (plr.y - spr.y) >= 0) + if (cansee(spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), spr.sectnum, plr.x, plr.y, + plr.z, plr.sector) && plr.invisibletime < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } +} + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + if (checkdist(plr, i)) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, ATTACK); + } + else if (krand() % 63 > 60) { + spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + + if ((movestat & kHitTypeMask) == kHitSprite) { + if ((movestat & kHitIndexMask) != plr.spritenum) { + short daang = (short)((spr.ang - 256) & 2047); + spr.ang = daang; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, SKIRMISH); + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, SKIRMISH); + } + } + } + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + int j = krand() % 3; + switch (j) { + case 0: + spr.extra = 30; + spr.hitag = (short)adjusthp(85); + break; + case 1: + spr.extra = 20; + spr.hitag = (short)adjusthp(85); + break; + case 2: + spr.extra = 10; + spr.hitag = (short)adjusthp(45); + break; + case 3: + spr.extra = 0; + spr.hitag = (short)adjusthp(15); + break; + } + spr.xrepeat = 35; + spr.yrepeat = 35; + spr.picnum = NEWGUY; + } +} + +static void skirmish(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + + if (spr.lotag < 0) + newstatus(i, FACE); + short osectnum = spr.sectnum; + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + checksector6(i); +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + checksector6(i); +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + chunksofmeat(plr, i, spr.x, spr.y, spr.z, spr.sectnum, spr.ang); + trailingsmoke(i, false); + newstatus((short)i, DIE); +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = NEWGUY; + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + if (plr.invisibletime < 0) + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + switch (spr.picnum) { + case NEWGUYCAST: + case NEWGUYBOW: + sprite[i].lotag -= TICSPERFRAME; + if (sprite[i].lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum)) + newstatus(i, CAST); + else + newstatus(i, CHASE); + } + else + sprite[i].ang = getangle(plr.x - sprite[i].x, plr.y - sprite[i].y); + break; + case NEWGUYMACE: + case NEWGUYPUNCH: + if (spr.lotag == 31) { + if (checksight(plr, i)) + if (checkdist(plr, i)) { + spr.ang = (short)checksight_ang; + attack(plr, i); + } + } + else if (spr.lotag < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } + spr.lotag -= TICSPERFRAME; + + checksector6(i); + break; + } +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == NEWGUYDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +static void cast(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 12; + } + + if (spr.picnum == NEWGUYCAST + 2) { + spr.extra--; + spr.picnum = NEWGUY; + playsound_loc(S_WISP, sprite[i].x, sprite[i].y); + skullycastspell(plr, i); + newstatus(i, CHASE); + } + if (spr.picnum == NEWGUYBOW + 2) { + spr.extra--; + spr.picnum = NEWGUY; + playsound_loc(S_PLRWEAPON3, sprite[i].x, sprite[i].y); + newguyarrow(i, plr); + newstatus(i, CHASE); + } + checksector6(i); +} + +static void newguyarrow(short s, PLAYER& plr) { + int j = insertsprite(sprite[s].sectnum, JAVLIN); + if (j == -1) + return; + + SPRITE& spr = sprite[j]; + + spr.x = sprite[s].x; + spr.y = sprite[s].y; + spr.z = sprite[s].z - (40 << 8); + + spr.cstat = 21; + + spr.picnum = WALLARROW; + spr.ang = (short)(((sprite[s].ang + 2048 + 96) - 512) & 2047); + spr.xrepeat = 24; + spr.yrepeat = 24; + spr.clipdist = 32; + + spr.extra = sprite[s].ang; + spr.shade = -15; + spr.xvel = (short)((krand() & 256) - 128); + spr.yvel = (short)((krand() & 256) - 128); + + spr.zvel = (short)(((plr.z + (8 << 8) - sprite[s].z) << 7) / engine + .ksqrt((plr.x - sprite[s].x) * (plr.x - sprite[s].x) + (plr.y - sprite[s].y) * (plr.y - sprite[s].y))); + + spr.zvel += ((krand() % 256) - 128); + + spr.owner = s; + spr.lotag = 1024; + spr.hitag = 0; + spr.pal = 0; +} + + void createNewGuyAI() { + //picanm[NEWGUYDIE] = 0; + //picanm[NEWGUYDIE + 3] = 0; + auto& e = enemy[NEWGUYTYPE]; + e.info.Init(35, 35, 1024 + 256, 120, 0, 48, false, 90, 0); + e.info.getAttackDist = [](EnemyInfo& e, SPRITE& spr) + { + int out = e.attackdist; + switch (spr.picnum) { + case NEWGUY: + case NEWGUYMACE: + case NEWGUYCAST: + case NEWGUYBOW: + if (spr.extra > 10) + out = 2048 << 1; + else out = 1024 + 256; + break; + case NEWGUYPUNCH: + out = 1024 + 256; + break; + default: + out = 512; + break; + } + + return out; + }; + + e.info.getHealth = [](EnemyInfo& e, SPRITE& spr) + { + switch (spr.picnum) { + case NEWGUYSTAND: + case NEWGUYKNEE: + return adjusthp(50); + case NEWGUYCAST: + return adjusthp(85); + case NEWGUYBOW: + return adjusthp(85); + case NEWGUYMACE: + return adjusthp(45); + case NEWGUYPUNCH: + return adjusthp(15); + } + + return adjusthp(e.health); + }; + e.stand = stand; + e.chase = chase; + e.resurect = resurect; + e.skirmish = skirmish; + e.search = search; + e.nuked = nuked; + e.pain = pain; + e.face = face; + e.flee = flee; + e.attack = attack; + e.die = die; + e.cast = cast; + } + + + void premapNewGuy(short i) { + SPRITE& spr = sprite[i]; + spr.detail = NEWGUYTYPE; + + enemy[NEWGUYTYPE].info.set(spr); + + switch (spr.picnum) { + case NEWGUYSTAND: + case NEWGUYKNEE: + changespritestat(i, STAND); + if (spr.picnum == NEWGUYSTAND) + spr.extra = 20; + else + spr.extra = 30; + break; + case NEWGUYCAST: + case NEWGUYBOW: + case NEWGUYMACE: + case NEWGUYPUNCH: + case NEWGUY: + switch (spr.picnum) { + case NEWGUYCAST: + spr.extra = 30; + break; + case NEWGUYBOW: + spr.extra = 20; + break; + case NEWGUYMACE: + spr.extra = 10; + break; + case NEWGUYPUNCH: + spr.extra = 0; + break; + } + changespritestat(i, FACE); + spr.picnum = NEWGUY; + } + } +} +END_WH_NS diff --git a/source/games/whaven/src/airat.cpp b/source/games/whaven/src/airat.cpp new file mode 100644 index 000000000..48f0bc7e2 --- /dev/null +++ b/source/games/whaven/src/airat.cpp @@ -0,0 +1,111 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void chase(PLAYER& plr, short i) { + newstatus(i, FLEE); +} + +static void search(PLAYER& plr, short i) { + sprite[i].ang = (short) (((krand() & 512 - 256) + sprite[i].ang + 1024) & 2047); + newstatus(i, FLEE); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + spr.ang = (short) (((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + spr.owner = sprite[plr.spritenum].owner; + newstatus(i, FLEE); +} + +static void die(PLAYER& plr, short i) { + deletesprite(i); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + return; + } + + if ((movestat & kHitTypeMask) == kHitWall) { + WALL wal = wall[movestat & kHitIndexMask]; + short wallang = (short)((getangle(wall[wal.point2].x - wal.x, wall[wal.point2].y - wal.y) + 512) + & 2047); + spr.ang = (short)(krand() & 512 - 256 + wallang); + } + + if ((movestat & kHitTypeMask) == kHitSprite) { + SPRITE sp = sprite[movestat & kHitIndexMask]; + spr.owner = (short)(movestat & kHitIndexMask); + spr.ang = getangle(sp.x - spr.x, sp.y - spr.y); + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + } + + if (klabs(plr.x - spr.x) <= 1024 && klabs(plr.y - spr.y) <= 1024) { + spr.owner = sprite[plr.spritenum].owner; + newstatus(i, FACE); + } + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + // switch (checkfluid(i, zr_florhit)) { + // case TYPELAVA: + // case TYPEWATER: + // spr.z += tilesizy[spr.picnum] << 5; + // break; + // } + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA2 + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); +} + + +void createRatAI() { + auto& e = enemy[RATTYPE]; + e.info.Init(32, 32, 512, 120, 0, 32, false, 0, 0); + e.info.getHealth = [](EnemyInfo&, SPRITE& spr) + { + return 10; + }; + e.chase = chase; + e.search = search; + e.face = face; + e.die = die; + e.flee = flee; +} + +void premapRat(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = RATTYPE; + enemy[RATTYPE].info.set(spr); + changespritestat(i, FACE); + + spr.shade = 12; + spr.pal = 5; +} + +END_WH_NS diff --git a/source/games/whaven/src/aiskeleton.cpp b/source/games/whaven/src/aiskeleton.cpp new file mode 100644 index 000000000..989e66c95 --- /dev/null +++ b/source/games/whaven/src/aiskeleton.cpp @@ -0,0 +1,388 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void checkexpl(PLAYER& plr, short i); + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + if (checkdist(plr, i)) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, ATTACK); + } + else if (krand() % 63 > 60) { + spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + + if ((movestat & kHitTypeMask) == kHitSprite) { + if ((movestat & kHitIndexMask) != plr.spritenum) { + short daang = (short)((spr.ang - 256) & 2047); + spr.ang = daang; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, SKIRMISH); + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, SKIRMISH); + } + } + } + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + checkexpl(plr, i); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == SKELETONDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047); + + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); + + checkexpl(plr, i); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.picnum = SKELETON; + + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void stand(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + if (sintable[(spr.ang + 2560) & 2047] * (plr.x - spr.x) + + sintable[(spr.ang + 2048) & 2047] * (plr.y - spr.y) >= 0) + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + + if (spr.picnum == HANGMAN) { + newstatus(i, CHILL); + playsound_loc(S_SKELSEE, spr.x, spr.y); + } + else { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } + } + + checksector6(i); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + if (spr.lotag == 16) { + if (checksight(plr, i)) + if (checkdist(plr, i)) { + spr.ang = (short)checksight_ang; + attack(plr, i); + } + } + else if (spr.lotag < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } + spr.lotag -= TICSPERFRAME; + + checksector6(i); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + spr.picnum = SKELETON; + spr.hitag = (short)adjusthp(10); + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + if (!checksector6(i)) + checkexpl(plr, i); +} + +static void frozen(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.pal = 0; + spr.picnum = SKELETON; + newstatus(i, FACE); + } +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + if (game.WH2) { + chunksofmeat(plr, i, spr.x, spr.y, spr.z, spr.sectnum, spr.ang); + trailingsmoke(i, false); + newstatus((short)i, DIE); + return; + } + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 24; + if (spr.picnum == SKELETONCHAR + 4) { + trailingsmoke(i, false); + deletesprite(i); + } + } +} + +static void skirmish(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + + if (spr.lotag < 0) + newstatus(i, FACE); + short osectnum = spr.sectnum; + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + if (checksector6(i)) + return; + + checkexpl(plr, i); +} + +void skeletonChill(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 18; + if (spr.picnum == HANGMAN + 10) { + spr.picnum = SKELETON; + newstatus(i, FACE); + } + } +} + +static void checkexpl(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + short j = headspritesect[spr.sectnum]; + while (j != -1) { + short nextj = nextspritesect[j]; + int dx = klabs(spr.x - sprite[j].x); // x distance to sprite + int dy = klabs(spr.y - sprite[j].y); // y distance to sprite + int dz = klabs((spr.z >> 8) - (sprite[j].z >> 8)); // z distance to sprite + int dh = tilesizy[sprite[j].picnum] >> 1; // height of sprite + if (dx + dy < PICKDISTANCE && dz - dh <= getPickHeight()) { + if (sprite[j].picnum == EXPLO2 + || sprite[j].picnum == SMOKEFX + || sprite[j].picnum == MONSTERBALL) { + spr.hitag -= TICSPERFRAME << 2; + if (spr.hitag < 0) { + newstatus(i, DIE); + } + } + } + j = nextj; + } +} + +void createSkeletonAI() { + auto& e = enemy[SKELETONTYPE]; + e.info.Init(game.WH2 ? 35 : 24, game.WH2 ? 35 : 24, 1024, 120, 0, 64, false, game.WH2 ? 25 : 30, 0); + e.chase = chase; + e.die = die; + e.face = face; + e.flee = flee; + e.stand = stand; + e.attack = attack; + e.resurect = resurect; + e.search = search; + e.frozen = frozen; + e.nuked = nuked; + e.skirmish = skirmish; +} + + +void premapSkeleton(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = SKELETONTYPE; + enemy[SKELETONTYPE].info.set(spr); + + if (spr.picnum == HANGMAN) { + spr.xrepeat = 28; + spr.yrepeat = 28; + changespritestat(i, STAND); + return; + } + + changespritestat(i, FACE); +} + +END_WH_NS diff --git a/source/games/whaven/src/aiskully.cpp b/source/games/whaven/src/aiskully.cpp new file mode 100644 index 000000000..33d12ce9a --- /dev/null +++ b/source/games/whaven/src/aiskully.cpp @@ -0,0 +1,258 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + + if (krand() % 63 == 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum))// && invisibletime < 0) + newstatus(i, ATTACK); + } + else { + checksight(plr, i); + if (!checkdist(plr, i)) { + if ((aimove(i) & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + } + else { + if (krand() % 8 == 0) // NEW + newstatus(i, ATTACK); // NEW + else { // NEW + sprite[i].ang = (short)(((krand() & 512 - 256) + sprite[i].ang + 1024) & 2047); // NEW + newstatus(i, FLEE); // NEW + } + } + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + spr.picnum = SKULLY; + spr.hitag = (short)adjusthp(100); + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + checksector6(i); +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 24; + if (spr.picnum == SKULLYCHAR + 4) { + trailingsmoke(i, false); + deletesprite(i); + } + } +} + +static void pain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum = SKULLY; + spr.ang = (short)plr.ang; + newstatus(i, FLEE); + } + + aimove(i); + processfluid(i, zr_florhit, false); + setsprite(i, spr.x, spr.y, spr.z); +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + case TYPEWATER: + spr.z += tilesizy[spr.picnum] << 5; + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + sprite[i].lotag -= TICSPERFRAME; + if (sprite[i].lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum)) + newstatus(i, CAST); + else + newstatus(i, CHASE); + } + else + sprite[i].ang = getangle(plr.x - sprite[i].x, plr.y - sprite[i].y); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void cast(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.picnum++; + spr.lotag = 12; + } + + if (spr.picnum == SKULLYATTACK + 2) { + sprite[i].picnum = SKULLY; + playsound_loc(S_SKULLWITCH1 + krand() % 3, sprite[i].x, sprite[i].y); + skullycastspell(plr, i); + newstatus(i, CHASE); + } + checksector6(i); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == SKULLYDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +void createSkullyAI() { + auto& e = enemy[SKULLYTYPE]; + e.info.Init(32, 32, 2048, 120, 0, 64, false, 300, 0); + e.chase = chase; + e.resurect = resurect; + e.search = search; + e.nuked = nuked; + e.pain = pain; + e.face = face; + e.attack = attack; + e.flee = flee; + e.cast = cast; + e.die = die; +} + +void premapSkully(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = SKULLYTYPE; + enemy[SKULLYTYPE].info.set(spr); + changespritestat(i, FACE); + + if (krand() % 100 > 50) + spr.extra = 1; +} + +END_WH_NS diff --git a/source/games/whaven/src/aispider.cpp b/source/games/whaven/src/aispider.cpp new file mode 100644 index 000000000..1897e53dc --- /dev/null +++ b/source/games/whaven/src/aispider.cpp @@ -0,0 +1,322 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void checkexpl(PLAYER& plr, short i); + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + if (checkdist(plr, i)) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, ATTACK); + } + else if (krand() % 63 > 60) { + spr.ang = (short)(((krand() & 128 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + int movestat = aimove(i); + if ((movestat & kHitTypeMask) == kHitFloor) + { + spr.ang = (short)((spr.ang + 1024) & 2047); + newstatus(i, FLEE); + return; + } + + if ((movestat & kHitTypeMask) == kHitSprite) { + if ((movestat & kHitIndexMask) != plr.spritenum) { + short daang = (short)((spr.ang - 256) & 2047); + spr.ang = daang; + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else + newstatus(i, SKIRMISH); + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, SKIRMISH); + } + } + } + } + else { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA2 || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + checkexpl(plr, i); +} + +static void resurect(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + newstatus(i, FACE); + spr.picnum = SPIDER; + spr.hitag = (short)adjusthp(15); + spr.lotag = 100; + spr.cstat |= 1; + } +} + +static void skirmish(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + + if (spr.lotag < 0) + newstatus(i, FACE); + short osectnum = spr.sectnum; + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + if (checksector6(i)) + return; + + checkexpl(plr, i); +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, false); + if (!checksector6(i)) + checkexpl(plr, i); +} + +static void frozen(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + spr.pal = 0; + spr.picnum = SPIDER; + newstatus(i, FACE); + } +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + boolean cansee = cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum); + + if (cansee && plr.invisibletime < 0) { + spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047); + + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else if (cansee) newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); + + checkexpl(plr, i); +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + spr.z = zr_florz; + + switch (checkfluid(i, zr_florhit)) { + case TYPELAVA: + sprite[i].hitag--; + if (sprite[i].hitag < 0) + newstatus(i, DIE); + break; + } + + setsprite(i, spr.x, spr.y, spr.z); + + if (spr.lotag >= 64) { + if (checksight(plr, i)) + if (checkdist(plr, i)) { + spr.ang = (short)checksight_ang; + attack(plr, i); + if (krand() % 100 > ((plr.lvl * 7) + 20)) { + playsound_loc(S_SPIDERBITE, sprite[i].x, sprite[i].y); + plr.poisoned = 1; + plr.poisontime = 7200; + showmessage("Poisoned", 360); + newstatus(i, DIE); + return; + } + } + } + else if (spr.lotag < 0) { + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); // NEW + newstatus(i, FLEE); + } + else + newstatus(i, CHASE); + } + spr.lotag -= TICSPERFRAME; + + checksector6(i); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aimove(i); + if ((movestat & kHitTypeMask) != kHitFloor && movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, false); + + setsprite(i, spr.x, spr.y, spr.z); + + checkexpl(plr, i); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + + if (spr.picnum == SPIDERDEAD) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +static void checkexpl(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + short j = headspritesect[spr.sectnum]; + while (j != -1) { + short nextj = nextspritesect[j]; + long dx = klabs(spr.x - sprite[j].x); // x distance to sprite + long dy = klabs(spr.y - sprite[j].y); // y distance to sprite + long dz = klabs((spr.z >> 8) - (sprite[j].z >> 8)); // z distance to sprite + long dh = tilesizy[sprite[j].picnum] >> 1; // height of sprite + if (dx + dy < PICKDISTANCE && dz - dh <= getPickHeight()) { + if (sprite[j].picnum == EXPLO2 + || sprite[j].picnum == SMOKEFX + || sprite[j].picnum == MONSTERBALL) { + spr.hitag -= TICSPERFRAME << 2; + if (spr.hitag < 0) { + newstatus(i, DIE); + } + } + } + j = nextj; + } +} + +void createSpiderAI() { + auto& e = enemy[SPIDERTYPE]; + e.info.Init(24, 18, 512, 60, 0, 64, false, 5, 0); + e.chase = chase; + e.resurect = resurect; + e.skirmish = skirmish; + e.search = search; + e.frozen = frozen; + e.face = face; + e.attack = attack; + e.flee = flee; + e.die = die; +} + +void premapSpider(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = SPIDERTYPE; + enemy[SPIDERTYPE].info.set(spr); + changespritestat(i, FACE); +} + +END_WH_NS diff --git a/source/games/whaven/src/aiwillow.cpp b/source/games/whaven/src/aiwillow.cpp new file mode 100644 index 000000000..9165ed0f9 --- /dev/null +++ b/source/games/whaven/src/aiwillow.cpp @@ -0,0 +1,291 @@ +#include "ns.h" +#include "wh.h" + +BEGIN_WH_NS + +static void willowDrain(PLAYER& plr, short i); + +static void chase(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) + spr.lotag = 250; + + short osectnum = spr.sectnum; + if (krand() % 63 == 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, sprite[i].x, sprite[i].y, + sprite[i].z - (tilesizy[sprite[i].picnum] << 7), sprite[i].sectnum) && plr.invisibletime < 0) + newstatus(i, ATTACK); + return; + } + else { + //sprite[i].z = sector[sprite[i].sectnum].floorz - (32 << 8); + int dax = (sintable[(sprite[i].ang + 512) & 2047] * TICSPERFRAME) << 3; + int day = (sintable[sprite[i].ang & 2047] * TICSPERFRAME) << 3; + checksight(plr, i); + + if (!checkdist(plr, i)) { + checkmove(i, dax, day); + } + else { + if (krand() % 8 == 0) // NEW + newstatus(i, ATTACK); // NEW + else { // NEW + sprite[i].ang = (short)(((krand() & 512 - 256) + sprite[i].ang + 1024) & 2047); // NEW + newstatus(i, CHASE); // NEW + } + } + } + + getzrange(spr.x, spr.y, spr.z - 1, spr.sectnum, (spr.clipdist) << 2, CLIPMASK0); + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (spr.z > zr_florz) + spr.z = zr_florz; + if (spr.z < zr_ceilz - (32 << 8)) + spr.z = zr_ceilz - (32 << 8); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, true); + + if (sector[osectnum].lotag == KILLSECTOR) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } + + setsprite(i, spr.x, spr.y, spr.z); + + if ((zr_florhit & kHitTypeMask) == kHitSector && (sector[spr.sectnum].floorpicnum == LAVA + || sector[spr.sectnum].floorpicnum == LAVA1 || sector[spr.sectnum].floorpicnum == ANILAVA)) { + spr.hitag--; + if (spr.hitag < 0) + newstatus(i, DIE); + } +} + +static void attack(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (plr.z < spr.z) + spr.z -= TICSPERFRAME << 8; + + if (plr.z > spr.z) + spr.z += TICSPERFRAME << 8; + + if (spr.lotag < 0) { + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum)) + if (checkdist(plr, i)) { + if (plr.shockme < 0) + if ((krand() & 1) != 0) { + plr.shockme = 120; + if (!game.WH2) { + plr.lvl--; + switch (plr.lvl) { + case 1: + plr.score = 0; + plr.maxhealth = 100; + break; + case 2: + plr.score = 2350; + plr.maxhealth = 120; + break; + case 3: + plr.score = 4550; + plr.maxhealth = 140; + break; + case 4: + plr.score = 9300; + plr.maxhealth = 160; + break; + case 5: + plr.score = 18400; + plr.maxhealth = 180; + break; + case 6: + plr.score = 36700; + plr.maxhealth = 200; + break; + case 7: + plr.score = 75400; + plr.maxhealth = 200; + break; + } + if (plr.lvl < 1) { + plr.lvl = 1; + plr.health = -1; + } + showmessage("Level Drained", 360); + } + else + showmessage("Shocked", 360); + + } + } + else + newstatus(i, DRAIN); + else + newstatus(i, CHASE); + } + + int floorz = getflorzofslope(spr.sectnum, spr.x, spr.y) - (16 << 8); + if (spr.z > floorz) + spr.z = floorz; +} + +static void face(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + + if (cansee(plr.x, plr.y, plr.z, plr.sector, spr.x, spr.y, spr.z - (tilesizy[spr.picnum] << 7), + spr.sectnum) && plr.invisibletime < 0) { + spr.ang = (short)(getangle(plr.x - spr.x, plr.y - spr.y) & 2047); + + if (plr.shadowtime > 0) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang + 1024) & 2047); + newstatus(i, FLEE); + } + else { + spr.owner = plr.spritenum; + newstatus(i, CHASE); + } + } + else { // get off the wall + if (spr.owner == plr.spritenum) { + spr.ang = (short)(((krand() & 512 - 256) + spr.ang) & 2047); + newstatus(i, FINDME); + } + else newstatus(i, FLEE); + } + + if (checkdist(plr, i)) + newstatus(i, ATTACK); +} + +static void search(PLAYER& plr, short i) { + aisearch(plr, i, true); + checksector6(i); +} + +static void flee(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + short osectnum = spr.sectnum; + + int movestat = aifly(i); + + if (movestat != 0) { + if ((movestat & kHitTypeMask) == kHitWall) { + int nWall = movestat & kHitIndexMask; + int nx = -(wall[wall[nWall].point2].y - wall[nWall].y) >> 4; + int ny = (wall[wall[nWall].point2].x - wall[nWall].x) >> 4; + spr.ang = getangle(nx, ny); + } + else { + spr.ang = getangle(plr.x - spr.x, plr.y - spr.y); + newstatus(i, FACE); + } + } + if (spr.lotag < 0) + newstatus(i, FACE); + + if ((spr.sectnum != osectnum) && (sector[spr.sectnum].lotag == 10)) + warpsprite(i); + + if (checksector6(i)) + return; + + processfluid(i, zr_florhit, true); + + setsprite(i, spr.x, spr.y, spr.z); +} + +static void die(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + spr.lotag -= TICSPERFRAME; + + if (spr.lotag <= 0) { + spr.picnum++; + spr.lotag = 20; + if (sprite[i].picnum == WILLOWEXPLO || sprite[i].picnum == WILLOWEXPLO + 1 + || sprite[i].picnum == WILLOWEXPLO + 2) + sprite[i].xrepeat = sprite[i].yrepeat <<= 1; + + if (spr.picnum == WILLOWEXPLO + 2) { + if (difficulty == 4) + newstatus(i, RESURECT); + else { + kills++; + newstatus(i, DEAD); + } + } + } +} + +static void nuked(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + if (game.WH2) { + chunksofmeat(plr, i, spr.x, spr.y, spr.z, spr.sectnum, spr.ang); + trailingsmoke(i, false); + newstatus((short)i, DIE); + } +} + +void willowProcess(PLAYER& plr) +{ + for (short i = headspritestat[DRAIN], nextsprite; i >= 0; i = nextsprite) { + nextsprite = nextspritestat[i]; + SPRITE& spr = sprite[i]; + + switch (spr.detail) { + case WILLOWTYPE: + willowDrain(plr, i); + break; + } + } +} + +static void willowDrain(PLAYER& plr, short i) { + SPRITE& spr = sprite[i]; + + spr.lotag -= TICSPERFRAME; + if (spr.lotag < 0) { + playsound_loc(S_FIREBALL, spr.x, spr.y); + int oldz = spr.z; + spr.z += 6144; + castspell(plr, i); + spr.z = oldz; + newstatus(i, CHASE); + } +} + +void createWillowAI() { + auto& e = enemy[WILLOWTYPE]; + e.info.Init(32, 32, 512, 120, 0, 64, true, game.WH2 ? 5 : 400, 0); + e.chase = chase; + e.attack = attack; + e.face = face; + e.search = search; + e.flee = flee; + e.die = die; + e.nuked = nuked; +} + + +void premap(short i) { + SPRITE& spr = sprite[i]; + + spr.detail = WILLOWTYPE; + enemy[WILLOWTYPE].info.set(spr); + spr.cstat |= 128; + spr.z -= tilesizy[WILLOW] << 8; + changespritestat(i, FACE); +} + +END_WH_NS diff --git a/source/games/whaven/src/globals.h b/source/games/whaven/src/globals.h new file mode 100644 index 000000000..31064bf86 --- /dev/null +++ b/source/games/whaven/src/globals.h @@ -0,0 +1,207 @@ +#pragma once +#include "ns.h" + +BEGIN_WH_NS + +enum +{ + MAXWEAPONS = 10, + MAXPOTIONS = 5, + + BACKBUTTON = 9216, + BACKSCALE = 16384, + MOUSECURSOR = 9217, + RESERVED1 = 9218, + RESERVED2 = 9219, + + WHLOGO = 9220, + MENUFONT = 9221, //+32 + + MINITEXTPOINT = 9254, + MINITEXTSLASH = 9255, + + WH2FONTBIGLETTERS = 9256, + WH2FONTLILLETTERS = 9282, + WH2FONTNUMBERS = 9308, + WH2LOGO = 9335, + WH2FONTBACKGROUND = 9336, + + ARROWCOUNTLIMIT = 100, + THROWPIKELIMIT = 100, + + GRAVITYCONSTANT = (4 << 7) - 32, + JUMPVEL = (4 << 10) - 256, + + WH2GRAVITYCONSTANT = (8 << 5), + WH2JUMPVEL = (6 << 10), //(8 << 10) + GROUNDBIT = 1, + PLATFORMBIT = 2, + + TICSPERFRAME = 3, + TIMERRATE = 120, + + kExtraTile = MAXTILES - MAXUSERTILES, + + // Hit definitions + kHitTypeMask = 0xE000, + kHitIndexMask = 0x1FFF, + kHitFloor = 0x4000, + kHitSector = 0x4000, + kHitCeiling = 0x6000, + kHitWall = 0x8000, + kHitSprite = 0xC000, + + PLAYERHEIGHT = 48, + WH2PLAYERHEIGHT = 64, + MAXNUMORBS = 8, + MAXHEALTH = 100, + MAXKEYS = 4, + MAXTREASURES = 18, + + LOW = 1, + HIGH = 2, + + TOP = 1, + BOTTOM = 2, + + INACTIVE = 0, + PATROL = 1, + CHASE = 2, + AMBUSH = 3, + BIRTH = 4, + DODGE = 5, + ATTACK = 6, + DEATH = 7, + STAND = 8, + + MISSILE = 100, + FX = 101, + HEATSEEKER = 102, + YELL = 103, + CAST = 104, + PUSH = 105, + FALL = 106, + DIE = 107, + DEAD = 108, + FACE = 109, + SHOVE = 110, + SHATTER = 111, + FIRE = 112, + LIFTUP = 113, + LIFTDN = 114, + PENDULUM = 115, + RESURECT = 116, + BOB = 117, + SHOVER = 118, + TORCHER = 119, + MASPLASH = 120, + CHUNKOMEAT = 121, + FLEE = 122, + DORMANT = 123, + ACTIVE = 124, + ATTACK2 = 125, + WITCHSIT = 126, + CHILL = 127, + SKIRMISH = 128, + FLOCK = 129, + FLOCKSPAWN = 130, + PAIN = 131, + WAR = 132, + TORCHLIGHT = 133, + GLOWLIGHT = 134, + BLOOD = 135, + DRIP = 136, + DEVILFIRE = 137, + FROZEN = 138, + PULLTHECHAIN = 139, + FLOCKCHIRP = 140, + CHUNKOWALL = 141, + FINDME = 142, + DRAIN = 143, + RATRACE = 144, + SMOKE = 145, + EXPLO = 146, + JAVLIN = 147, + ANIMLEVERUP = 148, + ANIMLEVERDN = 149, + BROKENVASE = 150, + NUKED = 151, + WARPFX = 152, + PATROLFLAG = 153, + PLACECONE = 154, + REMOVECONE = 155, + FIRSTCONE = 156, + GOTOCONE = 157, + TORCHFRONT = 158, + APATROLPOINT = 159, + SHADE = 160, + EVILSPIRIT = 161, + STONETOFLESH = 162, + SPARKS = 163, + SPARKSUP = 164, + SPARKSDN = 165, + LAND = 166, + SHARDOFGLASS = 167, + FIRECHUNK = 168, + DUDE = 170, + + ACTIVATESECTOR = 1, + ACTIVATESECTORONCE = 2, + + DOORUPTAG = 6, + DOORDOWNTAG = 7, + DOORSPLITHOR = 8, + DOORSPLITVER = 9, + DOORSWINGTAG = 13, + DOORBOX = 16, + + PLATFORMELEVTAG = 1000, + BOXELEVTAG = 1003, + + SECTOREFFECT = 104, + PULSELIGHT = 0, + FLICKERLIGHT = 1, + DELAYEFFECT = 2, + XPANNING = 3, + + DOORDELAY = 480, // 4 second delay for doors to close + DOORSPEED = 128, + ELEVSPEED = 256, + + PICKDISTANCE = 512, // for picking up sprites + PICKHEIGHT = 40, + PICKHEIGHT2 = 64, + + JETPACKPIC = 93 , // sprites available to pick up + + MAXSWINGDOORS = 32, + + JETPACKITEM = 0, + SHOTGUNITEM = 1, + + SHOTGUNPIC = 101, + SHOTGUNVIEW = 102, + + KILLSECTOR = 4444, + + TDIAMONDRING = 0, //armortype3 200units + TSHADOWAMULET = 1, //shadow + TGLASSSKULL = 2, //add score + TAHNK = 3, //health 250units + TBLUESCEPTER = 4, //lava walk + TYELLOWSCEPTER = 5, //water walk + TADAMANTINERING = 6, //unfinity attack protection + TONYXRING = 7, //projectiles protection + TPENTAGRAM = 8, //exit + TCRYSTALSTAFF = 9, //health 250units armortype2 200units + TAMULETOFTHEMIST = 10, //invisible + THORNEDSKULL = 11, //end game + TTHEHORN = 12, //vampire + TSAPHIRERING = 13, //set armortype to 3 + TBRASSKEY = 14, + TBLACKKEY = 15, + TGLASSKEY = 16, + TIVORYKEY = 17, +}; + +END_WH_NS diff --git a/source/games/whaven/src/names.cpp b/source/games/whaven/src/names.cpp new file mode 100644 index 000000000..3f085f3ac --- /dev/null +++ b/source/games/whaven/src/names.cpp @@ -0,0 +1,501 @@ +#include "ns.h" +#include "gamecontrol.h" + +short KNIFEREADY; +short KNIFEATTACK; +short RFIST; +short SWORDATTACK; +short MORNINGSTAR; +short BOWREADY; +short BOWREADYEND; +short BOWWALK; +short KNIFEATTACK2; +short SWORDPULL; +short SWORDATTACK2; +short MORNINGATTACK2; +short MUMEDUSA; +short MUTWOHANDS; +short BMUTWOHANDS; +short GOBSWORDPULL; +short GOBSWORDATTACK; +short GOBSWORDATTACK2; +short BIGAXEATTACK; +short BIGAXEATTACK2; +short BIGAXEDRAW; +short HALBERDATTACK1; +short HALBERDATTACK2; +short HALBERDDRAW; +short PIKEDRAW; +short PIKEATTACK1; +short EXCALATTACK1; +short EXCALATTACK2; +short EXCALDRAW; +short BIGAXEDRAW9; +short BIGAXEDRAW10; +short GEARS2START; +short HORNEDSKULL; +short THEFONT; +short CRYSTALSTAFF; +short TORCH; +short WEAPON1; +short WEAPON1A; +short AMULETOFTHEMIST; +short WEAPON2; +short BRASSKEY; +short BLACKKEY; +short GLASSKEY; +short IVORYKEY; +short NEWCHUNK; +short BOWLOFFIRE; +short SPAWNFIREBALL; +short PENTAGRAM; +short THEHORN; +short BOW; +short SWINGGATE3; +short PLATEARMOR; +short HELMET; +short CHAINMAIL; +short SCROLLSCARE; +short SCROLLNUKE; +short SCROLLFLY; +short SCROLLFIREBALL; +short SCROLLFREEZE; +short SCROLLNIGHT; +short SCROLLMAGIC; +short SCROLLOPEN; +short LEATHERARMOR; +short QUIVER; +short SWINGGATE4; +short SWINGGATE5; +short SMOKEFX; +short STANDINTORCH; +short PENTADOOR3; +short PENTADOOR4; +short PENTADOOR5; +short PENTADOOR6; +short PENTADOOR7; +short SCARY; +short FISH; +short LEVERUP; +short LEVERDOWN; +short SPAWNJAVLIN; +short RAT; +short GUARDIAN; +short GUARDIANATTACK; +short DART; +short WEAPON4; +short WEAPON6; +short WEAPON5; +short WEAPON5B; +short THROWHALBERD; +short WEAPON7; +short THROWPIKE; +short EXPLO2; +short SHATTERVASE; +short SHATTERVASE2; +short SHATTERVASE3; +short HANGMAN; +short SKELETON; +short SKELETONATTACK; +short SKELETONSKULL; +short SKELETONUP; +short SKELETONDIE; +short SKELETONDEAD; +short BONECHUNK1; +short BONECHUNKEND; +short PIKEATTACK2; +short GOBWEAPON; +short SFLASKBLUE; +short SFLASKGREEN; +short SFLASKOCHRE; +short SFLASKRED; +short SFLASKTAN; +short SFLASKBLACK; +short SHEALTHFONT; +short SSCOREFONT; +short SPOTIONFONT; +short SPOTIONBACKPIC; +short SPOTIONARROW; +short SSPELLBOOKBLANK; +short SSPELLBOOK2; +short SSPELLBOOK3; +short SSPELLBOOK4; +short SSPELLBOOK5; +short SSPELLBOOK6; +short SSPELLBOOK7; +short SSPELLBOOK8; +short SARROWS; +short SPLAYERLVL; +short SSTATUSBAR; +short SKEYBLANK; +short SKEYBRASS; +short SKEYBLACK; +short SKEYGLASS; +short SKEYIVORY; +short SHEALTHBACK; +short SSCOREBACKPIC; +short SNDEFFECT; +short SNDLOOP; +short SNDLOOPOFF; +short BROWNCHUNKSTART; +short GREYCHUNKSTART; +short REDCHUNKSTART; +short GREENCHUNKSTART; +short TANCHUNKSTART; +short WILLOW; +short SPIKES; +short STHEFLAG; +short GRONHALATTACK; +short GRONHALATTACKEND; +short GROLHALREADY; +short GRONHALREADYEND; +short GRONHAL; +short GRONHALPAIN; +short GRONHALDIE; +short GRONSWATTACK; +short GRONSW; +short GRONSWPAIN; +short GRONSWDIE; +short GRONMUATTACK; +short GRONDIE; +short GRONDEAD; +short GRONMU; +short GRONMUPAIN; +short GRONMUDIE; +short GRONSHIELD; +short SHIELD; + +void InitNames() +{ + if(!game.WH2) { + KNIFEREADY = 1249; + KNIFEATTACK = 1261; + RFIST = 1268; + SWORDATTACK = 1291; + MORNINGSTAR = 1306; + BOWREADY = 1313; + BOWREADYEND = 1319; + BOWWALK = 1323; + KNIFEATTACK2 = 1329; + SWORDPULL = 1333; + SWORDATTACK2 = 1340; + MORNINGATTACK2 = 1348; + MUMEDUSA = 1353; + MUTWOHANDS = 1363; + BMUTWOHANDS = 1378; + GOBSWORDPULL = 1390; + GOBSWORDATTACK = 1397; + GOBSWORDATTACK2 = 1404; + BIGAXEATTACK = 1411; + BIGAXEATTACK2 = 1421; + BIGAXEDRAW = 1429; + HALBERDATTACK1 = 1438; + HALBERDATTACK2 = 1443; + HALBERDDRAW = 1447; + PIKEDRAW = 1451; + PIKEATTACK1 = 1457; + EXCALATTACK1 = 1463; + EXCALATTACK2 = 1473; + EXCALDRAW = 1481; + BIGAXEDRAW9 = 1494; + BIGAXEDRAW10 = 1495; + GEARS2START = 1498; + HORNEDSKULL = 1503; + THEFONT = 1511; + CRYSTALSTAFF = 1551; + TORCH = 1554; + WEAPON1 = 1567; + WEAPON1A = 1571; + AMULETOFTHEMIST = 1575; + WEAPON2 = 1583; + BRASSKEY = 1624; + BLACKKEY = 1632; + GLASSKEY = 1640; + IVORYKEY = 1648; + NEWCHUNK = 1664; + BOWLOFFIRE = 1705; + SPAWNFIREBALL = 1718; + PENTAGRAM = 1760; + THEHORN = 1768; + BOW = 1776; + SWINGGATE3 = 1789; + PLATEARMOR = 1794; + HELMET = 1802; + CHAINMAIL = 1810; + SCROLLSCARE = 1818; + SCROLLNUKE = 1826; + SCROLLFLY = 1834; + SCROLLFIREBALL = 1842; + SCROLLFREEZE = 1850; + SCROLLNIGHT = 1858; + SCROLLMAGIC = 1866; + SCROLLOPEN = 1874; + LEATHERARMOR = 1882; + QUIVER = 1890; + SWINGGATE4 = 1898; + SWINGGATE5 = 1899; + SMOKEFX = 1904; + STANDINTORCH = 1908; + PENTADOOR3 = 1927; + PENTADOOR4 = 1928; + PENTADOOR5 = 1929; + PENTADOOR6 = 1930; + PENTADOOR7 = 1931; + SCARY = 1933; + FISH = 1945; + LEVERUP = 1947; + LEVERDOWN = 1949; + SPAWNJAVLIN = 1958; + RAT = 1962; + GUARDIAN = 1994; + GUARDIANATTACK = 2002; + DART = 2010; + WEAPON4 = 2027; + WEAPON6 = 2039; + WEAPON5 = 2047; + WEAPON5B = 2055; + THROWHALBERD = 2066; + WEAPON7 = 2067; + THROWPIKE = 2071; + EXPLO2 = 2096; + SHATTERVASE = 2124; + SHATTERVASE2 = 2131; + SHATTERVASE3 = 2138; + HANGMAN = 2145; + SKELETON = 2156; + SKELETONATTACK = 2181; + SKELETONSKULL = 2186; + SKELETONUP = 2191; + SKELETONDIE = 2192; + SKELETONDEAD = 2198; + BONECHUNK1 = 2199; + BONECHUNKEND = 2208; + PIKEATTACK2 = 2209; + GOBWEAPON = 2218; + SFLASKBLUE = 2240; + SFLASKGREEN = 2241; + SFLASKOCHRE = 2242; + SFLASKRED = 2243; + SFLASKTAN = 2244; + SFLASKBLACK = 2245; + SHEALTHFONT = 2246; + SSCOREFONT = 2256; + SPOTIONFONT = 2266; + SPOTIONBACKPIC = 2280; + SPOTIONARROW = 2281; + SSPELLBOOKBLANK = 2286; + SSPELLBOOK2 = 2294; + SSPELLBOOK3 = 2302; + SSPELLBOOK4 = 2310; + SSPELLBOOK5 = 2317; + SSPELLBOOK6 = 2324; + SSPELLBOOK7 = 2332; + SSPELLBOOK8 = 2340; + SARROWS = 2348; + SPLAYERLVL = 2349; + SSTATUSBAR = 2358; + SKEYBLANK = 2359; + SKEYBRASS = 2360; + SKEYBLACK = 2361; + SKEYGLASS = 2362; + SKEYIVORY = 2363; + SHEALTHBACK = 2365; + SSCOREBACKPIC = 2368; + SNDEFFECT = 2369; + SNDLOOP = 2370; + SNDLOOPOFF = 2371; + BROWNCHUNKSTART = 2387; + GREYCHUNKSTART = 2395; + REDCHUNKSTART = 2403; + GREENCHUNKSTART = 2411; + TANCHUNKSTART = 2419; + WILLOW = 2427; + SPIKES = 2488; + STHEFLAG = 2491; + GRONHALATTACK = 2504; + GRONHALATTACKEND = 2508; + GROLHALREADY = 2509; + GRONHALREADYEND = 2510; + GRONHAL = 2539; + GRONHALPAIN = 2559; + GRONHALDIE = 2560; + GRONSWATTACK = 2561; + GRONSW = 2581; + GRONSWPAIN = 2601; + GRONSWDIE = 2602; + GRONMUATTACK = 2603; + GRONDIE = 2633; + GRONDEAD = 2639; + GRONMU = 2640; + GRONMUPAIN = 2660; + GRONMUDIE = 2661; + GRONSHIELD = 2680; + SHIELD = 2684; + } else { //WH2 + KNIFEREADY = 1248; + KNIFEATTACK = 1260; + RFIST = 1267; + SWORDATTACK = 1290; + MORNINGSTAR = 1305; + BOWREADY = 1312; + BOWREADYEND = 1318; + BOWWALK = 1322; + KNIFEATTACK2 = 1328; + SWORDPULL = 1332; + SWORDATTACK2 = 1339; + MORNINGATTACK2 = 1347; + MUMEDUSA = 1352; + MUTWOHANDS = 1362; + BMUTWOHANDS = 1377; + GOBSWORDPULL = 1389; + GOBSWORDATTACK = 1396; + GOBSWORDATTACK2 = 1403; + BIGAXEATTACK = 1410; + BIGAXEATTACK2 = 1420; + BIGAXEDRAW = 1428; + HALBERDATTACK1 = 1437; + HALBERDATTACK2 = 1442; + HALBERDDRAW = 1446; + PIKEDRAW = 1450; + PIKEATTACK1 = 1456; + EXCALATTACK1 = 1462; + EXCALATTACK2 = 1472; + EXCALDRAW = 1480; + BIGAXEDRAW9 = 1493; + BIGAXEDRAW10 = 1494; + GEARS2START = 1497; + HORNEDSKULL = 1502; + THEFONT = 1510; + CRYSTALSTAFF = 1550; + TORCH = 1553; + WEAPON1 = 1566; + WEAPON1A = 1570; + AMULETOFTHEMIST = 1574; + WEAPON2 = 1582; + BRASSKEY = 1623; + BLACKKEY = 1631; + GLASSKEY = 1639; + IVORYKEY = 1647; + NEWCHUNK = 1663; + BOWLOFFIRE = 1704; + SPAWNFIREBALL = 1717; + PENTAGRAM = 1759; + THEHORN = 1767; + BOW = 1775; + SWINGGATE3 = 1788; + PLATEARMOR = 1793; + HELMET = 1801; + CHAINMAIL = 1809; + SCROLLSCARE = 1817; + SCROLLNUKE = 1825; + SCROLLFLY = 1833; + SCROLLFIREBALL = 1841; + SCROLLFREEZE = 1849; + SCROLLNIGHT = 1857; + SCROLLMAGIC = 1865; + SCROLLOPEN = 1873; + LEATHERARMOR = 1881; + QUIVER = 1889; + SWINGGATE4 = 1897; + SWINGGATE5 = 1898; + SMOKEFX = 1903; + STANDINTORCH = 1907; + PENTADOOR3 = 1926; + PENTADOOR4 = 1927; + PENTADOOR5 = 1928; + PENTADOOR6 = 1929; + PENTADOOR7 = 1930; + SCARY = 1932; + FISH = 1944; + LEVERUP = 1946; + LEVERDOWN = 1948; + SPAWNJAVLIN = 1957; + RAT = 1961; + GUARDIAN = 1993; + GUARDIANATTACK = 2001; + DART = 2009; + WEAPON4 = 2026; + WEAPON6 = 2038; + WEAPON5 = 2046; + WEAPON5B = 2054; + THROWHALBERD = 2065; + WEAPON7 = 2066; + THROWPIKE = 2070; + EXPLO2 = 2095; + SHATTERVASE = 2123; + SHATTERVASE2 = 2130; + SHATTERVASE3 = 2137; + HANGMAN = 2144; + SKELETON = 2155; + SKELETONATTACK = 2180; + SKELETONSKULL = 2185; + SKELETONUP = 2190; + SKELETONDIE = 2191; + SKELETONDEAD = 2197; + BONECHUNK1 = 2198; + BONECHUNKEND = 2207; + PIKEATTACK2 = 2208; + GOBWEAPON = 2217; + SFLASKBLUE = 2239; + SFLASKGREEN = 2240; + SFLASKOCHRE = 2241; + SFLASKRED = 2242; + SFLASKTAN = 2243; + SFLASKBLACK = 2244; + SHEALTHFONT = 2245; + SSCOREFONT = 2255; + SPOTIONFONT = 2265; + SPOTIONBACKPIC = 2279; + SPOTIONARROW = 2280; + SSPELLBOOKBLANK = 2285; + SSPELLBOOK2 = 2293; + SSPELLBOOK3 = 2301; + SSPELLBOOK4 = 2309; + SSPELLBOOK5 = 2316; + SSPELLBOOK6 = 2323; + SSPELLBOOK7 = 2331; + SSPELLBOOK8 = 2339; + SARROWS = 2347; + SPLAYERLVL = 2348; + SSTATUSBAR = 2357; + SKEYBLANK = 2358; + SKEYBRASS = 2359; + SKEYBLACK = 2360; + SKEYGLASS = 2361; + SKEYIVORY = 2362; + SHEALTHBACK = 2364; + SSCOREBACKPIC = 2367; + SNDEFFECT = 2368; + SNDLOOP = 2369; + SNDLOOPOFF = 2370; + BROWNCHUNKSTART = 2386; + GREYCHUNKSTART = 2394; + REDCHUNKSTART = 2402; + GREENCHUNKSTART = 2410; + TANCHUNKSTART = 2418; + WILLOW = 2426; + SPIKES = 2487; + STHEFLAG = 2490; + GRONHALATTACK = 2502; + GRONHALATTACKEND = 2506; + GROLHALREADY = 2507; + GRONHALREADYEND = 2508; + GRONHAL = 2537; + GRONHALPAIN = 2557; + GRONHALDIE = 2558; + GRONSWATTACK = 2559; + GRONSW = 2579; + GRONSWPAIN = 2599; + GRONSWDIE = 2600; + GRONMUATTACK = 2601; + GRONDIE = 2631; + GRONDEAD = 2637; + GRONMU = 2638; + GRONMUPAIN = 2658; + GRONMUDIE = 2659; + GRONSHIELD = 2678; + SHIELD = 2682; + } +} + +END_WH_NS diff --git a/source/games/whaven/src/names.h b/source/games/whaven/src/names.h new file mode 100644 index 000000000..621312a7e --- /dev/null +++ b/source/games/whaven/src/names.h @@ -0,0 +1,388 @@ +BEGIN_WH_NS + +enum Names { + + TILES000_START = 0, + SLIME = 5, + DRYWATER = 22, + DRYSLIME = 33, + COOLLAVA = 58, + ANILAVA = 61, + LAVA1 = 62, + WOODPLANK = 68, + SKY = 75, + LAVA = 79, + LAVA2 = 80, + HEALTHWATER = 86, + WATER = 90, + COOLLAVA2 = 103, + SPLASHAROO = 160, + LASTSPLASHAROO = 166, + SKY2 = 167, + SKY3 = 168, + SKY4 = 169, + SKY5 = 170, + SKY6 = 171, + SKY7 = 172, + TILES001_START = 247, + GIFTBOX = 260, + OPENCHEST = 263, + BARREL = 269, + SPACEPLANK = 271, + PENTADOOR1 = 280, + PENTADOOR2 = 281, + ROPEDOOR = 282, + TELEPAD = 291, + BULLET = 294, + PINE = 308, + SWINGDOOR = 324, + SWINGDOOR2 = 325, + SWINGDOOR3 = 326, + BAT = 330, + FBARREL = 340, + FBARRELFALL = 341, + FSHATTERBARREL = 342, + BOULDER = 361, + PULLCHAIN1 = 370, + PULLCHAIN2 = 371, + PULLCHAIN3 = 372, + SAPHIRERING = 373, + TALLSWING = 385, + TALLSWING2 = 386, + SPARKFX = 390, + VASEA = 392, + VASEB = 393, + VASEC = 394, + HEALTHPOTION = 401, + FIREWALKPOTION = 402, + STRENGTHPOTION = 403, + INVISIBLEPOTION = 404, + ARMORPOTION = 406, + LAVASPLASH = 423, + LASTLAVASPLASH = 437, + SPIKEBLADE = 461, + SPIKE = 462, + SPIKEPOLE = 463, + HORIZSPIKEPOLE = 464, + HORIZSPIKE = 465, + HORIZSPIKEBLADE = 466, + GEARSSTART = 467, + GEARSEND = 474, + SWINGHOLE = 476, + SWINGGATE = 477, + SWINGGATE2 = 478, + WOODGEARSSTART = 483, + WOODGEARSEND = 486, + SQUAREGRATE = 490, + MAINMENU = 500, + TITLEPIC = 501, + SAVEPIC = 502, + SAVENUMBERS = 503, + LOADPIC = 504, + AREYOUSURE = 505, + BLOODGORERED = 506, + DIFFICULTRED = 507, + BLOODGOREGREEN = 508, + DIFFICULTGREEN = 509, + HORNYSKULL1 = 510, + HORNYSKULL2 = 511, + HORNYSKULL3 = 512, + HORNYSKULL4 = 513, + HORNYBACK = 514, + LOADRED = 515, + SAVERED = 516, + LOADGREEN = 517, + SAVEGREEN = 518, + MENUSELECTIONS = 519, + NEWGAMEGREEN = 520, + LOADSAVEGREEN = 521, + BLOODGOREGREEN2 = 522, + HELPGREEN = 523, + QUITGREEN = 524, + NOGORESHADOW = 525, + NOGORESOLID = 526, + GORESHADOW = 527, + GORESOLID = 528, + VDARK = 529, + MDARK = 530, + FLICKER = 531, + XDARK = 532, + BACKGROUND = 536, + WALLARROW = 537, + MUHANDS = 538, + STATUSBAR = 545, + ORB1 = 546, + ORB2 = 547, + FLASKBLUE = 548, + FLASKGREEN = 549, + FLASKOCHRE = 550, + FLASKRED = 551, + FLASKTAN = 552, + FLASKBLACK = 553, + BGZERO = 554, + BGONE = 555, + BGTWO = 556, + BGTHREE = 557, + BGFOUR = 558, + BGFIVE = 559, + BGSIX = 560, + BGSEVEN = 561, + BGEIGHT = 562, + BGNINE = 563, + SCOREFONT = 564, + MDONE = 565, + MDTWO = 566, + MDTHREE = 567, + MDFOUR = 568, + MDFIVE = 569, + MDSIX = 570, + MDSEVEN = 571, + MDEIGHT = 572, + MDNINE = 573, + SMFONT = 574, + SMONE = 575, + SMTWO = 576, + SMTHREE = 577, + SMFOUR = 578, + SMFIVE = 579, + SMSIX = 580, + SMSEVEN = 581, + SMEIGHT = 582, + SMNINE = 583, + SCOREBACKPIC = 584, + WEAPONBACKPIC = 585, + HEALTHBACKPIC = 586, + BOOKBACKPIC = 587, + ORBBACKPIC = 588, + POTIONBACKPIC = 589, + POTIONARROW = 590, + ORB3 = 595, + ORB4 = 596, + ORB5 = 597, + ORB6 = 598, + ORB7 = 599, + ORB8 = 600, + WAVES1_SND = 607, + WAVES2_SND = 608, + WIND1_SND = 609, + WIND2_SND = 610, + LAVA1_SND = 611, + LAVA2_SND = 612, + DIESPIKE = 613, + SPELLBOOKBLANK = 618, + SPELLBOOK2 = 627, + SPELLBOOK3 = 636, + CHUNK1 = 645, + CHUNK2 = 646, + CHUNK3 = 647, + CHUNK4 = 648, + PLASMA = 649, + ANNIHILATE = 650, + WILLOWEXPLO = 653, + EXPLOSION = 656, + FATSPANK = 658, + MONSTERBALL = 660, + ICECUBE = 663, + DISTORTIONBLAST = 664, + SPELLBOOKBACK = 665, + WEAPON3 = 666, + ORB = 674, + SPAWN = 675, + ARMOR = 676, + POTION = 677, + WEAPON = 678, + COPYRIGHT = 679, + DIAMONDRING = 694, + SHADOWAMULET = 698, + GLASSSKULL = 706, + AHNK = 714, + BLUESCEPTER = 718, + YELLOWSCEPTER = 722, + ADAMANTINERING = 726, + ONYXRING = 730, + TILES003_START = 736, + KOBOLD = 737, + KOBOLDATTACK = 762, + KOBOLDDIE = 765, + KOBOLDDEAD = 770, + KOBOLDTORCH = 771, + DEVILSTAND = 772, + DEVIL = 777, + DEVILATTACK = 797, + DEVILPAIN = 809, + DEVILDIE = 814, + DEVILDEAD = 820, + TILES004_START = 980, + MINOTAUR = 981, + MINOTAURATTACK = 1001, + MINOTAURPAIN = 1012, + MINOTAURDIE = 1017, + MINOTAURDEAD = 1027, +}; + + +extern short KNIFEREADY; +extern short KNIFEATTACK; +extern short RFIST; +extern short SWORDATTACK; +extern short MORNINGSTAR; +extern short BOWREADY; +extern short BOWREADYEND; +extern short BOWWALK; +extern short KNIFEATTACK2; +extern short SWORDPULL; +extern short SWORDATTACK2; +extern short MORNINGATTACK2; +extern short MUMEDUSA; +extern short MUTWOHANDS; +extern short BMUTWOHANDS; +extern short GOBSWORDPULL; +extern short GOBSWORDATTACK; +extern short GOBSWORDATTACK2; +extern short BIGAXEATTACK; +extern short BIGAXEATTACK2; +extern short BIGAXEDRAW; +extern short HALBERDATTACK1; +extern short HALBERDATTACK2; +extern short HALBERDDRAW; +extern short PIKEDRAW; +extern short PIKEATTACK1; +extern short EXCALATTACK1; +extern short EXCALATTACK2; +extern short EXCALDRAW; +extern short BIGAXEDRAW9; +extern short BIGAXEDRAW10; +extern short GEARS2START; +extern short HORNEDSKULL; +extern short THEFONT; +extern short CRYSTALSTAFF; +extern short TORCH; +extern short WEAPON1; +extern short WEAPON1A; +extern short AMULETOFTHEMIST; +extern short WEAPON2; +extern short BRASSKEY; +extern short BLACKKEY; +extern short GLASSKEY; +extern short IVORYKEY; +extern short NEWCHUNK; +extern short BOWLOFFIRE; +extern short SPAWNFIREBALL; +extern short PENTAGRAM; +extern short THEHORN; +extern short BOW; +extern short SWINGGATE3; +extern short PLATEARMOR; +extern short HELMET; +extern short CHAINMAIL; +extern short SCROLLSCARE; +extern short SCROLLNUKE; +extern short SCROLLFLY; +extern short SCROLLFIREBALL; +extern short SCROLLFREEZE; +extern short SCROLLNIGHT; +extern short SCROLLMAGIC; +extern short SCROLLOPEN; +extern short LEATHERARMOR; +extern short QUIVER; +extern short SWINGGATE4; +extern short SWINGGATE5; +extern short SMOKEFX; +extern short STANDINTORCH; +extern short PENTADOOR3; +extern short PENTADOOR4; +extern short PENTADOOR5; +extern short PENTADOOR6; +extern short PENTADOOR7; +extern short SCARY; +extern short FISH; +extern short LEVERUP; +extern short LEVERDOWN; +extern short SPAWNJAVLIN; +extern short RAT; +extern short GUARDIAN; +extern short GUARDIANATTACK; +extern short DART; +extern short WEAPON4; +extern short WEAPON6; +extern short WEAPON5; +extern short WEAPON5B; +extern short THROWHALBERD; +extern short WEAPON7; +extern short THROWPIKE; +extern short EXPLO2; +extern short SHATTERVASE; +extern short SHATTERVASE2; +extern short SHATTERVASE3; +extern short HANGMAN; +extern short SKELETON; +extern short SKELETONATTACK; +extern short SKELETONSKULL; +extern short SKELETONUP; +extern short SKELETONDIE; +extern short SKELETONDEAD; +extern short BONECHUNK1; +extern short BONECHUNKEND; +extern short PIKEATTACK2; +extern short GOBWEAPON; +extern short SFLASKBLUE; +extern short SFLASKGREEN; +extern short SFLASKOCHRE; +extern short SFLASKRED; +extern short SFLASKTAN; +extern short SFLASKBLACK; +extern short SHEALTHFONT; +extern short SSCOREFONT; +extern short SPOTIONFONT; +extern short SPOTIONBACKPIC; +extern short SPOTIONARROW; +extern short SSPELLBOOKBLANK; +extern short SSPELLBOOK2; +extern short SSPELLBOOK3; +extern short SSPELLBOOK4; +extern short SSPELLBOOK5; +extern short SSPELLBOOK6; +extern short SSPELLBOOK7; +extern short SSPELLBOOK8; +extern short SARROWS; +extern short SPLAYERLVL; +extern short SSTATUSBAR; +extern short SKEYBLANK; +extern short SKEYBRASS; +extern short SKEYBLACK; +extern short SKEYGLASS; +extern short SKEYIVORY; +extern short SHEALTHBACK; +extern short SSCOREBACKPIC; +extern short SNDEFFECT; +extern short SNDLOOP; +extern short SNDLOOPOFF; +extern short BROWNCHUNKSTART; +extern short GREYCHUNKSTART; +extern short REDCHUNKSTART; +extern short GREENCHUNKSTART; +extern short TANCHUNKSTART; +extern short WILLOW; +extern short SPIKES; +extern short STHEFLAG; +extern short GRONHALATTACK; +extern short GRONHALATTACKEND; +extern short GROLHALREADY; +extern short GRONHALREADYEND; +extern short GRONHAL; +extern short GRONHALPAIN; +extern short GRONHALDIE; +extern short GRONSWATTACK; +extern short GRONSW; +extern short GRONSWPAIN; +extern short GRONSWDIE; +extern short GRONMUATTACK; +extern short GRONDIE; +extern short GRONDEAD; +extern short GRONMU; +extern short GRONMUPAIN; +extern short GRONMUDIE; +extern short GRONSHIELD; +extern short SHIELD; + +END_WH_NS diff --git a/source/games/whaven/src/player.h b/source/games/whaven/src/player.h new file mode 100644 index 000000000..ff2e2853a --- /dev/null +++ b/source/games/whaven/src/player.h @@ -0,0 +1,90 @@ +#pragma once + +BEGIN_WH_NS + +struct PLAYER { + + //Input pInput; + int x,y,z; + float ang; + float horiz, jumphoriz; + int height; + int hvel; + short sector; + short oldsector; + short spritenum; + boolean keytoggle; + int flags; + int weapon[MAXWEAPONS], preenchantedweapon[MAXWEAPONS]; + int ammo[MAXWEAPONS], preenchantedammo[MAXWEAPONS]; + int orbammo[MAXNUMORBS]; + int treasure[MAXTREASURES]; + int orbactive[MAXNUMORBS]; + int orb[MAXNUMORBS]; + int potion[MAXPOTIONS]; + int lvl; + int score; + int health; + int maxhealth; + int armor; + int armortype; + int onsomething; + int fallz; + + boolean dead; + short turnAround; + + int shadowtime; + int helmettime; + int scoretime; + int vampiretime; + + int selectedgun; + int currweapon; + int currweapontics; + int currweaponanim; + int currweaponframe; + int currweaponfired; + int currweaponattackstyle; + int currweaponflip; + int hasshot; + + int currentpotion; + int strongtime, manatime, invisibletime=-1; + + int orbshot; + int spellbooktics; + int spellbook; + int spellbookframe; + int spellbookflip; + int nightglowtime; + + int showbook; + int showbooktype; + int showbookflip; + int showbookanim; + int currentorb; + + int spelltime; + + int shieldpoints; + int shieldtype; + + int poisoned; + int poisontime; + int shockme = -1; + int invincibletime; + + int spiked; + int spiketics; + int spikeframe; + int currspikeframe; + boolean godMode; + boolean noclip; + + // no copy assignments for this one! + PLAYER(const PLAYER&) = delete; + PLAYER& operator=(const PLAYER&) = delete; +}; + +END_WH_NS diff --git a/source/games/whaven/src/wh.h b/source/games/whaven/src/wh.h new file mode 100644 index 000000000..713471db2 --- /dev/null +++ b/source/games/whaven/src/wh.h @@ -0,0 +1,17 @@ +#pragma once + +#include "build.h" + +BEGIN_WH_NS + +using SPRITE = spritetype; +using boolean = bool; + +END_WH_NS + +#include "globals.h" +#include "names.h" +#include "wh1names.h" +#include "wh2names.h" +#include "player.h" +#include "ai.h" diff --git a/source/games/whaven/src/wh1names.h b/source/games/whaven/src/wh1names.h new file mode 100644 index 000000000..b93d7b173 --- /dev/null +++ b/source/games/whaven/src/wh1names.h @@ -0,0 +1,266 @@ +#pragma once + +BEGIN_WH_NS + +enum WH1Names { + + SKY8 = 179, + SKY9 = 180, + SKY10 = 181, + FIREBALL = 314, + LFIRE = 345, + SFIRE = 353, + WATERSPLASH = 438, + LASTWATERSPLASH = 446, + GLOW = 451, + COMPASS = 499, + MACEWITHSPIKES = 540, + MACE = 541, + KNIFE = 542, + SWORD1 = 543, + SWORD2 = 544, + GYSER = 680, + FATWITCH = 821, + FATWITCHATTACK = 841, + FATWITCHDIE = 846, + FATWITCHDEAD = 852, + SWAPCHILL = 853, + SWAMPSTAND = 859, + SWAMPTHING = 860, + SWAMPATTACK = 862, + FREDSTAND = 866, + FRED = 871, + FREDATTACK = 891, + FREDPAIN = 906, + FREDDIE = 911, + FREDDEAD = 916, + GOBLINSTAND = 917, + GOBLIN = 922, + GOBLINCHILL = 942, + GOBLINSURPRISE = 946, + GOBLINATTACK = 952, + GOBLINPAIN = 963, + GOBLINDIE = 968, + GOBLINDEAD = 977, + SKULLY = 1028, + SKULLYATTACK = 1048, + SKULLYDIE = 1059, + SKULLYDEAD = 1069, + SPIDER = 1070, + SPIDERDIE = 1110, + SPIDERDEAD = 1117, + JUDYSIT = 1118, + JUDYSTAND = 1119, + JUDY = 1123, + JUDYATTACK1 = 1143, + JUDYATTACK2 = 1150, + JUDYDIE = 1159, + JUDYDEAD = 1163, + DRAGONATTACK = 1164, + DRAGONDIE = 1187, + DRAGONDEAD = 1200, + DRAGON = 1201, + DRAGONATTACK2 = 1207, + DOG = 1213, + TILES005_START = 1221, + SVGAMENU2 = 1990, + SVGAMENU = 1991, + GASCLOUD = 2021, + POISONICON = 2373, + SKULLYCHAR = 2433, + DEVILCHAR = 2438, + DRAGONCHAR = 2443, + FATWITCHCHAR = 2448, + GOBLINCHAR = 2453, + JUDYCHAR = 2458, + KOBOLDCHAR = 2463, + MINOTAURCHAR = 2468, + SKELETONCHAR = 2473, + GRONCHAR = 2483, + GUARDIANCHAR = 2498, + BETAPAGE = 2691, + STONEHENGE = 2698, + SVGAVICTORYA1 = 2699, + SVGAVICTORYA2 = 2700, + VICTORYA = 2703, + VICTORYB = 2704, + SVGAVICTORYB1 = 2705, + SVGAVICTORYB2 = 2706, + SVB1 = 2707, + SVB2 = 2708, + SVBR1 = 2709, + SVBR2 = 2710, + VICTORYC = 2714, + SVP1 = 2715, + SVP2 = 2716, + SVR1 = 2717, + SVR2 = 2718, + + + WH1KNIFEREADY = 1249, + WH1KNIFEATTACK = 1261, + WH1RFIST = 1268, + WH1SWORDATTACK = 1291, + WH1MORNINGSTAR = 1306, + WH1BOWREADY = 1313, + WH1BOWREADYEND = 1319, + WH1BOWWALK = 1323, + WH1KNIFEATTACK2 = 1329, + WH1SWORDPULL = 1333, + WH1SWORDATTACK2 = 1340, + WH1MORNINGATTACK2 = 1348, + WH1MUMEDUSA = 1353, + WH1MUTWOHANDS = 1363, + WH1BMUTWOHANDS = 1378, + WH1GOBSWORDPULL = 1390, + WH1GOBSWORDATTACK = 1397, + WH1GOBSWORDATTACK2 = 1404, + WH1BIGAXEATTACK = 1411, + WH1BIGAXEATTACK2 = 1421, + WH1BIGAXEDRAW = 1429, + WH1HALBERDATTACK1 = 1438, + WH1HALBERDATTACK2 = 1443, + WH1HALBERDDRAW = 1447, + WH1PIKEDRAW = 1451, + WH1PIKEATTACK1 = 1457, + WH1EXCALATTACK1 = 1463, + WH1EXCALATTACK2 = 1473, + WH1EXCALDRAW = 1481, + WH1BIGAXEDRAW9 = 1494, + WH1BIGAXEDRAW10 = 1495, + WH1GEARS2START = 1498, + WH1HORNEDSKULL = 1503, + WH1THEFONT = 1511, + WH1CRYSTALSTAFF = 1551, + WH1TORCH = 1554, + WH1WEAPON1 = 1567, + WH1WEAPON1A = 1571, + WH1AMULETOFTHEMIST = 1575, + WH1WEAPON2 = 1583, + WH1BRASSKEY = 1624, + WH1BLACKKEY = 1632, + WH1GLASSKEY = 1640, + WH1IVORYKEY = 1648, + WH1NEWCHUNK = 1664, + WH1BOWLOFFIRE = 1705, + WH1SPAWNFIREBALL = 1718, + WH1PENTAGRAM = 1760, + WH1THEHORN = 1768, + WH1BOW = 1776, + WH1SWINGGATE3 = 1789, + WH1PLATEARMOR = 1794, + WH1HELMET = 1802, + WH1CHAINMAIL = 1810, + WH1SCROLLSCARE = 1818, + WH1SCROLLNUKE = 1826, + WH1SCROLLFLY = 1834, + WH1SCROLLFIREBALL = 1842, + WH1SCROLLFREEZE = 1850, + WH1SCROLLNIGHT = 1858, + WH1SCROLLMAGIC = 1866, + WH1SCROLLOPEN = 1874, + WH1LEATHERARMOR = 1882, + WH1QUIVER = 1890, + WH1SWINGGATE4 = 1898, + WH1SWINGGATE5 = 1899, + WH1SMOKEFX = 1904, + WH1STANDINTORCH = 1908, + WH1PENTADOOR3 = 1927, + WH1PENTADOOR4 = 1928, + WH1PENTADOOR5 = 1929, + WH1PENTADOOR6 = 1930, + WH1PENTADOOR7 = 1931, + WH1SCARY = 1933, + WH1FISH = 1945, + WH1LEVERUP = 1947, + WH1LEVERDOWN = 1949, + WH1SPAWNJAVLIN = 1958, + WH1RAT = 1962, + WH1GUARDIAN = 1994, + WH1GUARDIANATTACK = 2002, + WH1DART = 2010, + WH1WEAPON4 = 2027, + WH1WEAPON6 = 2039, + WH1WEAPON5 = 2047, + WH1WEAPON5B = 2055, + WH1THROWHALBERD = 2066, + WH1WEAPON7 = 2067, + WH1THROWPIKE = 2071, + WH1EXPLO2 = 2096, + WH1SHATTERVASE = 2124, + WH1SHATTERVASE2 = 2131, + WH1SHATTERVASE3 = 2138, + WH1HANGMAN = 2145, + WH1SKELETON = 2156, + WH1SKELETONATTACK = 2181, + WH1SKELETONSKULL = 2186, + WH1SKELETONUP = 2191, + WH1SKELETONDIE = 2192, + WH1SKELETONDEAD = 2198, + WH1BONECHUNK1 = 2199, + WH1BONECHUNKEND = 2208, + WH1PIKEATTACK2 = 2209, + WH1GOBWEAPON = 2218, + WH1SFLASKBLUE = 2240, + WH1SFLASKGREEN = 2241, + WH1SFLASKOCHRE = 2242, + WH1SFLASKRED = 2243, + WH1SFLASKTAN = 2244, + WH1SFLASKBLACK = 2245, + WH1SHEALTHFONT = 2246, + WH1SSCOREFONT = 2256, + WH1SPOTIONFONT = 2266, + WH1SPOTIONBACKPIC = 2280, + WH1SPOTIONARROW = 2281, + WH1SSPELLBOOKBLANK = 2286, + WH1SSPELLBOOK2 = 2294, + WH1SSPELLBOOK3 = 2302, + WH1SSPELLBOOK4 = 2310, + WH1SSPELLBOOK5 = 2317, + WH1SSPELLBOOK6 = 2324, + WH1SSPELLBOOK7 = 2332, + WH1SSPELLBOOK8 = 2340, + WH1SARROWS = 2348, + WH1SPLAYERLVL = 2349, + WH1SSTATUSBAR = 2358, + WH1SKEYBLANK = 2359, + WH1SKEYBRASS = 2360, + WH1SKEYBLACK = 2361, + WH1SKEYGLASS = 2362, + WH1SKEYIVORY = 2363, + WH1SHEALTHBACK = 2365, + WH1SSCOREBACKPIC = 2368, + WH1SNDEFFECT = 2369, + WH1SNDLOOP = 2370, + WH1SNDLOOPOFF = 2371, + WH1BROWNCHUNKSTART = 2387, + WH1GREYCHUNKSTART = 2395, + WH1REDCHUNKSTART = 2403, + WH1GREENCHUNKSTART = 2411, + WH1TANCHUNKSTART = 2419, + WH1WILLOW = 2427, + WH1SPIKES = 2488, + WH1STHEFLAG = 2491, + WH1GRONHALATTACK = 2504, + WH1GRONHALATTACKEND = 2508, + WH1GROLHALREADY = 2509, + WH1GRONHALREADYEND = 2510, + WH1GRONHAL = 2539, + WH1GRONHALPAIN = 2559, + WH1GRONHALDIE = 2560, + WH1GRONSWATTACK = 2561, + WH1GRONSW = 2581, + WH1GRONSWPAIN = 2601, + WH1GRONSWDIE = 2602, + WH1GRONMUATTACK = 2603, + WH1GRONDIE = 2633, + WH1GRONDEAD = 2639, + WH1GRONMU = 2640, + WH1GRONMUPAIN = 2660, + WH1GRONMUDIE = 2661, + WH1GRONSHIELD = 2680, + WH1SHIELD = 2684, + +}; + +END_WH_NS diff --git a/source/games/whaven/src/wh2names.h b/source/games/whaven/src/wh2names.h new file mode 100644 index 000000000..b0900a84f --- /dev/null +++ b/source/games/whaven/src/wh2names.h @@ -0,0 +1,389 @@ +#include "ns.h" + +BEGIN_WH_NS + +enum WH2Names { + + STAINQ = 180, + FLOORMIRROR = 182, + STARMAP = 208, + BLOODSPLAT1 = 212, + BLOODSPLAT1END = 222, + BLOODSPLAT2 = 223, + BLOODSPLAT2END = 228, + WEAPON8 = 229, + SILVERBAG = 234, + GOLDBAG = 235, + GOLDBAG2 = 236, + GOLDCOINS = 237, + GOLDCOINS2 = 238, + SILVERCOINS = 239, + WALLPIKE = 356, + WALLSWORD = 357, + WALLBOW = 358, + WALLAXE = 359, + STAINTRIANGLE = 410, + STAINFLOWER = 411, + STAINTHIN = 412, + PATROLPOINT = 447, + CONE = 449, + STAINCIRCLE = 451, + STAINCIRCLEBREAK = 452, + STAINCIRCLEEND = 457, + STAINHEAD = 498, + STAINSNAKE = 499, + SKULLPULLCHAIN1 = 539, + GONZOSHIELD = 540, + SKULLPULLCHAIN3 = 541, + SPARKBALL = 602, + WEAPON3A = 670, + SLIMESPLASH = 821, + LASTSLIMESPLASH = 827, + DAFONT = 864, + ZFIRE = 905, + IMP = 922, + IMPATTACK = 952, + IMPDIE = 958, + IMPPAIN = 959, + IMPDEAD = 967, + THEMAINMENU = 1028, + THEMAINMENUWITH = 1029, + THENEWGAME = 1030, + THELOADSAVE = 1031, + THEOPTIONS = 1032, + THEHELP = 1033, + THEQUIT = 1034, + ZCREDITS = 1035, + ZWEAPON = 1036, + ZSPELL = 1037, + ZKEN = 1038, + ZCREDITS2 = 1039, + ZMOVE = 1040, + ZMOVE2 = 1041, + ZPOTION = 1042, + ZCREDITS3 = 1043, + ZARTIST = 1044, + ZSAVE = 1045, + ZLOAD = 1046, + ZGOREPG = 1047, + VMAINBLANK = 1048, + VMAIN = 1049, + VNEW = 1050, + VCREDIT1 = 1055, + DALOAD = 1065, + DASAVE = 1066, + ZLOADSAVE = 1067, + ZSURE = 1068, + THEORDER = 1069, + STHEORDER = 1070, + ZOPS = 1072, + DASOUND = 1073, + DAGAMEPLAY = 1074, + DACONTROLS = 1075, + DASLIDER = 1076, + ZCDPLAYER = 1077, + STAINGLASS1 = 1079, + STAINGLASS2 = 1086, + STAINGLASS3 = 1093, + STAINGLASS4 = 1100, + STAINGLASS5 = 1107, + STAINGLASS6 = 1114, + STAINGLASS7 = 1121, + STAINGLASS8 = 1128, + STAINGLASS9 = 1135, + CDMUVOL = 1142, + REDSHUFFLE = 1164, + ZZGORE = 1182, + ZZBLOOD = 1183, + ZZDIFFICULTY = 1184, + ZCONTROLS = 1185, + ZZSLIDER = 1198, + ZZON = 1199, + ZZOFF = 1200, + ZZONLITE = 1201, + ZZOFFLITE = 1202, + EXPLOSTART = 1203, + EXPLOEND = 1215, + ARROWFLAME = 1216, + STAINSCENE = 1658, + STAINSKULL = 1660, + STAINGARGO = 1661, + STAINMU = 1662, + SHARD = 1687, + DEMON = 1935, + GONZOBSHIELD = 2432, + GONZOCSHIELD = 2439, + GONZOGSHIELD = 2446, + STONEGONZOCHM = 2483, + STONEGONZOGSH = 2484, + STONEGRONDOVAL = 2485, + STONEGONZOBSW = 2486, + STONEGONZOBSH = 2497, + STONEGONZOBSW2 = 2498, + SBLUEKNIGHTS1 = 2705, + SBLUEKNIGHTS2 = 2706, + SBROWNKNIGHTS1 = 2707, + SBROWNKNIGHTS2 = 2708, + SPURPLEKNIGHTS1 = 2713, + SPURPLEKNIGHTS2 = 2714, + SREDKNIGHTS1 = 2715, + SREDKNIGHTS2 = 2716, + NEWGUYBOW = 2750, + NEWGUYPUNCH = 2780, + GONZOBSHPAIN = 3006, + GONZOBSHDEAD = 3016, + GONZOCSW = 3017, + GONZOCSWAT = 3047, + GONZOCSWPAIN = 3077, + GONZOCSWDEAD = 3089, + KURTSTAND = 3090, + KURTKNEE = 3095, + KURTJUMP = 3100, + KURTAT = 3110, + GONZOCHMAT = 3120, + KURTPUNCH = 3140, + KURTREADY = 3160, + NEWGUY = 3170, + NEWGUYMACE = 3200, + NEWGUYDIE = 3230, + NEWGUYDEAD = 3239, + NEWGUYSTAND = 3243, + NEWGUYKNEE = 3248, + GONZOCSHPAIN = 3268, + GONZOCSHDEAD = 3278, + GONZOGSW = 3279, + GONZOGSWAT = 3309, + GONZOGSWPAIN = 3339, + GONZOGSWDEAD = 3351, + GONZOGHM = 3352, + GONZOGHMAT = 3382, + GONZOGHMPAIN = 3412, + GONZOGHMDEAD = 3425, + GONZOGSH = 3426, + GONZOGSHAT = 3474, + GONZOGSHPAIN = 3530, + GONZOGSHDEAD = 3540, + KATIE = 3541, + KATIEASS = 3561, + KATIEAT = 3566, + KATIEPAIN = 3583, + KATIEDEAD = 3591, + NEWGUYMACEMU = 3592, + NEWGUYCAST = 3602, + NEWGUYPAIN = 3612, + GONZOHMJUMP = 3630, + GONZOHMJUMPEND = 3635, + GONZOSHJUMP = 3636, + GONZOSHJUMPEND = 3641, + ZFLASHER1 = 3650, + ZFLASHER2 = 3662, + SFLASH1 = 3680, + SFLASH2 = 3692, + SFLASH4 = 3704, + SFLASH3 = 3707, + VLOAD = 3711, + VSAVE = 3712, + VSOUNDA = 3713, + VSOUNDB = 3714, + VGOREA = 3715, + VGOREB = 3716, + ZPIKEREADY = 3743, + ZPIKE = 3748, + ZPIKEATTACK = 3752, + ZPIKEATTACK2 = 3758, + ZBOWREADY = 3767, + ZBOWREADYEND = 3774, + ZBOWCOCK = 3775, + ZBOWWALK = 3776, + ZBOWATTACK = 3781, + ZKNIFEREADY = 3786, + ZKNIFEATTACK = 3798, + ZKNIFEATTACK2 = 3804, + ZAXEREADY = 3808, + ZAXEATTACK = 3817, + ZAXEATTACK2 = 3832, + ZFREEZE = 3840, + ZFIREBALL = 3855, + ZLIGHT = 3865, + ZSTARATTACK = 3875, + ZSTARATTACK2 = 3884, + ZTWOHANDREADY = 3888, + ZTWOHANDATTACK = 3900, + ZTWOHANDATTACK2 = 3915, + ZSHORTREADY = 3922, + ZSHORTATTACK = 3929, + ZSHORTATTACKONE = 3933, + ZSHORTATTACK2 = 3939, + ZHALBERDREADY = 3946, + ZHALBERDATTACK = 3948, + ZHALBERDATTACK2 = 3957, + ROUNDSHIELD = 3961, + + + + WH2KNIFEREADY = 1248, + WH2KNIFEATTACK = 1260, + WH2RFIST = 1267, + WH2SWORDATTACK = 1290, + WH2MORNINGSTAR = 1305, + WH2BOWREADY = 1312, + WH2BOWREADYEND = 1318, + WH2BOWWALK = 1322, + WH2KNIFEATTACK2 = 1328, + WH2SWORDPULL = 1332, + WH2SWORDATTACK2 = 1339, + WH2MORNINGATTACK2 = 1347, + WH2MUMEDUSA = 1352, + WH2MUTWOHANDS = 1362, + WH2BMUTWOHANDS = 1377, + WH2GOBSWORDPULL = 1389, + WH2GOBSWORDATTACK = 1396, + WH2GOBSWORDATTACK2 = 1403, + WH2BIGAXEATTACK = 1410, + WH2BIGAXEATTACK2 = 1420, + WH2BIGAXEDRAW = 1428, + WH2HALBERDATTACK1 = 1437, + WH2HALBERDATTACK2 = 1442, + WH2HALBERDDRAW = 1446, + WH2PIKEDRAW = 1450, + WH2PIKEATTACK1 = 1456, + WH2EXCALATTACK1 = 1462, + WH2EXCALATTACK2 = 1472, + WH2EXCALDRAW = 1480, + WH2BIGAXEDRAW9 = 1493, + WH2BIGAXEDRAW10 = 1494, + WH2GEARS2START = 1497, + WH2HORNEDSKULL = 1502, + WH2THEFONT = 1510, + WH2CRYSTALSTAFF = 1550, + WH2TORCH = 1553, + WH2WEAPON1 = 1566, + WH2WEAPON1A = 1570, + WH2AMULETOFTHEMIST = 1574, + WH2WEAPON2 = 1582, + WH2BRASSKEY = 1623, + WH2BLACKKEY = 1631, + WH2GLASSKEY = 1639, + WH2IVORYKEY = 1647, + WH2NEWCHUNK = 1663, + WH2BOWLOFFIRE = 1704, + WH2SPAWNFIREBALL = 1717, + WH2PENTAGRAM = 1759, + WH2THEHORN = 1767, + WH2BOW = 1775, + WH2SWINGGATE3 = 1788, + WH2PLATEARMOR = 1793, + WH2HELMET = 1801, + WH2CHAINMAIL = 1809, + WH2SCROLLSCARE = 1817, + WH2SCROLLNUKE = 1825, + WH2SCROLLFLY = 1833, + WH2SCROLLFIREBALL = 1841, + WH2SCROLLFREEZE = 1849, + WH2SCROLLNIGHT = 1857, + WH2SCROLLMAGIC = 1865, + WH2SCROLLOPEN = 1873, + WH2LEATHERARMOR = 1881, + WH2QUIVER = 1889, + WH2SWINGGATE4 = 1897, + WH2SWINGGATE5 = 1898, + WH2SMOKEFX = 1903, + WH2STANDINTORCH = 1907, + WH2PENTADOOR3 = 1926, + WH2PENTADOOR4 = 1927, + WH2PENTADOOR5 = 1928, + WH2PENTADOOR6 = 1929, + WH2PENTADOOR7 = 1930, + WH2SCARY = 1932, + WH2FISH = 1944, + WH2LEVERUP = 1946, + WH2LEVERDOWN = 1948, + WH2SPAWNJAVLIN = 1957, + WH2RAT = 1961, + WH2GUARDIAN = 1993, + WH2GUARDIANATTACK = 2001, + WH2DART = 2009, + WH2WEAPON4 = 2026, + WH2WEAPON6 = 2038, + WH2WEAPON5 = 2046, + WH2WEAPON5B = 2054, + WH2THROWHALBERD = 2065, + WH2WEAPON7 = 2066, + WH2THROWPIKE = 2070, + WH2EXPLO2 = 2095, + WH2SHATTERVASE = 2123, + WH2SHATTERVASE2 = 2130, + WH2SHATTERVASE3 = 2137, + WH2HANGMAN = 2144, + WH2SKELETON = 2155, + WH2SKELETONATTACK = 2180, + WH2SKELETONSKULL = 2185, + WH2SKELETONUP = 2190, + WH2SKELETONDIE = 2191, + WH2SKELETONDEAD = 2197, + WH2BONECHUNK1 = 2198, + WH2BONECHUNKEND = 2207, + WH2PIKEATTACK2 = 2208, + WH2GOBWEAPON = 2217, + WH2SFLASKBLUE = 2239, + WH2SFLASKGREEN = 2240, + WH2SFLASKOCHRE = 2241, + WH2SFLASKRED = 2242, + WH2SFLASKTAN = 2243, + WH2SFLASKBLACK = 2244, + WH2SHEALTHFONT = 2245, + WH2SSCOREFONT = 2255, + WH2SPOTIONFONT = 2265, + WH2SPOTIONBACKPIC = 2279, + WH2SPOTIONARROW = 2280, + WH2SSPELLBOOKBLANK = 2285, + WH2SSPELLBOOK2 = 2293, + WH2SSPELLBOOK3 = 2301, + WH2SSPELLBOOK4 = 2309, + WH2SSPELLBOOK5 = 2316, + WH2SSPELLBOOK6 = 2323, + WH2SSPELLBOOK7 = 2331, + WH2SSPELLBOOK8 = 2339, + WH2SARROWS = 2347, + WH2SPLAYERLVL = 2348, + WH2SSTATUSBAR = 2357, + WH2SKEYBLANK = 2358, + WH2SKEYBRASS = 2359, + WH2SKEYBLACK = 2360, + WH2SKEYGLASS = 2361, + WH2SKEYIVORY = 2362, + WH2SHEALTHBACK = 2364, + WH2SSCOREBACKPIC = 2367, + WH2SNDEFFECT = 2368, + WH2SNDLOOP = 2369, + WH2SNDLOOPOFF = 2370, + WH2BROWNCHUNKSTART = 2386, + WH2GREYCHUNKSTART = 2394, + WH2REDCHUNKSTART = 2402, + WH2GREENCHUNKSTART = 2410, + WH2TANCHUNKSTART = 2418, + WH2WILLOW = 2426, + WH2SPIKES = 2487, + WH2STHEFLAG = 2490, + WH2GRONHALATTACK = 2502, + WH2GRONHALATTACKEND = 2506, + WH2GROLHALREADY = 2507, + WH2GRONHALREADYEND = 2508, + WH2GRONHAL = 2537, + WH2GRONHALPAIN = 2557, + WH2GRONHALDIE = 2558, + WH2GRONSWATTACK = 2559, + WH2GRONSW = 2579, + WH2GRONSWPAIN = 2599, + WH2GRONSWDIE = 2600, + WH2GRONMUATTACK = 2601, + WH2GRONDIE = 2631, + WH2GRONDEAD = 2637, + WH2GRONMU = 2638, + WH2GRONMUPAIN = 2658, + WH2GRONMUDIE = 2659, + WH2GRONSHIELD = 2678, + WH2SHIELD = 2682, +}; + +END_WH_NS