2019-11-20 16:21:32 +00:00
|
|
|
//-------------------------------------------------------------------------
|
|
|
|
/*
|
|
|
|
Copyright (C) 2010-2019 EDuke32 developers and contributors
|
|
|
|
Copyright (C) 2019 sirlemonhead, Nuke.YKT
|
|
|
|
This file is part of PCExhumed.
|
|
|
|
PCExhumed is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU General Public License version 2
|
|
|
|
as published by the Free Software Foundation.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
|
|
See the GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
//-------------------------------------------------------------------------
|
2019-11-22 23:11:37 +00:00
|
|
|
#include "ns.h"
|
2019-08-26 03:59:14 +00:00
|
|
|
#include "engine.h"
|
|
|
|
#include "exhumed.h"
|
2020-08-18 07:52:08 +00:00
|
|
|
#include "aistuff.h"
|
2019-08-26 03:59:14 +00:00
|
|
|
#include "status.h"
|
|
|
|
#include "player.h"
|
|
|
|
#include "sequence.h"
|
2021-01-01 22:38:15 +00:00
|
|
|
#include "input.h"
|
2019-08-26 03:59:14 +00:00
|
|
|
#include "sound.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
2019-11-22 23:11:37 +00:00
|
|
|
BEGIN_PS_NS
|
|
|
|
|
2020-11-29 23:18:32 +00:00
|
|
|
FreeListArray<Snake, kMaxSnakes> SnakeList;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-11-21 19:13:19 +00:00
|
|
|
int16_t nPlayerSnake[kMaxPlayers];
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-12-07 17:53:02 +00:00
|
|
|
size_t MarkSnake()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < kMaxSnakes; i++)
|
|
|
|
{
|
|
|
|
GC::Mark(SnakeList[i].pEnemy);
|
|
|
|
GC::MarkArray(SnakeList[i].pSprites, kSnakeSprites);
|
|
|
|
}
|
|
|
|
return kMaxSnakes * (1 + kSnakeSprites);
|
|
|
|
}
|
|
|
|
|
2020-11-29 23:18:32 +00:00
|
|
|
FSerializer& Serialize(FSerializer& arc, const char* keyname, Snake& w, Snake* def)
|
|
|
|
{
|
|
|
|
if (arc.BeginObject(keyname))
|
|
|
|
{
|
2021-10-19 09:19:50 +00:00
|
|
|
arc("enemy", w.pEnemy)
|
|
|
|
("countdown", w.nCountdown)
|
|
|
|
.Array("sprites", w.pSprites, kSnakeSprites)
|
2020-11-29 23:18:32 +00:00
|
|
|
("run", w.nRun)
|
|
|
|
.Array("c", w.c, countof(w.c))
|
2021-11-21 19:13:19 +00:00
|
|
|
("se", w.nAngle)
|
2020-11-29 23:18:32 +00:00
|
|
|
("player", w.nSnakePlayer)
|
|
|
|
.EndObject();
|
|
|
|
}
|
|
|
|
return arc;
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2020-11-29 23:18:32 +00:00
|
|
|
void SerializeSnake(FSerializer& arc)
|
2019-08-26 03:59:14 +00:00
|
|
|
{
|
2020-11-29 23:18:32 +00:00
|
|
|
arc("snake", SnakeList);
|
|
|
|
arc.Array("playersnake", nPlayerSnake, PlayerCount);
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
|
|
|
|
2020-11-29 23:18:32 +00:00
|
|
|
void InitSnakes()
|
|
|
|
{
|
|
|
|
SnakeList.Clear();
|
2019-08-31 07:47:15 +00:00
|
|
|
memset(nPlayerSnake, 0, sizeof(nPlayerSnake));
|
2019-08-26 03:59:14 +00:00
|
|
|
}
|
|
|
|
|
2021-11-21 19:13:19 +00:00
|
|
|
int GrabSnake()
|
2019-08-26 03:59:14 +00:00
|
|
|
{
|
2020-11-29 23:18:32 +00:00
|
|
|
return SnakeList.Get();
|
2019-08-26 03:59:14 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void DestroySnake(int nSnake)
|
|
|
|
{
|
2021-11-21 19:13:19 +00:00
|
|
|
int nRun = SnakeList[nSnake].nRun;
|
2019-08-31 07:47:15 +00:00
|
|
|
runlist_SubRunRec(nRun);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2019-08-31 07:47:15 +00:00
|
|
|
for (int i = 0; i < kSnakeSprites; i++)
|
|
|
|
{
|
2021-12-07 17:53:02 +00:00
|
|
|
DExhumedActor* pSnake = SnakeList[nSnake].pSprites[i];
|
|
|
|
if (!pSnake) continue;
|
2021-10-19 09:19:50 +00:00
|
|
|
auto pSprite = &pSnake->s();
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-09-06 06:33:02 +00:00
|
|
|
runlist_DoSubRunRec(pSprite->lotag - 1);
|
|
|
|
runlist_DoSubRunRec(pSprite->owner);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
DeleteActor(pSnake);
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2020-11-29 23:18:32 +00:00
|
|
|
SnakeList.Release(nSnake);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2019-08-31 07:47:15 +00:00
|
|
|
if (nSnake == nSnakeCam)
|
|
|
|
{
|
|
|
|
nSnakeCam = -1;
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
}
|
|
|
|
|
2021-11-16 17:50:02 +00:00
|
|
|
void ExplodeSnakeSprite(DExhumedActor* pActor, int nPlayer)
|
2019-08-26 03:59:14 +00:00
|
|
|
{
|
2021-10-19 09:19:50 +00:00
|
|
|
auto pSprite = &pActor->s();
|
2021-11-21 19:13:19 +00:00
|
|
|
int nDamage = BulletInfo[kWeaponStaff].nDamage;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-05-13 17:15:53 +00:00
|
|
|
if (PlayerList[nPlayer].nDouble > 0) {
|
2019-08-31 07:47:15 +00:00
|
|
|
nDamage *= 2;
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2019-08-31 07:47:15 +00:00
|
|
|
// take a copy of this, to revert after call to runlist_RadialDamageEnemy()
|
2021-12-07 17:53:02 +00:00
|
|
|
DExhumedActor* nOwner = pActor->pTarget;
|
2021-10-21 20:39:17 +00:00
|
|
|
pActor->pTarget = PlayerList[nPlayer].pActor;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
runlist_RadialDamageEnemy(pActor, nDamage, BulletInfo[kWeaponStaff].nRadius);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-21 20:39:17 +00:00
|
|
|
pActor->pTarget = nOwner;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-12-22 11:29:00 +00:00
|
|
|
BuildAnim(nullptr, 23, 0, pSprite->pos.X, pSprite->pos.Y, pSprite->pos.Z, pSprite->sector(), 40, 4);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-12-22 11:29:00 +00:00
|
|
|
AddFlash(pSprite->sector(), pSprite->pos.X, pSprite->pos.Y, pSprite->pos.Z, 128);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
StopActorSound(pActor);
|
2019-08-26 03:59:14 +00:00
|
|
|
}
|
|
|
|
|
2021-11-21 19:13:19 +00:00
|
|
|
void BuildSnake(int nPlayer, int zVal)
|
2019-08-26 03:59:14 +00:00
|
|
|
{
|
2019-08-31 07:47:15 +00:00
|
|
|
|
|
|
|
zVal -= 1280;
|
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
auto pPlayerActor = PlayerList[nPlayer].Actor();
|
|
|
|
auto pPlayerSprite = &pPlayerActor->s();
|
2021-11-22 23:20:15 +00:00
|
|
|
auto pViewSect = PlayerList[nPlayer].pPlayerViewSect;
|
2021-11-21 19:13:19 +00:00
|
|
|
int nPic = seq_GetSeqPicnum(kSeqSnakBody, 0, 0);
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2021-12-22 10:57:10 +00:00
|
|
|
int x = pPlayerSprite->pos.X;
|
2021-12-22 11:17:17 +00:00
|
|
|
int y = pPlayerSprite->pos.Y;
|
2021-12-22 11:29:00 +00:00
|
|
|
int z = (pPlayerSprite->pos.Z + zVal) - 2560;
|
2021-11-16 17:41:34 +00:00
|
|
|
int nAngle = pPlayerSprite->ang;
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2021-12-06 11:24:22 +00:00
|
|
|
HitInfo hit{};
|
2021-11-25 23:25:28 +00:00
|
|
|
hitscan({ x, y, z }, pPlayerSprite->sector(), { bcos(nAngle), bsin(nAngle), 0 }, hit, CLIPMASK1);
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2021-12-22 09:40:26 +00:00
|
|
|
uint32_t yDiff = abs(hit.hitpos.Y - y);
|
2021-12-22 09:36:09 +00:00
|
|
|
uint32_t xDiff = abs(hit.hitpos.X - x);
|
2020-06-22 10:24:21 +00:00
|
|
|
|
|
|
|
uint32_t sqrtNum = xDiff * xDiff + yDiff * yDiff;
|
|
|
|
|
|
|
|
if (sqrtNum > INT_MAX)
|
|
|
|
{
|
2020-09-08 16:48:18 +00:00
|
|
|
DPrintf(DMSG_WARNING, "%s %d: overflow\n", __func__, __LINE__);
|
2020-06-22 10:24:21 +00:00
|
|
|
sqrtNum = INT_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
int nSqrt = ksqrt(sqrtNum);
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2020-11-14 09:19:28 +00:00
|
|
|
if (nSqrt < bsin(512, -4))
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2021-12-22 09:40:26 +00:00
|
|
|
BackUpBullet(&hit.hitpos.X, &hit.hitpos.Y, nAngle);
|
2021-11-25 23:25:28 +00:00
|
|
|
auto pActor = insertActor(hit.hitSector, 202);
|
2021-10-19 09:19:50 +00:00
|
|
|
auto pSprite = &pActor->s();
|
2021-12-22 10:57:10 +00:00
|
|
|
pSprite->pos.X = hit.hitpos.X;
|
2021-12-22 11:17:17 +00:00
|
|
|
pSprite->pos.Y = hit.hitpos.Y;
|
2021-12-22 11:29:00 +00:00
|
|
|
pSprite->pos.Z = hit.hitpos.Z;
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
ExplodeSnakeSprite(pActor, nPlayer);
|
|
|
|
DeleteActor(pActor);
|
2021-10-15 16:37:39 +00:00
|
|
|
return;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-10-19 09:19:50 +00:00
|
|
|
DExhumedActor* pTarget = nullptr;
|
2021-11-25 23:25:28 +00:00
|
|
|
auto hitactor = hit.actor();
|
2021-12-21 22:18:23 +00:00
|
|
|
if (hitactor && hitactor->spr.statnum >= 90 && hitactor->spr.statnum <= 199) {
|
2021-10-19 09:19:50 +00:00
|
|
|
pTarget = hitactor;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
2021-10-21 20:18:29 +00:00
|
|
|
else if (sPlayerInput[nPlayer].pTarget != nullptr)
|
2021-10-19 09:19:50 +00:00
|
|
|
{
|
2021-10-21 20:18:29 +00:00
|
|
|
pTarget = sPlayerInput[nPlayer].pTarget;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
|
2021-11-21 19:13:19 +00:00
|
|
|
int nSnake = GrabSnake();
|
2021-10-15 16:37:39 +00:00
|
|
|
if (nSnake == -1) return;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-15 21:31:00 +00:00
|
|
|
// GrabTimeSlot(3);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-11-14 14:03:50 +00:00
|
|
|
DExhumedActor* sprt = nullptr;
|
2019-08-31 07:47:15 +00:00
|
|
|
|
|
|
|
for (int i = 0; i < kSnakeSprites; i++)
|
|
|
|
{
|
2021-11-22 23:20:15 +00:00
|
|
|
auto pActor = insertActor(pViewSect, 202);
|
2021-10-19 09:19:50 +00:00
|
|
|
auto pSprite = &pActor->s();
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
pActor->pTarget = pPlayerActor;
|
|
|
|
//pSprite->owner = nPlayerSprite;
|
2021-09-06 06:33:02 +00:00
|
|
|
pSprite->picnum = nPic;
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2019-11-18 19:38:19 +00:00
|
|
|
if (i == 0)
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2021-12-22 10:57:10 +00:00
|
|
|
pSprite->pos.X = pPlayerSprite->pos.X;
|
2021-12-22 11:17:17 +00:00
|
|
|
pSprite->pos.Y = pPlayerSprite->pos.Y;
|
2021-12-22 11:29:00 +00:00
|
|
|
pSprite->pos.Z = pPlayerSprite->pos.Z + zVal;
|
2021-09-06 06:33:02 +00:00
|
|
|
pSprite->xrepeat = 32;
|
|
|
|
pSprite->yrepeat = 32;
|
2021-11-22 23:20:15 +00:00
|
|
|
pViewSect = pSprite->sector();
|
2021-10-19 09:19:50 +00:00
|
|
|
sprt = pActor;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
2019-11-18 19:38:19 +00:00
|
|
|
else
|
|
|
|
{
|
2021-12-22 10:57:10 +00:00
|
|
|
pSprite->pos.X = sprt->spr.pos.X;
|
2021-12-22 11:17:17 +00:00
|
|
|
pSprite->pos.Y = sprt->spr.pos.Y;
|
2021-12-22 11:29:00 +00:00
|
|
|
pSprite->pos.Z = sprt->spr.pos.Z;
|
2021-10-15 21:31:00 +00:00
|
|
|
pSprite->xrepeat = 40 - 3 * i;
|
|
|
|
pSprite->yrepeat = 40 - 3 * i;
|
2019-11-18 19:38:19 +00:00
|
|
|
}
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2021-09-06 06:33:02 +00:00
|
|
|
pSprite->clipdist = 10;
|
|
|
|
pSprite->cstat = 0;
|
|
|
|
pSprite->shade = -64;
|
|
|
|
pSprite->pal = 0;
|
|
|
|
pSprite->xoffset = 0;
|
|
|
|
pSprite->yoffset = 0;
|
2021-10-18 22:00:52 +00:00
|
|
|
pSprite->ang = pPlayerSprite->ang;
|
2021-09-06 06:33:02 +00:00
|
|
|
pSprite->xvel = 0;
|
|
|
|
pSprite->yvel = 0;
|
|
|
|
pSprite->zvel = 0;
|
|
|
|
pSprite->hitag = 0;
|
|
|
|
pSprite->extra = -1;
|
|
|
|
pSprite->lotag = runlist_HeadRun() + 1;
|
|
|
|
pSprite->backuppos();
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
SnakeList[nSnake].pSprites[i] = pActor;
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2021-10-15 16:37:39 +00:00
|
|
|
pSprite->owner = runlist_AddRunRec(pSprite->lotag - 1, ((nSnake << 8) | i), 0x110000);
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
|
2021-10-15 16:37:39 +00:00
|
|
|
SnakeList[nSnake].nRun = runlist_AddRunRec(NewRun, nSnake, 0x110000);
|
2019-08-31 07:47:15 +00:00
|
|
|
SnakeList[nSnake].c[1] = 2;
|
|
|
|
SnakeList[nSnake].c[5] = 5;
|
|
|
|
SnakeList[nSnake].c[2] = 4;
|
|
|
|
SnakeList[nSnake].c[3] = 6;
|
|
|
|
SnakeList[nSnake].c[4] = 7;
|
|
|
|
SnakeList[nSnake].c[6] = 6;
|
|
|
|
SnakeList[nSnake].c[7] = 7;
|
2021-10-19 09:19:50 +00:00
|
|
|
SnakeList[nSnake].pEnemy = pTarget;
|
|
|
|
SnakeList[nSnake].nCountdown = 0;
|
2021-11-21 19:13:19 +00:00
|
|
|
SnakeList[nSnake].nAngle = 0;
|
2020-11-29 23:18:32 +00:00
|
|
|
SnakeList[nSnake].nSnakePlayer = nPlayer;
|
2019-08-31 07:47:15 +00:00
|
|
|
nPlayerSnake[nPlayer] = nSnake;
|
|
|
|
|
|
|
|
if (bSnakeCam)
|
|
|
|
{
|
|
|
|
if (nSnakeCam < 0) {
|
|
|
|
nSnakeCam = nSnake;
|
|
|
|
}
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
D3PlayFX(StaticSound[kSound6], sprt);
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
}
|
|
|
|
|
2021-11-21 19:13:19 +00:00
|
|
|
DExhumedActor* FindSnakeEnemy(int nSnake)
|
2019-08-26 03:59:14 +00:00
|
|
|
{
|
2021-11-16 17:50:02 +00:00
|
|
|
int nPlayer = SnakeList[nSnake].nSnakePlayer;
|
2021-10-19 09:19:50 +00:00
|
|
|
auto pPlayerActor = PlayerList[nPlayer].Actor();
|
|
|
|
|
2021-12-07 17:53:02 +00:00
|
|
|
DExhumedActor* pActor = SnakeList[nSnake].pSprites[0]; // CHECKME
|
|
|
|
if (!pActor) return nullptr;
|
2021-10-19 09:19:50 +00:00
|
|
|
auto pSprite = &pActor->s();
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2021-11-16 17:41:34 +00:00
|
|
|
int nAngle = pSprite->ang;
|
2021-11-23 00:21:55 +00:00
|
|
|
auto pSector =pSprite->sector();
|
2019-08-31 07:47:15 +00:00
|
|
|
|
|
|
|
int esi = 2048;
|
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
DExhumedActor* pEnemy = nullptr;
|
2019-08-31 07:47:15 +00:00
|
|
|
|
2021-11-23 00:21:55 +00:00
|
|
|
ExhumedSectIterator it(pSector);
|
2021-10-19 09:19:50 +00:00
|
|
|
while (auto pAct2 = it.Next())
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2021-10-19 09:19:50 +00:00
|
|
|
auto pSpr2 = &pAct2->s();
|
2021-12-18 17:40:25 +00:00
|
|
|
if (pSpr2->statnum >= 90 && pSpr2->statnum < 150 && (pSpr2->cstat & CSTAT_SPRITE_BLOCK_ALL))
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2021-12-18 17:40:25 +00:00
|
|
|
if (pAct2 != pPlayerActor && !(pSpr2->cstat & CSTAT_SPRITE_INVISIBLE))
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2021-10-20 21:02:23 +00:00
|
|
|
int nAngle2 = (nAngle - GetAngleToSprite(pActor, pAct2)) & kAngleMask;
|
2019-08-31 07:47:15 +00:00
|
|
|
if (nAngle2 < esi)
|
|
|
|
{
|
2021-10-19 09:19:50 +00:00
|
|
|
pEnemy = pAct2;
|
2019-08-31 07:47:15 +00:00
|
|
|
esi = nAngle2;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
if (pEnemy)
|
2019-11-18 19:38:19 +00:00
|
|
|
{
|
2021-10-19 09:19:50 +00:00
|
|
|
SnakeList[nSnake].pEnemy = pEnemy;
|
|
|
|
SnakeList[nSnake].nCountdown = 0;
|
2019-11-18 19:38:19 +00:00
|
|
|
}
|
|
|
|
else
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2021-10-19 09:19:50 +00:00
|
|
|
SnakeList[nSnake].nCountdown--;
|
|
|
|
if (SnakeList[nSnake].nCountdown < -25)
|
2019-08-31 07:47:15 +00:00
|
|
|
{
|
2021-10-19 09:19:50 +00:00
|
|
|
pEnemy = pPlayerActor;
|
|
|
|
SnakeList[nSnake].pEnemy = pPlayerActor;
|
2019-08-31 07:47:15 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
return pEnemy;
|
2019-08-26 03:59:14 +00:00
|
|
|
}
|
|
|
|
|
2021-10-15 21:31:00 +00:00
|
|
|
void AISnake::Tick(RunListEvent* ev)
|
2019-08-26 03:59:14 +00:00
|
|
|
{
|
2021-11-21 19:13:19 +00:00
|
|
|
int nSnake = RunData[ev->nRun].nObjIndex;
|
2021-10-15 21:31:00 +00:00
|
|
|
assert(nSnake >= 0 && nSnake < kMaxSnakes);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-12-07 17:53:02 +00:00
|
|
|
DExhumedActor* pActor = SnakeList[nSnake].pSprites[0];
|
|
|
|
if (!pActor) return;
|
2021-10-19 09:19:50 +00:00
|
|
|
auto pSprite = &pActor->s();
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
seq_MoveSequence(pActor, SeqOffsets[kSeqSnakehed], 0);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-12-07 17:53:02 +00:00
|
|
|
DExhumedActor* pEnemySprite = SnakeList[nSnake].pEnemy;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
Collision nMov;
|
2021-10-15 21:31:00 +00:00
|
|
|
int zVal;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
if (pEnemySprite == nullptr)
|
2021-10-15 21:31:00 +00:00
|
|
|
{
|
|
|
|
SEARCH_ENEMY:
|
2021-10-19 09:19:50 +00:00
|
|
|
nMov = movesprite(pActor,
|
2021-10-15 21:31:00 +00:00
|
|
|
600 * bcos(pSprite->ang),
|
|
|
|
600 * bsin(pSprite->ang),
|
2021-11-21 19:13:19 +00:00
|
|
|
bsin(SnakeList[nSnake].nAngle, -5),
|
2021-10-15 21:31:00 +00:00
|
|
|
0, 0, CLIPMASK1);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-15 21:31:00 +00:00
|
|
|
FindSnakeEnemy(nSnake);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-15 21:31:00 +00:00
|
|
|
zVal = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-12-21 22:18:23 +00:00
|
|
|
if (!(pEnemySprite->spr.cstat & CSTAT_SPRITE_BLOCK_ALL))
|
2021-10-15 21:31:00 +00:00
|
|
|
{
|
2021-10-19 09:19:50 +00:00
|
|
|
SnakeList[nSnake].pEnemy = nullptr;
|
2021-10-15 21:31:00 +00:00
|
|
|
goto SEARCH_ENEMY;
|
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-12-22 11:29:00 +00:00
|
|
|
zVal = pSprite->pos.Z;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-11-21 19:13:19 +00:00
|
|
|
nMov = AngleChase(pActor, pEnemySprite, 1200, SnakeList[nSnake].nAngle, 32);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-12-22 11:29:00 +00:00
|
|
|
zVal = pSprite->pos.Z - zVal;
|
2021-10-15 21:31:00 +00:00
|
|
|
}
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
if (nMov.type || nMov.exbits)
|
2021-10-15 21:31:00 +00:00
|
|
|
{
|
2021-11-16 17:50:02 +00:00
|
|
|
int nPlayer = SnakeList[nSnake].nSnakePlayer;
|
2021-10-19 09:19:50 +00:00
|
|
|
ExplodeSnakeSprite(SnakeList[nSnake].pSprites[0], nPlayer);
|
2019-11-20 16:21:32 +00:00
|
|
|
|
2021-10-15 21:31:00 +00:00
|
|
|
nPlayerSnake[nPlayer] = -1;
|
|
|
|
SnakeList[nSnake].nSnakePlayer = -1;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-15 21:31:00 +00:00
|
|
|
DestroySnake(nSnake);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2021-11-16 17:41:34 +00:00
|
|
|
int nAngle = pSprite->ang;
|
2021-10-15 21:31:00 +00:00
|
|
|
int var_30 = -bcos(nAngle, 6);
|
|
|
|
int var_34 = -bsin(nAngle, 6);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-11-21 19:13:19 +00:00
|
|
|
int var_20 = SnakeList[nSnake].nAngle;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-11-21 19:13:19 +00:00
|
|
|
SnakeList[nSnake].nAngle = (SnakeList[nSnake].nAngle + 64) & 0x7FF;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-15 21:31:00 +00:00
|
|
|
int var_28 = (nAngle + 512) & kAngleMask;
|
2021-11-23 00:15:28 +00:00
|
|
|
auto pSector = pSprite->sector();
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-12-22 10:57:10 +00:00
|
|
|
int x = pSprite->pos.X;
|
2021-12-22 11:17:17 +00:00
|
|
|
int y = pSprite->pos.Y;
|
2021-12-22 11:29:00 +00:00
|
|
|
int z = pSprite->pos.Z;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-15 21:31:00 +00:00
|
|
|
for (int i = 7; i > 0; i--)
|
|
|
|
{
|
2021-12-07 17:53:02 +00:00
|
|
|
DExhumedActor* pActor2 = SnakeList[nSnake].pSprites[i];
|
|
|
|
if (!pActor2) continue;
|
2021-10-19 09:19:50 +00:00
|
|
|
auto pSprite2 = &pActor2->s();
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
pSprite2->ang = nAngle;
|
2021-12-22 10:57:10 +00:00
|
|
|
pSprite2->pos.X = x;
|
2021-12-22 11:17:17 +00:00
|
|
|
pSprite2->pos.Y = y;
|
2021-12-22 11:29:00 +00:00
|
|
|
pSprite2->pos.Z = z;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-11-23 00:15:28 +00:00
|
|
|
ChangeActorSect(pActor2, pSector);
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-15 21:31:00 +00:00
|
|
|
int eax = (bsin(var_20) * SnakeList[nSnake].c[i]) >> 9;
|
2019-08-26 03:59:14 +00:00
|
|
|
|
2021-10-19 09:19:50 +00:00
|
|
|
movesprite(pActor2, var_30 + var_30 * i + eax * bcos(var_28), var_30 + var_34 * i + eax * bsin(var_28),
|
2021-10-15 21:31:00 +00:00
|
|
|
-zVal * (i - 1), 0, 0, CLIPMASK1);
|
2019-11-20 16:21:32 +00:00
|
|
|
|
2021-10-15 21:31:00 +00:00
|
|
|
var_20 = (var_20 + 128) & kAngleMask;
|
2019-11-18 19:38:19 +00:00
|
|
|
}
|
2021-10-15 21:31:00 +00:00
|
|
|
}
|
|
|
|
}
|
2019-11-18 19:38:19 +00:00
|
|
|
|
2021-10-15 21:31:00 +00:00
|
|
|
void AISnake::Draw(RunListEvent* ev)
|
|
|
|
{
|
2021-11-09 12:40:20 +00:00
|
|
|
int nSnake = RunData[ev->nRun].nObjIndex;
|
|
|
|
int nSprite = ev->nParam;
|
2019-11-18 19:38:19 +00:00
|
|
|
|
2021-10-15 21:31:00 +00:00
|
|
|
if ((nSnake & 0xFF) == 0) {
|
|
|
|
seq_PlotSequence(nSprite, SeqOffsets[kSeqSnakehed], 0, 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
seq_PlotSequence(nSprite, SeqOffsets[kSeqSnakBody], 0, 0);
|
|
|
|
}
|
2019-11-18 19:38:19 +00:00
|
|
|
|
2021-12-04 18:08:50 +00:00
|
|
|
ev->pTSprite->ownerActor = nullptr;
|
2021-10-15 21:31:00 +00:00
|
|
|
}
|
2019-11-18 19:38:19 +00:00
|
|
|
|
2019-11-22 23:11:37 +00:00
|
|
|
END_PS_NS
|