#pragma once #include "gamehud.h" #include "global.h" #include "models/modeldata.h" #include "texinfo.h" #include "funct.h" #include "mapinfo.h" // all inline functions. BEGIN_DUKE_NS inline DDukePlayer* getPlayer(int index) { return static_cast(PlayerArray[index]); } inline int rnd(int X) { return ((krand() >> 8) >= (255 - (X))); } // internal controller classes can be directly checked for by type inline int ismasterswitch(DDukeActor* actor) { // The STAT_REMOVED check here is important! return actor->GetClass() == DukeMasterSwitchClass && actor->spr.statnum != STAT_REMOVED; } inline int issoundcontroller(DDukeActor* actor) { return actor->GetClass() == DukeSoundControllerClass; } inline int isrespawncontroller(DDukeActor* actor) { return actor->GetClass() == DukeRespawnControllerClass; } inline int isactivator(DDukeActor* actor) { return actor->GetClass() == DukeActivatorClass; } inline int islockedactivator(DDukeActor* actor) { return actor->GetClass() == DukeActivatorLockedClass; } inline int islocator(DDukeActor* actor) { return actor->GetClass() == DukeLocatorClass; } inline int iseffector(DDukeActor* actor) { return actor->GetClass() == DukeSectorEffectorClass; } inline bool inventory(DDukeActor* S) { return S->flags1 & SFLAG_INVENTORY; } inline bool wallswitchcheck(DDukeActor* s) { return !!(tileflags(s->spr.spritetexture()) & TFLAG_WALLSWITCH); } inline bool isadoorwall(FTextureID dapic) { return tileflags(dapic) & TFLAG_DOORWALL; } inline bool isablockdoor(FTextureID dapic) { return tileflags(dapic) & TFLAG_BLOCKDOOR; } inline int checkcursectnums(sectortype* se) { for (int i = connecthead; i >= 0; i = connectpoint2[i]) { const auto pact = getPlayer(i)->GetActor(); if (pact && pact->sector() == se) return i; } return -1; } inline bool isIn(int value, int first) { return value == first; } template bool isIn(int value, int first, Args... args) { return value == first || isIn(value, args...); } inline bool isIn(int value, const std::initializer_list& list) { for (auto v : list) if (v == value) return true; return false; } inline void clearfriction() { for (int i = 0; i != -1; i = connectpoint2[i]) { getPlayer(i)->fric.Zero(); } } inline void SetPlayerPal(DDukePlayer* p, PalEntry pe) { p->pals = pe; } inline bool playrunning() { return (paused == 0 || (paused == 1 && (ud.recstat == 2 || ud.multimode > 1))); } //--------------------------------------------------------------------------- // // // //--------------------------------------------------------------------------- inline ESpriteFlags randomFlip() { int r = krand() & 12; if (r == 0) return 0; if (r == 4) return CSTAT_SPRITE_XFLIP; if (r == 8) return CSTAT_SPRITE_YFLIP; return CSTAT_SPRITE_XFLIP | CSTAT_SPRITE_YFLIP; } inline ESpriteFlags randomXFlip() { int r = krand() & 4; if (r == 0) return 0; return CSTAT_SPRITE_XFLIP; } inline DAngle randomAngle(double span = 360.) { return DAngle::fromDeg(krandf(span)); } inline DAngle randomAngle(DAngle span) { return DAngle::fromDeg(krandf(span.Degrees())); } inline int angletorotation1(DAngle sprang, DAngle viewang, int shiftv = 8, int andv = 7) { return (((sprang.Buildang() + 3072 + 128 - viewang.Buildang()) & 2047) >> shiftv) & andv; } inline int angletorotation2(DAngle sprang, DAngle viewang) { return ((sprang.Buildang() + 3072 + 128 - viewang.Buildang()) & 2047) / 170; } // 4 (8) frame rotation. inline void applyRotation1(DDukeActor* h, tspritetype* t, DAngle viewang, FTextureID base = FNullTextureID()) { if (tilehasmodelorvoxel(h->spr.spritetexture(), h->spr.pal)) { t->cstat &= ~CSTAT_SPRITE_XFLIP; return; } int k = angletorotation1(t->Angles.Yaw, viewang); if (k > 4) { k = 8 - k; t->cstat |= CSTAT_SPRITE_XFLIP; } else t->cstat &= ~CSTAT_SPRITE_XFLIP; if (base.isNull()) base = h->spr.spritetexture(); t->setspritetexture(base + k); } // 6 (12) frame rotation. inline void applyRotation2(DDukeActor* h, tspritetype* t, DAngle viewang, FTextureID base = FNullTextureID()) { if (tilehasmodelorvoxel(h->spr.spritetexture(), h->spr.pal)) { t->cstat &= ~CSTAT_SPRITE_XFLIP; return; } int k = angletorotation2(t->Angles.Yaw, viewang); if (k > 6) { k = 12 - k; t->cstat |= CSTAT_SPRITE_XFLIP; } else t->cstat &= ~CSTAT_SPRITE_XFLIP; if (base.isNull()) base = h->spr.spritetexture(); t->setspritetexture(base + k); } inline int monsterCheatCheck(DDukeActor* self) { if (ud.multimode < 2) { if (actor_tog == 1) { self->spr.cstat = CSTAT_SPRITE_INVISIBLE; return true; } else if (actor_tog == 2) self->spr.cstat = CSTAT_SPRITE_BLOCK_ALL; } return false; } inline void rotateInputVel(DDukePlayer* const p) { p->cmd.ucmd.vel.XY() = p->cmd.ucmd.vel.XY().Rotated(p->GetActor()->spr.Angles.Yaw) + p->fric; } inline const ActorInfo* DDukeActor::conInfo() const { auto tn = static_cast(GetClass())->ActorInfo()->TypeNum; return tn < 0 || gs.actorinfo[tn].scriptaddress == 0 ? nullptr : &gs.actorinfo[tn]; } inline bool DDukeActor::isPlayer() const { return IsKindOf(DukePlayerBaseClass); } inline bool shrinkersizecheck(PClass* type, DDukeActor* act2) { // this should be a damage type check, not a projectile type check. // It's also quite broken because it doesn't check for being shrunk but tries to guess it from the size. // Unfortunately, with CON there is no way to retrieve proper shrunk state in any way. return type != DukeShrinkSparkClass || (act2->spr.scale.X >= 0.375); } inline void setPlayerActorViewZOffset(DDukeActor* const pact) { if (!PlayClock) { pact->spr.pos.Z += gs.playerheight; pact->opos.Z += gs.playerheight; pact->oviewzoffset = pact->viewzoffset = -gs.playerheight; } } // flag mess to avoid double counting of kills. // this is still not foolproof because CON requires manually recording the kills. inline void addtokills(DDukeActor* actor) { if (actor->flags1 & SFLAG_KILLCOUNT) { Level.addKillCount(1); actor->spr.cstat2 |= CSTAT2_SPRITE_COUNTKILL; } } inline void addkill(DDukeActor* actor) { if ((actor->flags1 & SFLAG_KILLCOUNT) && (actor->spr.cstat2 & CSTAT2_SPRITE_COUNTKILL)) { Level.addKill(myconnectindex); actor->spr.cstat2 &= ~CSTAT2_SPRITE_COUNTKILL; } } inline void subkill(DDukeActor* actor) { if ((actor->flags1 & SFLAG_KILLCOUNT) && !(actor->spr.cstat2 & CSTAT2_SPRITE_COUNTKILL)) { Level.addKill(-1, -1); // only deduct from global, not from player kills actor->spr.cstat2 |= CSTAT2_SPRITE_COUNTKILL; } } inline void dokill(DDukePlayer* p, DDukeActor* g_ac, int amount) { if (g_ac->spriteextra < 1 || g_ac->spriteextra == 128 || !isRR()) { if (amount > 0) addkill(g_ac); else if (amount < 0) subkill(g_ac); } g_ac->actorstayput = nullptr; } END_DUKE_NS