diff --git a/source/CMakeLists.txt b/source/CMakeLists.txt index 45922db53..01365773e 100644 --- a/source/CMakeLists.txt +++ b/source/CMakeLists.txt @@ -1305,6 +1305,7 @@ unset( PCH_SOURCES ) unset( HEADER_FILES ) unset( NOT_COMPILED_SOURCE_FILES ) +add_subdirectory( duke ) add_subdirectory( duke3d ) add_subdirectory( blood ) add_subdirectory( rr ) diff --git a/source/core/gamecontrol.cpp b/source/core/gamecontrol.cpp index 0d808b01c..d94c19bf0 100644 --- a/source/core/gamecontrol.cpp +++ b/source/core/gamecontrol.cpp @@ -419,6 +419,10 @@ void UserConfig::ProcessOptions() // //========================================================================== +namespace Duke3d +{ + ::GameInterface* CreateInterface(); +} namespace Duke { ::GameInterface* CreateInterface(); @@ -445,6 +449,7 @@ extern int MinFPSRate; // this is a bit messy. void CheckFrontend(int flags) { + auto old = Args->CheckValue("-duke_old"); MinFPSRate = 30; bool duke_compat = duke_compatibility_15; // This point is too early to have cmdline CVAR checkers working so it must be with a switch. @@ -458,10 +463,6 @@ void CheckFrontend(int flags) { gi = Blood::CreateInterface(); } - else if (flags & GAMEFLAG_RRALL) - { - gi = Redneck::CreateInterface(); - } else if (flags & GAMEFLAG_SW) { MinFPSRate = 40; @@ -471,6 +472,14 @@ void CheckFrontend(int flags) { gi = Powerslave::CreateInterface(); } + else if (old) + { + gi = Duke3d::CreateInterface(); + } + else if (flags & GAMEFLAG_RRALL) + { + gi = Redneck::CreateInterface(); + } else if ((flags & GAMEFLAG_FURY) || GameStartupInfo.modern > 0) { gi = Duke::CreateInterface(); diff --git a/source/core/menu/menu.cpp b/source/core/menu/menu.cpp index 3f75d5b18..0bbdc2d70 100644 --- a/source/core/menu/menu.cpp +++ b/source/core/menu/menu.cpp @@ -57,6 +57,7 @@ #include "v_video.h" void RegisterDukeMenus(); +void RegisterDuke3dMenus(); void RegisterRedneckMenus(); void RegisterBloodMenus(); void RegisterSWMenus(); @@ -1017,6 +1018,7 @@ void M_PreviousMenu() void M_Init (void) { RegisterDukeMenus(); + RegisterDuke3dMenus(); RegisterRedneckMenus(); RegisterBloodMenus(); RegisterSWMenus(); diff --git a/source/core/ns.h b/source/core/ns.h index 8ad103b2d..b97f6907a 100644 --- a/source/core/ns.h +++ b/source/core/ns.h @@ -2,9 +2,12 @@ #ifndef NO_NAMESPACE -#define BEGIN_DUKE_NS namespace Duke { +#define BEGIN_DUKE_NS namespace Duke3d { #define END_DUKE_NS } +#define BEGIN_EDUKE_NS namespace Duke { +#define END_EDUKE_NS } + #define BEGIN_RR_NS namespace Redneck { #define END_RR_NS } @@ -19,6 +22,9 @@ #else +#define BEGIN_EDUKE_NS +#define END_EDUKE_NS + #define BEGIN_DUKE_NS #define END_DUKE_NS diff --git a/source/duke/CMakeLists.txt b/source/duke/CMakeLists.txt new file mode 100644 index 000000000..33b806f9d --- /dev/null +++ b/source/duke/CMakeLists.txt @@ -0,0 +1,30 @@ + +set( PCH_SOURCES + src/actors.cpp + src/anim.cpp + src/cheats.cpp + src/cmdline.cpp + src/common.cpp + src/config.cpp + src/d_menu.cpp + src/demo.cpp + src/game.cpp + src/gamedef.cpp + src/gameexec.cpp + src/gamevars.cpp + src/global.cpp + src/namesdyn.cpp + src/net.cpp + src/osdcmds.cpp + src/player.cpp + src/premap.cpp + src/savegame.cpp + src/sbar.cpp + src/screens.cpp + src/text.cpp + src/sector.cpp + src/sounds.cpp + src/soundsdyn.cpp + src/rrdh.cpp) + +add_game_library( duke ) diff --git a/source/duke/src/actors.cpp b/source/duke/src/actors.cpp new file mode 100644 index 000000000..99819e602 --- /dev/null +++ b/source/duke/src/actors.cpp @@ -0,0 +1,9748 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! + +#define actors_c_ + +#include "duke3d.h" + +BEGIN_DUKE_NS + +#if KRANDDEBUG +# define ACTOR_STATIC +#else +# define ACTOR_STATIC static +#endif + +#define DELETE_SPRITE_AND_CONTINUE(KX) do { A_DeleteSprite(KX); goto next_sprite; } while (0) + +int32_t otherp; + +int G_SetInterpolation(int32_t *const posptr) +{ + if (g_interpolationCnt >= MAXINTERPOLATIONS) + return 1; + + for (bssize_t i = 0; i < g_interpolationCnt; ++i) + if (curipos[i] == posptr) + return 0; + + curipos[g_interpolationCnt] = posptr; + oldipos[g_interpolationCnt] = *posptr; + g_interpolationCnt++; + return 0; +} + +void G_StopInterpolation(const int32_t * const posptr) +{ + for (bssize_t i = 0; i < g_interpolationCnt; ++i) + if (curipos[i] == posptr) + { + g_interpolationCnt--; + oldipos[i] = oldipos[g_interpolationCnt]; + bakipos[i] = bakipos[g_interpolationCnt]; + curipos[i] = curipos[g_interpolationCnt]; + } +} + +void G_DoInterpolations(int smoothRatio) +{ + if (g_interpolationLock++) + return; + + int32_t ndelta = 0; + + for (bssize_t i = 0, j = 0; i < g_interpolationCnt; ++i) + { + int32_t const odelta = ndelta; + bakipos[i] = *curipos[i]; + ndelta = (*curipos[i]) - oldipos[i]; + if (odelta != ndelta) + j = mulscale16(ndelta, smoothRatio); + *curipos[i] = oldipos[i] + j; + } +} + +void G_ClearCameraView(DukePlayer_t *ps) +{ + ps->newowner = -1; + ps->pos = ps->opos; + ps->q16ang = ps->oq16ang; + + updatesector(ps->pos.x, ps->pos.y, &ps->cursectnum); + P_UpdateScreenPal(ps); + + for (bssize_t SPRITES_OF(STAT_ACTOR, k)) + if (sprite[k].picnum==CAMERA1) + sprite[k].yvel = 0; +} + +// Manhattan distance between wall-point and sprite. +static FORCE_INLINE int32_t G_WallSpriteDist(uwalltype const * const wal, uspritetype const * const spr) +{ + return klabs(wal->x - spr->x) + klabs(wal->y - spr->y); +} + +void A_RadiusDamage(int spriteNum, int blastRadius, int dmg1, int dmg2, int dmg3, int dmg4) +{ + uspritetype const *const pSprite = (uspritetype *)&sprite[spriteNum]; + + int32_t sectorCount = 0; + int32_t numSectors = 1; + int16_t sectorList[64] = { pSprite->sectnum }; + + if ((pSprite->picnum == RPG && pSprite->xrepeat < 11) + || (RRRA && pSprite->picnum == RPG2 && pSprite->xrepeat < 11) + || (!RR && pSprite->picnum == SHRINKSPARK)) + goto SKIPWALLCHECK; + + do + { + int const sectorNum = sectorList[sectorCount++]; + int const startWall = sector[sectorNum].wallptr; + int const endWall = startWall + sector[sectorNum].wallnum; + int const w2 = wall[startWall].point2; + + // Check if "hit" 1st or 3rd wall-point. This mainly makes sense + // for rectangular "ceiling light"-style sectors. + if (G_WallSpriteDist((uwalltype *)&wall[startWall], pSprite) < blastRadius || + G_WallSpriteDist((uwalltype *)&wall[wall[w2].point2], pSprite) < blastRadius) + { + if (((sector[sectorNum].ceilingz-pSprite->z)>>8) < blastRadius) + Sect_DamageCeiling(sectorNum); + } + + native_t w = startWall; + + for (uwalltype const *pWall = (uwalltype *)&wall[startWall]; w < endWall; w++, pWall++) + { + if (G_WallSpriteDist(pWall, pSprite) >= blastRadius) + continue; + + int const nextSector = pWall->nextsector; + + if (nextSector >= 0) + { + native_t otherSector = 0; + + for (; otherSector < numSectors; ++otherSector) + if (sectorList[otherSector] == nextSector) + break; + + if (otherSector == numSectors) + { + if (numSectors == ARRAY_SIZE(sectorList)) + goto SKIPWALLCHECK; // prevent oob access of 'sectorlist' + + sectorList[numSectors++] = nextSector; + } + } + + int16_t damageSector = (nextSector >= 0) ? wall[wall[w].nextwall].nextsector : sectorofwall(w); + vec3_t const vect = { (((pWall->x + wall[pWall->point2].x) >> 1) + pSprite->x) >> 1, + (((pWall->y + wall[pWall->point2].y) >> 1) + pSprite->y) >> 1, pSprite->z }; + + updatesector(vect.x, vect.y, &damageSector); + + if (damageSector >= 0 && cansee(vect.x, vect.y, pSprite->z, damageSector, pSprite->x, pSprite->y, pSprite->z, pSprite->sectnum)) + A_DamageWall(spriteNum, w, &vect, pSprite->picnum); + } + } + while (sectorCount < numSectors); + +SKIPWALLCHECK: + + // this is really weird + int32_t const zRand = (RR ? -(24<<8) : -ZOFFSET2) + (krand2()&(ZOFFSET5-1)); + + static const uint8_t statnumList [] ={ + STAT_DEFAULT, STAT_ACTOR, STAT_STANDABLE, + STAT_PLAYER, STAT_FALLER, STAT_ZOMBIEACTOR, STAT_MISC + }; + + for (unsigned char stati : statnumList) + { + int32_t otherSprite = headspritestat[stati]; + + while (otherSprite >= 0) + { + int const nextOther = nextspritestat[otherSprite]; + spritetype *const pOther = &sprite[otherSprite]; + + // DEFAULT, ZOMBIEACTOR, MISC + if (stati == STAT_DEFAULT || stati == STAT_ZOMBIEACTOR || stati == STAT_MISC || AFLAMABLE(pOther->picnum)) + { + if ((!RR && pSprite->picnum != SHRINKSPARK) || (pOther->cstat&257)) + { + if (dist(pSprite, pOther) < blastRadius) + { + if (A_CheckEnemySprite(pOther) && !cansee(pOther->x, pOther->y, pOther->z+zRand, pOther->sectnum, pSprite->x, pSprite->y, pSprite->z+zRand, pSprite->sectnum)) + goto next_sprite; + A_DamageObject(otherSprite, spriteNum); + } + } + } + else if (pOther->extra >= 0 && (uspritetype *)pOther != pSprite && ((pOther->cstat & 257) || + (!RR && pOther->picnum == TRIPBOMB) || pOther->picnum == QUEBALL || (RR && pOther->picnum == RRTILE3440) || pOther->picnum == STRIPEBALL || pOther->picnum == DUKELYINGDEAD || + A_CheckEnemySprite(pOther))) + { + if ((!RR && pSprite->picnum == SHRINKSPARK && pOther->picnum != SHARK && (otherSprite == pSprite->owner || pOther->xrepeat < 24)) + || (pSprite->picnum == MORTER && otherSprite == pSprite->owner) + || (RRRA && ((pSprite->picnum == CHEERBOMB && otherSprite == pSprite->owner) || (pOther->picnum == MINION && pOther->pal == 19)))) + goto next_sprite; + int32_t const spriteDist = pOther->picnum == APLAYER + ? FindDistance3D(pSprite->x - pOther->x, pSprite->y - pOther->y, pSprite->z - (pOther->z - PHEIGHT)) + : dist(pSprite, pOther); + + if (spriteDist >= blastRadius || !cansee(pOther->x, pOther->y, pOther->z - ZOFFSET3, pOther->sectnum, pSprite->x, + pSprite->y, pSprite->z - ZOFFSET4, pSprite->sectnum)) + goto next_sprite; + + actor_t & dmgActor = actor[otherSprite]; + + dmgActor.ang = getangle(pOther->x - pSprite->x, pOther->y - pSprite->y); + + if (RRRA && pOther->extra > 0 && pSprite->picnum == RPG2) + dmgActor.picnum = RPG; + else if ((pOther->extra > 0 && pSprite->picnum == RPG) + || (!RR && pSprite->picnum == SHRINKSPARK)) + dmgActor.picnum = pSprite->picnum; + else dmgActor.picnum = RADIUSEXPLOSION; + + if (RR || pSprite->picnum != SHRINKSPARK) + { + if (spriteDist < blastRadius/3) + { + if (dmg4 == dmg3) dmg4++; + dmgActor.extra = dmg3 + (krand2()%(dmg4-dmg3)); + } + else if (spriteDist < (2*blastRadius)/3) + { + if (dmg3 == dmg2) dmg3++; + dmgActor.extra = dmg2 + (krand2()%(dmg3-dmg2)); + } + else if (spriteDist < blastRadius) + { + if (dmg2 == dmg1) dmg2++; + dmgActor.extra = dmg1 + (krand2()%(dmg2-dmg1)); + } + + if (!A_CheckSpriteFlags(otherSprite, SFLAG_NODAMAGEPUSH)) + { + if (pOther->xvel < 0) pOther->xvel = 0; + pOther->xvel += ((RR ? pOther->extra : pSprite->extra)<<2); + } + + switch (DYNAMICTILEMAP(pOther->picnum)) + { + case PODFEM1__STATIC: + case FEM1__STATIC: + case FEM2__STATIC: + case FEM3__STATIC: + case FEM4__STATIC: + case FEM5__STATIC: + case FEM6__STATIC: + case FEM7__STATIC: + case FEM8__STATIC: + case FEM9__STATIC: + case FEM10__STATIC: + case SPACEMARINE__STATIC: if (RR) break; fallthrough__; + case STATUE__STATIC: + case STATUEFLASH__STATIC: + case QUEBALL__STATIC: + case RRTILE3440__STATICRR: + case STRIPEBALL__STATIC: A_DamageObject(otherSprite, spriteNum); + default: break; + } + } + else if (pSprite->extra == 0) dmgActor.extra = 0; + + if (pOther->picnum != RADIUSEXPLOSION && + pSprite->owner >= 0 && sprite[pSprite->owner].statnum < MAXSTATUS) + { + if (pOther->picnum == APLAYER) + { + DukePlayer_t *pPlayer = g_player[P_GetP((uspritetype *)pOther)].ps; + + if (pPlayer->newowner >= 0) + G_ClearCameraView(pPlayer); + } + + dmgActor.owner = pSprite->owner; + } + } +next_sprite: + otherSprite = nextOther; + } + } +} + +// Check whether sprite is on/in a non-SE7 water sector. +// : if not NULL, the sector on the other side. +int A_CheckNoSE7Water(uspritetype const * const pSprite, int sectNum, int sectLotag, int32_t *pOther) +{ + if (sectLotag == ST_1_ABOVE_WATER || sectLotag == ST_2_UNDERWATER) + { + int const otherSect = + yax_getneighborsect(pSprite->x, pSprite->y, sectNum, sectLotag == ST_1_ABOVE_WATER ? YAX_FLOOR : YAX_CEILING); + int const otherLotag = (sectLotag == ST_1_ABOVE_WATER) ? ST_2_UNDERWATER : ST_1_ABOVE_WATER; + + // If submerging, the lower sector MUST have lotag 2. + // If emerging, the upper sector MUST have lotag 1. + // This way, the x/y coordinates where above/below water + // changes can happen are the same. + if (otherSect >= 0 && sector[otherSect].lotag == otherLotag) + { + if (pOther) + *pOther = otherSect; + return 1; + } + } + + return 0; +} + +// Check whether to do a z position update of sprite . +// Returns: +// 0 if no. +// 1 if yes, but stayed inside [actor[].ceilingz+1, actor[].floorz]. +// <0 if yes, but passed a TROR no-SE7 water boundary. -returnvalue-1 is the +// other-side sector number. +static int32_t A_CheckNeedZUpdate(int32_t spriteNum, int32_t zChange, int32_t *pZcoord) +{ + uspritetype const *const pSprite = (uspritetype *)&sprite[spriteNum]; + int const newZ = pSprite->z + (zChange >> 1); + + *pZcoord = newZ; + + if (newZ > actor[spriteNum].ceilingz && newZ <= actor[spriteNum].floorz) + return 1; + +#ifdef YAX_ENABLE + int const sectNum = pSprite->sectnum; + int const sectLotag = sector[sectNum].lotag; + int32_t otherSect; + + // Non-SE7 water. + // PROJECTILE_CHSECT + if ((zChange < 0 && sectLotag == ST_2_UNDERWATER) || (zChange > 0 && sectLotag == ST_1_ABOVE_WATER)) + { + if (A_CheckNoSE7Water(pSprite, sprite[spriteNum].sectnum, sectLotag, &otherSect)) + { + A_Spawn(spriteNum, WATERSPLASH2); + // NOTE: Don't tweak its z position afterwards like with + // SE7-induced projectile teleportation. It doesn't look good + // with TROR water. + + actor[spriteNum].flags |= SFLAG_DIDNOSE7WATER; + return -otherSect-1; + } + } +#endif + + return 0; +} + +int32_t A_MoveSprite(int32_t spriteNum, vec3_t const * const change, uint32_t clipType) +{ + spritetype *const pSprite = &sprite[spriteNum]; + int const isEnemy = A_CheckEnemySprite(pSprite); + vec2_t const oldPos = *(vec2_t *)pSprite; + + if (pSprite->statnum == STAT_MISC || (isEnemy && pSprite->xrepeat < 4)) + { + pSprite->x += change->x; + pSprite->y += change->y; + pSprite->z += change->z; + + if (isEnemy) + setsprite(spriteNum, (vec3_t *)pSprite); + + return 0; + } + + int32_t clipDist; + + if (isEnemy) + { + if (RR) + clipDist = 192; + else if (pSprite->xrepeat > 60) + clipDist = 1024; + else if (pSprite->picnum == LIZMAN) + clipDist = 292; + else if (A_CheckSpriteFlags(spriteNum, SFLAG_BADGUY)) + clipDist = pSprite->clipdist<<2; + else + clipDist = 192; + } + else + { + if (pSprite->statnum == STAT_PROJECTILE) + clipDist = 8; + else if (RR) + clipDist = 128; + else + clipDist = pSprite->clipdist<<2; + } + + int16_t newSectnum = pSprite->sectnum; + int32_t newZ = pSprite->z - 2 * tilesiz[pSprite->picnum].y * pSprite->yrepeat; + int const oldZ = pSprite->z; + + // Handle horizontal movement first. + pSprite->z = newZ; + int returnValue = + clipmove((vec3_t *)pSprite, &newSectnum, change->x << 13, change->y << 13, clipDist, ZOFFSET6, ZOFFSET6, clipType); + pSprite->z = oldZ; + + if (isEnemy) + { + // Handle potential stayput condition (map-provided or hard-coded). + if (newSectnum < 0 + || ((actor[spriteNum].actorstayput >= 0 && actor[spriteNum].actorstayput != newSectnum) + || (!RR && ((pSprite->picnum == BOSS2 && pSprite->pal == 0 && sector[newSectnum].lotag != ST_3) + || ((pSprite->picnum == BOSS1 || pSprite->picnum == BOSS2) && sector[newSectnum].lotag == ST_1_ABOVE_WATER) + || (sector[newSectnum].lotag == ST_1_ABOVE_WATER + && (pSprite->picnum == LIZMAN || (pSprite->picnum == LIZTROOP && pSprite->zvel == 0))))) + )) + { + *(vec2_t *) pSprite = oldPos; + + if ((newSectnum >= 0 && sector[newSectnum].lotag == ST_1_ABOVE_WATER && (RR || pSprite->picnum == LIZMAN)) + || ((AC_COUNT(actor[spriteNum].t_data)&3) == 1 && (RR || pSprite->picnum != COMMANDER))) + pSprite->ang = krand2()&2047; + + setsprite(spriteNum, (vec3_t *)pSprite); + + if (newSectnum < 0) + newSectnum = 0; + + return 16384+newSectnum; + } + + if ((returnValue&49152) >= 32768 && actor[spriteNum].cgg==0) + pSprite->ang += 768; + } + + if (newSectnum == -1) + { + newSectnum = pSprite->sectnum; +// Printf("%s:%d wtf\n",__FILE__,__LINE__); + } + else if (newSectnum != pSprite->sectnum) + { + changespritesect(spriteNum, newSectnum); + // A_GetZLimits(spritenum); + } + + Bassert(newSectnum == pSprite->sectnum); + + int const doZUpdate = A_CheckNeedZUpdate(spriteNum, change->z, &newZ); + + // Update sprite's z positions and (for TROR) maybe the sector number. + if (doZUpdate) + { + pSprite->z = newZ; +#ifdef YAX_ENABLE + if (doZUpdate < 0) + { + // If we passed a TROR no-SE7 water boundary, signal to the outside + // that the ceiling/floor was not hit. However, this is not enough: + // later, code checks for (retval&49152)!=49152 + // [i.e. not "was ceiling or floor hit", but "was no sprite hit"] + // and calls G_WeaponHitCeilingOrFloor() then, so we need to set + // actor[].flags |= SFLAG_DIDNOSE7WATER in A_CheckNeedZUpdate() + // previously. + // XXX: Why is this contrived data flow necessary? (If at all.) + changespritesect(spriteNum, -doZUpdate-1); + return 0; + } + + if (yax_getbunch(newSectnum, (change->z>0))>=0 + && (SECTORFLD(newSectnum,stat, (change->z>0))&yax_waltosecmask(clipType))==0) + { + setspritez(spriteNum, (vec3_t *)pSprite); + } +#endif + } + else if (returnValue == 0) + returnValue = 16384+newSectnum; + + return returnValue; +} + +int32_t block_deletesprite = 0; + +#ifdef POLYMER +static void A_DeleteLight(int32_t s) +{ + if (actor[s].lightId >= 0) + polymer_deletelight(actor[s].lightId); + actor[s].lightId = -1; + actor[s].lightptr = NULL; +} + +void G_Polymer_UnInit(void) +{ + int32_t i; + + for (i=0; i= 0) + sprite[SpriteDeletionQueue[g_spriteDeleteQueuePos]].xrepeat = 0; + SpriteDeletionQueue[g_spriteDeleteQueuePos] = spriteNum; + g_spriteDeleteQueuePos = (g_spriteDeleteQueuePos+1)%g_deleteQueueSize; +} + +void A_SpawnMultiple(int spriteNum, int tileNum, int spawnCnt) +{ + spritetype *pSprite = &sprite[spriteNum]; + + for (; spawnCnt>0; spawnCnt--) + { + int32_t const r1 = krand2(), r2 = krand2(); + int const j = A_InsertSprite(pSprite->sectnum, pSprite->x, pSprite->y, pSprite->z - (r2 % (47 << 8)), tileNum, -32, 8, + 8, r1 & 2047, 0, 0, spriteNum, 5); + //A_Spawn(-1, j); + sprite[j].cstat = krand2()&12; + } +} + +void A_DoGuts(int spriteNum, int tileNum, int spawnCnt) +{ + uspritetype const *const pSprite = (uspritetype *)&sprite[spriteNum]; + vec2_t repeat = { 32, 32 }; + + if (A_CheckEnemySprite(pSprite) && pSprite->xrepeat < 16) + repeat.x = repeat.y = 8; + + int gutZ = pSprite->z - ZOFFSET3; + int floorz = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y); + + if (gutZ > (floorz-ZOFFSET3)) + gutZ = floorz-ZOFFSET3; + + if (!RR && pSprite->picnum == COMMANDER) + gutZ -= (24<<8); + + uint8_t pal = 0; + + if (A_CheckEnemySprite(pSprite) && pSprite->pal == 6) + pal = 6; + else if (RRRA && pSprite->picnum == MINION && (pSprite->pal == 8 || pSprite->pal == 19)) + pal = pSprite->pal; + + if (RR) repeat.x >>= 1, repeat.y >>= 1; + + for (bssize_t j=spawnCnt; j>0; j--) + { + int32_t const ang = krand2() & 2047; + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(), r4 = krand2(), r5 = krand2(); + int const i = A_InsertSprite(pSprite->sectnum, pSprite->x + (r5 & 255) - 128, + pSprite->y + (r4 & 255) - 128, gutZ - (r3 & 8191), tileNum, -32, repeat.x, + repeat.y, ang, 48 + (r2 & 31), -512 - (r1 & 2047), spriteNum, 5); + + if (!RR && PN(i) == JIBS2) + { + sprite[i].xrepeat >>= 2; + sprite[i].yrepeat >>= 2; + } + + sprite[i].pal = pal; + } +} + +void A_DoGutsDir(int spriteNum, int tileNum, int spawnCnt) +{ + uspritetype const * const s = (uspritetype *)&sprite[spriteNum]; + vec2_t repeat = { 32, 32 }; + + if (A_CheckEnemySprite(s) && s->xrepeat < 16) + repeat.x = repeat.y = 8; + + int gutZ = s->z-ZOFFSET3; + int floorZ = getflorzofslope(s->sectnum,s->x,s->y); + + if (gutZ > (floorZ-ZOFFSET3)) + gutZ = floorZ-ZOFFSET3; + + if (!RR && s->picnum == COMMANDER) + gutZ -= (24<<8); + + for (bssize_t j=spawnCnt; j>0; j--) + { + int32_t const ang = krand2() & 2047; + int32_t const r1 = krand2(), r2 = krand2(); + A_InsertSprite(s->sectnum, s->x, s->y, gutZ, tileNum, -32, repeat.x, repeat.y, ang, + 256 + (r2 & 127), -512 - (r1 & 2047), spriteNum, 5); + } +} + +static int32_t G_ToggleWallInterpolation(int32_t wallNum, int32_t setInterpolation) +{ + if (setInterpolation) + { + return G_SetInterpolation(&wall[wallNum].x) || G_SetInterpolation(&wall[wallNum].y); + } + else + { + G_StopInterpolation(&wall[wallNum].x); + G_StopInterpolation(&wall[wallNum].y); + return 0; + } +} + +void Sect_ToggleInterpolation(int sectNum, int setInterpolation) +{ + for (bssize_t j = sector[sectNum].wallptr, endwall = sector[sectNum].wallptr + sector[sectNum].wallnum; j < endwall; j++) + { + G_ToggleWallInterpolation(j, setInterpolation); + + int const nextWall = wall[j].nextwall; + + if (nextWall >= 0) + { + G_ToggleWallInterpolation(nextWall, setInterpolation); + G_ToggleWallInterpolation(wall[nextWall].point2, setInterpolation); + } + } +} + +void A_MoveSector(int spriteNum) +{ + // T1,T2 and T3 are used for all the sector moving stuff!!! + + spritetype *const pSprite = &sprite[spriteNum]; + int const rotateAngle = T3(spriteNum); + int originIdx = T2(spriteNum); + + pSprite->x += (pSprite->xvel * (sintable[(pSprite->ang + 512) & 2047])) >> 14; + pSprite->y += (pSprite->xvel * (sintable[pSprite->ang & 2047])) >> 14; + + int const endWall = sector[pSprite->sectnum].wallptr + sector[pSprite->sectnum].wallnum; + + for (bssize_t wallNum = sector[pSprite->sectnum].wallptr; wallNum < endWall; wallNum++) + { + vec2_t const origin = g_origins[originIdx]; + vec2_t result; + rotatepoint(zerovec, origin, rotateAngle & 2047, &result); + dragpoint(wallNum, pSprite->x + result.x, pSprite->y + result.y, 0); + + originIdx++; + } +} + +// NOTE: T5 is AC_ACTION_ID +# define LIGHTRAD_PICOFS(i) (T5(i) ? *(apScript + T5(i)) + (*(apScript + T5(i) + 2)) * AC_CURFRAME(actor[i].t_data) : 0) + +// this is the same crap as in game.c's tspr manipulation. puke. +// XXX: may access tilesizy out-of-bounds by bad user code. +#define LIGHTRAD(spriteNum, s) (s->yrepeat * tilesiz[s->picnum + LIGHTRAD_PICOFS(spriteNum)].y) +#define LIGHTRAD2(spriteNum, s) ((s->yrepeat + ((rand() % s->yrepeat)>>2)) * tilesiz[s->picnum + LIGHTRAD_PICOFS(spriteNum)].y) + +void G_AddGameLight(int lightRadius, int spriteNum, int zOffset, int lightRange, int lightColor, int lightPrio) +{ +#ifdef POLYMER + spritetype *s = &sprite[spriteNum]; + + if (videoGetRenderMode() != REND_POLYMER || pr_lighting != 1) + return; + + if (actor[spriteNum].lightptr == NULL) + { +#pragma pack(push, 1) + _prlight mylight; +#pragma pack(pop) + Bmemset(&mylight, 0, sizeof(mylight)); + + mylight.sector = s->sectnum; + mylight.x = s->x; + mylight.y = s->y; + mylight.z = s->z - zOffset; + mylight.color[0] = lightColor & 255; + mylight.color[1] = (lightColor >> 8) & 255; + mylight.color[2] = (lightColor >> 16) & 255; + mylight.radius = lightRadius; + actor[spriteNum].lightmaxrange = mylight.range = lightRange; + + mylight.priority = lightPrio; + mylight.tilenum = 0; + + mylight.publicflags.emitshadow = 1; + mylight.publicflags.negative = 0; + + actor[spriteNum].lightId = polymer_addlight(&mylight); + if (actor[spriteNum].lightId >= 0) + actor[spriteNum].lightptr = &prlights[actor[spriteNum].lightId]; + return; + } + + s->z -= zOffset; + + if (lightRange> 1) + actor[spriteNum].lightmaxrange = 0; + + if (lightRange > actor[spriteNum].lightmaxrange || lightPrio != actor[spriteNum].lightptr->priority || + Bmemcmp(&sprite[spriteNum], actor[spriteNum].lightptr, sizeof(int32_t) * 3)) + { + if (lightRange > actor[spriteNum].lightmaxrange) + actor[spriteNum].lightmaxrange = lightRange; + + Bmemcpy(actor[spriteNum].lightptr, &sprite[spriteNum], sizeof(int32_t) * 3); + actor[spriteNum].lightptr->sector = s->sectnum; + actor[spriteNum].lightptr->flags.invalidate = 1; + } + + actor[spriteNum].lightptr->priority = lightPrio; + actor[spriteNum].lightptr->range = lightRange; + actor[spriteNum].lightptr->color[0] = lightColor & 255; + actor[spriteNum].lightptr->color[1] = (lightColor >> 8) & 255; + actor[spriteNum].lightptr->color[2] = (lightColor >> 16) & 255; + + s->z += zOffset; + +#else + UNREFERENCED_PARAMETER(lightRadius); + UNREFERENCED_PARAMETER(spriteNum); + UNREFERENCED_PARAMETER(zOffset); + UNREFERENCED_PARAMETER(lightRange); + UNREFERENCED_PARAMETER(lightColor); + UNREFERENCED_PARAMETER(lightPrio); +#endif +} + +int g_canSeePlayer = 0; + +ACTOR_STATIC int G_WakeUp(spritetype *const pSprite, int const playerNum) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + if (!pPlayer->make_noise) + return 0; + int const radius = pPlayer->noise_radius; + + if (pSprite->pal == 30 || pSprite->pal == 32 || pSprite->pal == 33 || (RRRA && pSprite->pal == 8)) + return 0; + + return (pPlayer->noise_x - radius < pSprite->x && pPlayer->noise_x + radius > pSprite->x + && pPlayer->noise_y - radius < pSprite->y && pPlayer->noise_y + radius > pSprite->y); +} + +// sleeping monsters, etc +ACTOR_STATIC void G_MoveZombieActors(void) +{ + int spriteNum = headspritestat[STAT_ZOMBIEACTOR], canSeePlayer; + + if (RR) + canSeePlayer = g_canSeePlayer; + + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + int32_t playerDist; + spritetype *const pSprite = &sprite[spriteNum]; + int const playerNum = A_FindPlayer(pSprite, &playerDist); + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + if (sprite[pPlayer->i].extra > 0) + { + if (playerDist < 30000) + { + actor[spriteNum].timetosleep++; + if (actor[spriteNum].timetosleep >= (playerDist>>8)) + { + if (A_CheckEnemySprite(pSprite)) + { + vec3_t p = { pPlayer->opos.x + 64 - (krand2() & 127), + pPlayer->opos.y + 64 - (krand2() & 127), + 0 }; + + int16_t pSectnum = pPlayer->cursectnum; + + updatesector(p.x, p.y, &pSectnum); + + if (pSectnum == -1) + { + spriteNum = nextSprite; + continue; + } + + vec3_t s = { pSprite->x + 64 - (krand2() & 127), + pSprite->y + 64 - (krand2() & 127), + 0 }; + + int16_t sectNum = pSprite->sectnum; + + updatesector(s.x, s.y, §Num); + + //if (sectNum == -1) + //{ + // spriteNum = nextSprite; + // continue; + //} + canSeePlayer = 0; + if (!RR || pSprite->pal == 33 || A_CheckSpriteFlags(spriteNum, SFLAG_NOCANSEECHECK) + || (RRRA && pSprite->picnum == MINION && pSprite->pal == 8) + || (sintable[(pSprite->ang+512)&2047]*(p.x-s.x)+sintable[pSprite->ang&2047]*(p.y-s.y) >= 0)) + { + p.z = pPlayer->opos.z - (krand2() % ZOFFSET5); + s.z = pSprite->z - (krand2() % (52 << 8)); + canSeePlayer = cansee(s.x, s.y, s.z, pSprite->sectnum, p.x, p.y, p.z, pPlayer->cursectnum); + } + } + else + { + int32_t const r1 = krand2(), r2 = krand2(); + canSeePlayer = cansee(pSprite->x, pSprite->y, pSprite->z - ((r2 & 31) << 8), pSprite->sectnum, pPlayer->opos.x, + pPlayer->opos.y, pPlayer->opos.z - ((r1 & 31) << 8), pPlayer->cursectnum); + } + + if (canSeePlayer) + { + switch (DYNAMICTILEMAP(pSprite->picnum)) + { + case CANWITHSOMETHING2__STATIC: + case CANWITHSOMETHING3__STATIC: + case CANWITHSOMETHING4__STATIC: + case TRIPBOMB__STATIC: + if (RR) goto default_case; + fallthrough__; + case RUBBERCAN__STATIC: + case EXPLODINGBARREL__STATIC: + case WOODENHORSE__STATIC: + case HORSEONSIDE__STATIC: + case CANWITHSOMETHING__STATIC: + case FIREBARREL__STATIC: + case FIREVASE__STATIC: + case NUKEBARREL__STATIC: + case NUKEBARRELDENTED__STATIC: + case NUKEBARRELLEAKED__STATIC: + pSprite->shade = (sector[pSprite->sectnum].ceilingstat & 1) + ? sector[pSprite->sectnum].ceilingshade + : sector[pSprite->sectnum].floorshade; + actor[spriteNum].timetosleep = 0; + changespritestat(spriteNum, STAT_STANDABLE); + break; + + default: +default_case: + if (A_CheckSpriteFlags(spriteNum, SFLAG_USEACTIVATOR) && sector[sprite[spriteNum].sectnum].lotag & 16384) + break; + + actor[spriteNum].timetosleep = 0; + A_PlayAlertSound(spriteNum); + changespritestat(spriteNum, STAT_ACTOR); + + break; + } + } + else + actor[spriteNum].timetosleep = 0; + } + } + + if ((!RR || !canSeePlayer) && A_CheckEnemySprite(pSprite)) + { + pSprite->shade = (sector[pSprite->sectnum].ceilingstat & 1) + ? sector[pSprite->sectnum].ceilingshade + : sector[pSprite->sectnum].floorshade; + + if (RR && G_WakeUp(pSprite, playerNum)) + { + actor[spriteNum].timetosleep = 0; + A_PlayAlertSound(spriteNum); + changespritestat(spriteNum, STAT_ACTOR); + } + } + } + + spriteNum = nextSprite; + } +} + +// stupid name, but it's what the function does. +static FORCE_INLINE int G_FindExplosionInSector(int const sectNum) +{ + if (RR) + { + for (bssize_t SPRITES_OF(STAT_MISC, i)) + if (PN(i) == EXPLOSION2 || (PN(i) == EXPLOSION3 && sectNum == SECT(i))) + return i; + } + else + { + for (bssize_t SPRITES_OF(STAT_MISC, i)) + if (PN(i) == EXPLOSION2 && sectNum == SECT(i)) + return i; + } + + return -1; +} + +static FORCE_INLINE void P_Nudge(int playerNum, int spriteNum, int shiftLeft) +{ + g_player[playerNum].ps->vel.x += actor[spriteNum].extra * (sintable[(actor[spriteNum].ang + 512) & 2047]) << shiftLeft; + g_player[playerNum].ps->vel.y += actor[spriteNum].extra * (sintable[actor[spriteNum].ang & 2047]) << shiftLeft; +} + +int A_IncurDamage(int const spriteNum) +{ + spritetype *const pSprite = &sprite[spriteNum]; + actor_t *const pActor = &actor[spriteNum]; + + // dmg->picnum check: safety, since it might have been set to <0 from CON. + if (pActor->extra < 0 || pSprite->extra < 0 || pActor->picnum < 0) + { + pActor->extra = -1; + return -1; + } + + if (pSprite->picnum == APLAYER) + { + if (ud.god && (RR || pActor->picnum != SHRINKSPARK)) + return -1; + + int const playerNum = P_GetP(pSprite); + + if (pActor->owner >= 0 && (sprite[pActor->owner].picnum == APLAYER)) + { + if ( + (ud.ffire == 0) && + ((g_gametypeFlags[ud.coop] & GAMETYPE_PLAYERSFRIENDLY) || + ((g_gametypeFlags[ud.coop] & GAMETYPE_TDM) && g_player[playerNum].ps->team == g_player[P_Get(pActor->owner)].ps->team)) + ) + { + return -1; + } + } + + pSprite->extra -= pActor->extra; + + if (pActor->owner >= 0 && pSprite->extra <= 0 && pActor->picnum != FREEZEBLAST) + { + int const damageOwner = pActor->owner; + pSprite->extra = 0; + + g_player[playerNum].ps->wackedbyactor = damageOwner; + + if (sprite[damageOwner].picnum == APLAYER && playerNum != P_Get(damageOwner)) + g_player[playerNum].ps->frag_ps = P_Get(damageOwner); + + pActor->owner = g_player[playerNum].ps->i; + } + + switch (DYNAMICTILEMAP(pActor->picnum)) + { + case RPG2__STATICRR: + if (!RRRA) goto default_case; + fallthrough__; + case TRIPBOMBSPRITE__STATIC: + if (!RR) goto default_case; + fallthrough__; + case RADIUSEXPLOSION__STATIC: + case SEENINE__STATIC: + case RPG__STATIC: + case HYDRENT__STATIC: + case HEAVYHBOMB__STATIC: + case OOZFILTER__STATIC: + case EXPLODINGBARREL__STATIC: + P_Nudge(playerNum, spriteNum, 2); + break; + + default: +default_case: + P_Nudge(playerNum, spriteNum, 1); + break; + } + + pActor->extra = -1; + return pActor->picnum; + } + + if (pActor->extra == 0 && (RR || pActor->picnum == SHRINKSPARK) && pSprite->xrepeat < 24) + return -1; + + pSprite->extra -= pActor->extra; + + if (pSprite->picnum != RECON && pSprite->owner >= 0 && sprite[pSprite->owner].statnum < MAXSTATUS) + pSprite->owner = pActor->owner; + + pActor->extra = -1; + + return pActor->picnum; +} + +void A_MoveCyclers(void) +{ + for (bssize_t i=g_cyclerCnt-1; i>=0; i--) + { + int16_t *const pCycler = g_cyclers[i]; + int const sectNum = pCycler[0]; + int spriteShade = pCycler[2]; + int const floorShade = pCycler[3]; + int sectorShade = clamp(floorShade + (sintable[pCycler[1] & 2047] >> 10), spriteShade, floorShade); + + pCycler[1] += sector[sectNum].extra; + + if (pCycler[5]) // angle 1536... + { + walltype *pWall = &wall[sector[sectNum].wallptr]; + + for (bssize_t wallsLeft = sector[sectNum].wallnum; wallsLeft > 0; wallsLeft--, pWall++) + { + if (pWall->hitag != 1) + { + pWall->shade = sectorShade; + + if ((pWall->cstat&2) && pWall->nextwall >= 0) + wall[pWall->nextwall].shade = sectorShade; + } + } + + sector[sectNum].floorshade = sector[sectNum].ceilingshade = sectorShade; + } + } +} + +void A_MoveDummyPlayers(void) +{ + int spriteNum = headspritestat[STAT_DUMMYPLAYER]; + + while (spriteNum >= 0) + { + int const playerNum = P_Get(OW(spriteNum)); + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + int const nextSprite = nextspritestat[spriteNum]; + int const playerSectnum = pPlayer->cursectnum; + + if ((!RR && pPlayer->on_crane >= 0) || (playerSectnum >= 0 && sector[playerSectnum].lotag != ST_1_ABOVE_WATER) || sprite[pPlayer->i].extra <= 0) + { + pPlayer->dummyplayersprite = -1; + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else + { + if (pPlayer->on_ground && pPlayer->on_warping_sector == 1 && playerSectnum >= 0 && sector[playerSectnum].lotag == ST_1_ABOVE_WATER) + { + CS(spriteNum) = 257; + SZ(spriteNum) = sector[SECT(spriteNum)].ceilingz+(27<<8); + SA(spriteNum) = fix16_to_int(pPlayer->q16ang); + if (T1(spriteNum) == 8) + T1(spriteNum) = 0; + else T1(spriteNum)++; + } + else + { + if (sector[SECT(spriteNum)].lotag != ST_2_UNDERWATER) SZ(spriteNum) = sector[SECT(spriteNum)].floorz; + CS(spriteNum) = 32768; + } + } + + SX(spriteNum) += (pPlayer->pos.x-pPlayer->opos.x); + SY(spriteNum) += (pPlayer->pos.y-pPlayer->opos.y); + setsprite(spriteNum, (vec3_t *)&sprite[spriteNum]); + +next_sprite: + spriteNum = nextSprite; + } +} + + +static int P_Submerge(int, int, DukePlayer_t *, int, int); +static int P_Emerge(int, int, DukePlayer_t *, int, int); +static void P_FinishWaterChange(int, DukePlayer_t *, int, int, int); + +ACTOR_STATIC void G_MovePlayers(void) +{ + int spriteNum = headspritestat[STAT_PLAYER]; + + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + spritetype *const pSprite = &sprite[spriteNum]; + DukePlayer_t *const pPlayer = g_player[P_GetP(pSprite)].ps; + + if (pSprite->owner >= 0) + { + if (pPlayer->newowner >= 0) //Looking thru the camera + { + pSprite->x = pPlayer->opos.x; + pSprite->y = pPlayer->opos.y; + pSprite->z = pPlayer->opos.z + PHEIGHT; + actor[spriteNum].bpos.z = pSprite->z; + pSprite->ang = fix16_to_int(pPlayer->oq16ang); + + setsprite(spriteNum, (vec3_t *)pSprite); + } + else + { + int32_t otherPlayerDist; +#ifdef YAX_ENABLE + // TROR water submerge/emerge + int const playerSectnum = pSprite->sectnum; + int const sectorLotag = sector[playerSectnum].lotag; + int32_t otherSector; + + if (A_CheckNoSE7Water((uspritetype const *)pSprite, playerSectnum, sectorLotag, &otherSector)) + { + // NOTE: Compare with G_MoveTransports(). + pPlayer->on_warping_sector = 1; + + if ((sectorLotag == ST_1_ABOVE_WATER ? + P_Submerge(spriteNum, P_GetP(pSprite), pPlayer, playerSectnum, otherSector) : + P_Emerge(spriteNum, P_GetP(pSprite), pPlayer, playerSectnum, otherSector)) == 1) + P_FinishWaterChange(spriteNum, pPlayer, sectorLotag, -1, otherSector); + } +#endif + if (g_netServer || ud.multimode > 1) + otherp = P_FindOtherPlayer(P_GetP(pSprite), &otherPlayerDist); + else + { + otherp = P_GetP(pSprite); + otherPlayerDist = 0; + } + + if (G_HaveActor(sprite[spriteNum].picnum)) + A_Execute(spriteNum, P_GetP(pSprite), otherPlayerDist); + + pPlayer->q16angvel = G_GetQ16AngleDelta(pPlayer->oq16ang, pPlayer->q16ang); + pPlayer->oq16ang = pPlayer->q16ang; + pPlayer->oq16horiz = pPlayer->q16horiz; + pPlayer->oq16horizoff = pPlayer->q16horizoff; + + if (g_netServer || ud.multimode > 1) + { + if (sprite[g_player[otherp].ps->i].extra > 0) + { + if (pSprite->yrepeat > 32 && sprite[g_player[otherp].ps->i].yrepeat < 32) + { + if (otherPlayerDist < 1400 && pPlayer->knee_incs == 0) + { + pPlayer->knee_incs = 1; + pPlayer->weapon_pos = -1; + pPlayer->actorsqu = g_player[otherp].ps->i; + } + } + } + } + + if (ud.god) + { + pSprite->extra = pPlayer->max_player_health; + pSprite->cstat = 257; + if (!RR && !WW2GI) + pPlayer->inv_amount[GET_JETPACK] = 1599; + } + + if (pSprite->extra > 0) + { + actor[spriteNum].owner = spriteNum; + + if (ud.god == 0) + if (G_CheckForSpaceCeiling(pSprite->sectnum) || G_CheckForSpaceFloor(pSprite->sectnum)) + P_QuickKill(pPlayer); + } + else + { + pPlayer->pos.x = pSprite->x; + pPlayer->pos.y = pSprite->y; + pPlayer->pos.z = pSprite->z-(20<<8); + + pPlayer->newowner = -1; + + if (pPlayer->wackedbyactor >= 0 && sprite[pPlayer->wackedbyactor].statnum < MAXSTATUS) + { + pPlayer->q16ang += fix16_from_int(G_GetAngleDelta(fix16_to_int(pPlayer->q16ang), + getangle(sprite[pPlayer->wackedbyactor].x - pPlayer->pos.x, + sprite[pPlayer->wackedbyactor].y - pPlayer->pos.y)) + >> 1); + pPlayer->q16ang &= 0x7FFFFFF; + } + } + + pSprite->ang = fix16_to_int(pPlayer->q16ang); + } + } + else + { + if (pPlayer->holoduke_on == -1) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + Bmemcpy(&actor[spriteNum].bpos, pSprite, sizeof(vec3_t)); + pSprite->cstat = 0; + + if (pSprite->xrepeat < 42) + { + pSprite->xrepeat += 4; + pSprite->cstat |= 2; + } + else pSprite->xrepeat = 42; + + if (pSprite->yrepeat < 36) + pSprite->yrepeat += 4; + else + { + pSprite->yrepeat = 36; + if (sector[pSprite->sectnum].lotag != ST_2_UNDERWATER) + A_Fall(spriteNum); + if (pSprite->zvel == 0 && sector[pSprite->sectnum].lotag == ST_1_ABOVE_WATER) + pSprite->z += ZOFFSET5; + } + + if (pSprite->extra < 8) + { + pSprite->xvel = 128; + pSprite->ang = fix16_to_int(pPlayer->q16ang); + pSprite->extra++; + A_SetSprite(spriteNum,CLIPMASK0); + } + else + { + pSprite->ang = 2047-fix16_to_int(pPlayer->q16ang); + setsprite(spriteNum,(vec3_t *)pSprite); + } + } + + pSprite->shade = + logapproach(pSprite->shade, (sector[pSprite->sectnum].ceilingstat & 1) ? sector[pSprite->sectnum].ceilingshade + : sector[pSprite->sectnum].floorshade); + +next_sprite: + spriteNum = nextSprite; + } +} + +ACTOR_STATIC void G_MoveFX(void) +{ + int spriteNum = headspritestat[STAT_FX]; + + while (spriteNum >= 0) + { + spritetype *const pSprite = &sprite[spriteNum]; + int const nextSprite = nextspritestat[spriteNum]; + + switch (DYNAMICTILEMAP(pSprite->picnum)) + { + case RESPAWN__STATIC: + if (pSprite->extra == 66) + { + int32_t j = A_Spawn(spriteNum,SHT(spriteNum)); + if (RRRA) + { + sprite[j].pal = pSprite->pal; + if (sprite[j].picnum == MAMA) + { + switch (sprite[j].pal) + { + case 30: + sprite[j].xrepeat = sprite[j].yrepeat = 26; + sprite[j].clipdist = 75; + break; + case 31: + sprite[j].xrepeat = sprite[j].yrepeat = 36; + sprite[j].clipdist = 100; + break; + default: + sprite[j].xrepeat = sprite[j].yrepeat = 50; + sprite[j].clipdist = 100; + break; + } + } + + if (sprite[j].pal == 8) + sprite[j].cstat |= 2; + else if (sprite[j].pal == 6) + { + pSprite->extra = 66-13; + sprite[j].pal = 0; + break; + } + } + // sprite[j].pal = sprite[i].pal; + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else if (pSprite->extra > (66-13)) + sprite[spriteNum].extra++; + break; + + case MUSICANDSFX__STATIC: + { + int32_t const spriteHitag = (uint16_t)pSprite->hitag; + DukePlayer_t *const pPlayer = g_player[screenpeek].ps; + + if (T2(spriteNum) != (int)SoundEnabled()) + { + // If sound playback was toggled, restart. + T2(spriteNum) = SoundEnabled(); + T1(spriteNum) = 0; + } + + if (pSprite->lotag >= 1000 && pSprite->lotag < 2000) + { + int32_t playerDist = ldist(&sprite[pPlayer->i], pSprite); + +#ifdef SPLITSCREEN_MOD_HACKS + if (g_fakeMultiMode==2) + { + // HACK for splitscreen mod + int32_t otherdist = ldist(&sprite[g_player[1].ps->i],pSprite); + playerDist = min(playerDist, otherdist); + } +#endif + + if (playerDist < spriteHitag && T1(spriteNum) == 0) + { + FX_SetReverb(pSprite->lotag - 1000); + T1(spriteNum) = 1; + } + else if (playerDist >= spriteHitag && T1(spriteNum) == 1) + { + FX_SetReverb(0); + T1(spriteNum) = 0; + } + } + else if (pSprite->lotag < 999 && (unsigned)sector[pSprite->sectnum].lotag < 9 && // ST_9_SLIDING_ST_DOOR + snd_ambience && sector[SECT(spriteNum)].floorz != sector[SECT(spriteNum)].ceilingz) + { + auto flags = S_GetUserFlags(pSprite->lotag); + if (flags & SF_MSFX) + { + int playerDist = dist(&sprite[pPlayer->i], pSprite); + +#ifdef SPLITSCREEN_MOD_HACKS + if (g_fakeMultiMode==2) + { + // HACK for splitscreen mod + int32_t otherdist = dist(&sprite[g_player[1].ps->i],pSprite); + playerDist = min(playerDist, otherdist); + } +#endif + + if (playerDist < spriteHitag && T1(spriteNum) == 0)// && FX_VoiceAvailable(g_sounds[pSprite->lotag].pr-1)) + { + // Start playing an ambience sound. +#if 0 // let the sound system handle this internally. + if (g_numEnvSoundsPlaying == snd_numvoices) + { + int32_t j; + + for (SPRITES_OF(STAT_FX, j)) + if (j != spriteNum && S_IsAmbientSFX(j) && actor[j].t_data[0] == 1 && + dist(&sprite[j], &sprite[pPlayer->i]) > playerDist) + { + S_StopEnvSound(sprite[j].lotag,j); + break; + } + + if (j == -1) + goto next_sprite; + } +#endif + A_PlaySound(pSprite->lotag, spriteNum, CHAN_AUTO, CHANF_LOOP); + T1(spriteNum) = 1; // AMBIENT_SFX_PLAYING + } + else if (playerDist >= spriteHitag && T1(spriteNum) == 1) + { + // Stop playing ambience sound because we're out of its range. + + // T1 will be reset in sounds.c: CLEAR_SOUND_T0 + // T1 = 0; + S_StopEnvSound(pSprite->lotag,spriteNum); + } + } + + if ((flags & (SF_GLOBAL | SF_DTAG)) == SF_GLOBAL) + { + // Randomly playing global sounds (flyby of planes, screams, ...) + + if (T5(spriteNum) > 0) + T5(spriteNum)--; + else + { + for (int TRAVERSE_CONNECT(playerNum)) + if (playerNum == myconnectindex && g_player[playerNum].ps->cursectnum == pSprite->sectnum) + { + S_PlaySound(pSprite->lotag + (unsigned)g_globalRandom % (pSprite->hitag+1)); + T5(spriteNum) = GAMETICSPERSEC*40 + g_globalRandom%(GAMETICSPERSEC*40); + } + } + } + } + break; + } + } +next_sprite: + spriteNum = nextSprite; + } +} + +ACTOR_STATIC void G_MoveFallers(void) +{ + int spriteNum = headspritestat[STAT_FALLER]; + + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + spritetype *const pSprite = &sprite[spriteNum]; + int const sectNum = pSprite->sectnum; + + if (T1(spriteNum) == 0) + { + const int16_t oextra = pSprite->extra; + int j; + + pSprite->z -= ZOFFSET2; + T2(spriteNum) = pSprite->ang; + + if ((j = A_IncurDamage(spriteNum)) >= 0) + { + if ((!RR && j == FIREEXT) || j == RPG || (RRRA && j == RPG2) || j == RADIUSEXPLOSION || j == SEENINE || j == OOZFILTER) + { + if (pSprite->extra <= 0) + { + T1(spriteNum) = 1; + + for (bssize_t SPRITES_OF(STAT_FALLER, j)) + { + if (sprite[j].hitag == SHT(spriteNum)) + { + actor[j].t_data[0] = 1; + sprite[j].cstat &= (65535-64); + if (sprite[j].picnum == CEILINGSTEAM || sprite[j].picnum == STEAM) + sprite[j].cstat |= 32768; + } + } + } + } + else + { + actor[spriteNum].extra = 0; + pSprite->extra = oextra; + } + } + pSprite->ang = T2(spriteNum); + pSprite->z += ZOFFSET2; + } + else if (T1(spriteNum) == 1) + { + if ((int16_t)pSprite->lotag > 0) + { + pSprite->lotag-=3; + if (RR) + { + pSprite->xvel = (64+krand2())&127; + pSprite->zvel = -(1024+(krand2()&1023)); + } + else if ((int16_t)pSprite->lotag <= 0) + { + pSprite->xvel = (32+krand2())&63; + pSprite->zvel = -(1024+(krand2()&1023)); + } + } + else + { + int32_t spriteGravity = g_spriteGravity; + + if (pSprite->xvel > 0) + { + pSprite->xvel -= RR ? 2 : 8; + A_SetSprite(spriteNum,CLIPMASK0); + } + + if (EDUKE32_PREDICT_FALSE(G_CheckForSpaceFloor(pSprite->sectnum))) + spriteGravity = 0; + else if (EDUKE32_PREDICT_FALSE(G_CheckForSpaceCeiling(pSprite->sectnum))) + spriteGravity = g_spriteGravity / 6; + + if (pSprite->z < (sector[sectNum].floorz-ZOFFSET)) + { + pSprite->zvel += spriteGravity; + if (pSprite->zvel > 6144) + pSprite->zvel = 6144; + pSprite->z += pSprite->zvel; + } + + if ((sector[sectNum].floorz-pSprite->z) < ZOFFSET2) + { + for (size_t x = 0, x_end = 1+(krand2()&7); x < x_end; ++x) + RANDOMSCRAP(pSprite, spriteNum); + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + } + } + +next_sprite: + spriteNum = nextSprite; + } +} + +ACTOR_STATIC void G_MoveStandables(void) +{ + int spriteNum = headspritestat[STAT_STANDABLE], j, switchPic; + + while (spriteNum >= 0) + { + const int nextSprite = nextspritestat[spriteNum]; + int32_t *const pData = &actor[spriteNum].t_data[0]; + spritetype *const pSprite = &sprite[spriteNum]; + const int sectNum = pSprite->sectnum; + + if (sectNum < 0) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + Bmemcpy(&actor[spriteNum].bpos, pSprite, sizeof(vec3_t)); + + if (PN(spriteNum) >= CRANE && PN(spriteNum) <= CRANE+3) + { + int32_t nextj; + + //t[0] = state + //t[1] = checking sector number + + if (pSprite->xvel) A_GetZLimits(spriteNum); + + if (pData[0] == 0) //Waiting to check the sector + { + for (SPRITES_OF_SECT_SAFE(pData[1], j, nextj)) + { + switch (sprite[j].statnum) + { + case STAT_ACTOR: + case STAT_ZOMBIEACTOR: + case STAT_STANDABLE: + case STAT_PLAYER: + { + vec3_t vect = { g_origins[pData[4]+1].x, g_origins[pData[4]+1].y, sprite[j].z }; + + pSprite->ang = getangle(vect.x-pSprite->x, vect.y-pSprite->y); + setsprite(j, &vect); + pData[0]++; + goto next_sprite; + } + } + } + } + + else if (pData[0]==1) + { + if (pSprite->xvel < 184) + { + pSprite->picnum = CRANE+1; + pSprite->xvel += 8; + } + A_SetSprite(spriteNum,CLIPMASK0); + if (sectNum == pData[1]) + pData[0]++; + } + else if (pData[0]==2 || pData[0]==7) + { + pSprite->z += (1024+512); + + if (pData[0]==2) + { + if (sector[sectNum].floorz - pSprite->z < (64<<8)) + if (pSprite->picnum > CRANE) pSprite->picnum--; + + if (sector[sectNum].floorz - pSprite->z < 4096+1024) + pData[0]++; + } + + if (pData[0]==7) + { + if (sector[sectNum].floorz - pSprite->z < (64<<8)) + { + if (pSprite->picnum > CRANE) pSprite->picnum--; + else + { + if (pSprite->owner==-2) + { + int32_t p = A_FindPlayer(pSprite, NULL); + A_PlaySound(RR ? 390 : DUKE_GRUNT,g_player[p].ps->i); + if (g_player[p].ps->on_crane == spriteNum) + g_player[p].ps->on_crane = -1; + } + + pData[0]++; + pSprite->owner = -1; + } + } + } + } + else if (pData[0]==3) + { + pSprite->picnum++; + if (pSprite->picnum == CRANE+2) + { + int32_t p = G_CheckPlayerInSector(pData[1]); + + if (p >= 0 && g_player[p].ps->on_ground) + { + pSprite->owner = -2; + g_player[p].ps->on_crane = spriteNum; + A_PlaySound(RR ? 390 : DUKE_GRUNT,g_player[p].ps->i); + g_player[p].ps->q16ang = fix16_from_int(pSprite->ang+1024); + } + else + { + for (SPRITES_OF_SECT(pData[1], j)) + { + switch (sprite[j].statnum) + { + case STAT_ACTOR: + case STAT_STANDABLE: + pSprite->owner = j; + break; + } + } + } + + pData[0]++;//Grabbed the sprite + pData[2]=0; + goto next_sprite; + } + } + else if (pData[0]==4) //Delay before going up + { + pData[2]++; + if (pData[2] > 10) + pData[0]++; + } + else if (pData[0]==5 || pData[0] == 8) + { + if (pData[0]==8 && pSprite->picnum < (CRANE+2)) + if ((sector[sectNum].floorz-pSprite->z) > 8192) + pSprite->picnum++; + + if (pSprite->z < g_origins[pData[4]+2].x) + { + pData[0]++; + pSprite->xvel = 0; + } + else + pSprite->z -= (1024+512); + } + else if (pData[0]==6) + { + if (pSprite->xvel < 192) + pSprite->xvel += 8; + pSprite->ang = getangle(g_origins[pData[4]].x - pSprite->x, g_origins[pData[4]].y - pSprite->y); + A_SetSprite(spriteNum,CLIPMASK0); + if (((pSprite->x-g_origins[pData[4]].x)*(pSprite->x-g_origins[pData[4]].x)+(pSprite->y-g_origins[pData[4]].y)*(pSprite->y-g_origins[pData[4]].y)) < (128*128)) + pData[0]++; + } + + else if (pData[0]==9) + pData[0] = 0; + + { + vec3_t vect; + Bmemcpy(&vect,pSprite,sizeof(vec3_t)); + vect.z -= (34<<8); + setsprite(g_origins[pData[4]+2].y, &vect); + } + + + if (pSprite->owner != -1) + { + int32_t p = A_FindPlayer(pSprite, NULL); + + if (A_IncurDamage(spriteNum) >= 0) + { + if (pSprite->owner == -2) + if (g_player[p].ps->on_crane == spriteNum) + g_player[p].ps->on_crane = -1; + pSprite->owner = -1; + pSprite->picnum = CRANE; + goto next_sprite; + } + + if (pSprite->owner >= 0) + { + setsprite(pSprite->owner,(vec3_t *)pSprite); + + Bmemcpy(&actor[pSprite->owner].bpos, pSprite, sizeof(vec3_t)); + + pSprite->zvel = 0; + } + else if (pSprite->owner == -2) + { + DukePlayer_t *const ps = g_player[p].ps; + + ps->opos.x = ps->pos.x = pSprite->x-(sintable[(fix16_to_int(ps->q16ang)+512)&2047]>>6); + ps->opos.y = ps->pos.y = pSprite->y-(sintable[fix16_to_int(ps->q16ang)&2047]>>6); + ps->opos.z = ps->pos.z = pSprite->z+(2<<8); + + setsprite(ps->i, (vec3_t *)ps); + ps->cursectnum = sprite[ps->i].sectnum; + } + } + + goto next_sprite; + } + else if (PN(spriteNum) >= WATERFOUNTAIN && PN(spriteNum) <= WATERFOUNTAIN+3) + { + if (pData[0] > 0) + { + if (pData[0] < 20) + { + pData[0]++; + + pSprite->picnum++; + + if (pSprite->picnum == (WATERFOUNTAIN+3)) + pSprite->picnum = WATERFOUNTAIN+1; + } + else + { + int32_t playerDist; + + A_FindPlayer(pSprite,&playerDist); + + if (playerDist > 512) + { + pData[0] = 0; + pSprite->picnum = WATERFOUNTAIN; + } + else pData[0] = 1; + } + } + goto next_sprite; + } + else if (AFLAMABLE(pSprite->picnum)) + { + if (T1(spriteNum) == 1) + { + if ((++T2(spriteNum)&3) > 0) goto next_sprite; + + if (pSprite->picnum == TIRE && T2(spriteNum) == 32) + { + pSprite->cstat = 0; + j = A_Spawn(spriteNum,BLOODPOOL); + sprite[j].shade = 127; + } + else + { + if (pSprite->shade < 64) pSprite->shade++; + else DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + + j = pSprite->xrepeat-(krand2()&7); + if (j < 10) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + pSprite->xrepeat = j; + + j = pSprite->yrepeat-(krand2()&7); + if (j < 4) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + pSprite->yrepeat = j; + } + if (!RR && pSprite->picnum == BOX) + { + A_Fall(spriteNum); + actor[spriteNum].ceilingz = sector[pSprite->sectnum].ceilingz; + } + goto next_sprite; + } + else if (!RR && pSprite->picnum == TRIPBOMB) + { + int const tripBombMode = Gv_GetVarByLabel("TRIPBOMB_CONTROL", TRIPBOMB_TRIPWIRE, -1, -1); + if(tripBombMode & TRIPBOMB_TIMER) + { + // we're on a timer.... + if (pSprite->extra >= 0) + { + pSprite->extra--; + if (pSprite->extra == 0) + { + T3(spriteNum) = 16; + A_PlaySound(LASERTRIP_ARMING,spriteNum); + } + } + } + if (T3(spriteNum) > 0) + { + T3(spriteNum)--; + + if (T3(spriteNum) == 8) + { + for (j=0; j<5; j++) + RANDOMSCRAP(pSprite, spriteNum); + + int const dmg = pSprite->extra; + A_RadiusDamage(spriteNum, g_tripbombRadius, dmg>>2, dmg>>1, dmg-(dmg>>2), dmg); + + j = A_Spawn(spriteNum,EXPLOSION2); + A_PlaySound(LASERTRIP_EXPLODE,j); + sprite[j].ang = pSprite->ang; + sprite[j].xvel = 348; + A_SetSprite(j,CLIPMASK0); + + for (SPRITES_OF(STAT_MISC, j)) + { + if (sprite[j].picnum == LASERLINE && pSprite->hitag == sprite[j].hitag) + sprite[j].xrepeat = sprite[j].yrepeat = 0; + } + + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + goto next_sprite; + } + else + { + int const oldExtra = pSprite->extra; + int const oldAng = pSprite->ang; + + pSprite->extra = 1; + if (A_IncurDamage(spriteNum) >= 0) + { + T3(spriteNum) = 16; + } + pSprite->extra = oldExtra; + pSprite->ang = oldAng; + } + + if (T1(spriteNum) < 32) + { + int32_t playerDist; + A_FindPlayer(pSprite, &playerDist); + if (playerDist > 768 || T1(spriteNum) > 16) T1(spriteNum)++; + } + + if (T1(spriteNum) == 32) + { + int16_t hitSprite; + int const oldAng = pSprite->ang; + + pSprite->ang = T6(spriteNum); + + T4(spriteNum) = pSprite->x; + T5(spriteNum) = pSprite->y; + + pSprite->x += sintable[(T6(spriteNum)+512)&2047]>>9; + pSprite->y += sintable[(T6(spriteNum))&2047]>>9; + pSprite->z -= (3<<8); + + setsprite(spriteNum,(vec3_t *)pSprite); + + int hitDist = A_CheckHitSprite(spriteNum, &hitSprite); + + actor[spriteNum].lastv.x = hitDist; + pSprite->ang = oldAng; + + if (tripBombMode & TRIPBOMB_TRIPWIRE) + { + // we're on a trip wire + //int16_t cursectnum; + + while (hitDist > 0) + { + j = A_Spawn(spriteNum,LASERLINE); + setsprite(j,(vec3_t *)&sprite[j]); + sprite[j].hitag = pSprite->hitag; + actor[j].t_data[1] = sprite[j].z; + + pSprite->x += sintable[(T6(spriteNum)+512)&2047]>>4; + pSprite->y += sintable[(T6(spriteNum))&2047]>>4; + + if (hitDist < 1024) + { + sprite[j].xrepeat = hitDist>>5; + break; + } + hitDist -= 1024; + + //cursectnum = pSprite->sectnum; + //updatesector(pSprite->x, pSprite->y, &cursectnum); + //if (cursectnum < 0) + // break; + } + } + + T1(spriteNum)++; + + pSprite->x = T4(spriteNum); + pSprite->y = T5(spriteNum); + pSprite->z += (3<<8); + + setsprite(spriteNum,(vec3_t *)pSprite); + T4(spriteNum) = T3(spriteNum) = 0; + + if (hitSprite >= 0 && (tripBombMode & TRIPBOMB_TRIPWIRE)) + { + T3(spriteNum) = 13; + A_PlaySound(LASERTRIP_ARMING,spriteNum); + } + } + + if (T1(spriteNum) == 33) + { + T2(spriteNum)++; + + T4(spriteNum) = pSprite->x; + T5(spriteNum) = pSprite->y; + + pSprite->x += sintable[(T6(spriteNum)+512)&2047]>>9; + pSprite->y += sintable[(T6(spriteNum))&2047]>>9; + pSprite->z -= (3<<8); + + setsprite(spriteNum, (vec3_t *) pSprite); + + int hitDist = A_CheckHitSprite(spriteNum, NULL); + + pSprite->x = T4(spriteNum); + pSprite->y = T5(spriteNum); + pSprite->z += (3<<8); + setsprite(spriteNum, (vec3_t *) pSprite); + + // if( Actor[i].lastvx != x && lTripBombControl & TRIPBOMB_TRIPWIRE) + if (actor[spriteNum].lastv.x != hitDist && (tripBombMode & TRIPBOMB_TRIPWIRE)) + { + T3(spriteNum) = 13; + A_PlaySound(LASERTRIP_ARMING, spriteNum); + } + } + + goto next_sprite; + } + else if (pSprite->picnum >= CRACK1 && pSprite->picnum <= CRACK4) + { + if (pSprite->hitag) + { + pData[0] = pSprite->cstat; + pData[1] = pSprite->ang; + + int const dmgTile = A_IncurDamage(spriteNum); + + if (dmgTile < 0) + goto crack_default; + + switch (DYNAMICTILEMAP(dmgTile)) + { + case RPG2__STATICRR: + if (!RRRA) goto crack_default; + fallthrough__; + case FIREEXT__STATIC: + if (RR) goto crack_default; + fallthrough__; + case RPG__STATIC: + case RADIUSEXPLOSION__STATIC: + case SEENINE__STATIC: + case OOZFILTER__STATIC: + for (SPRITES_OF(STAT_STANDABLE, j)) + { + if (pSprite->hitag == sprite[j].hitag && + (sprite[j].picnum == OOZFILTER || sprite[j].picnum == SEENINE)) + if (sprite[j].shade != -32) + sprite[j].shade = -32; + } + + goto DETONATE; + +crack_default: + default: + pSprite->cstat = pData[0]; + pSprite->ang = pData[1]; + pSprite->extra = 0; + + goto next_sprite; + } + } + goto next_sprite; + } + else if (!RR && pSprite->picnum == FIREEXT) + { + if (A_IncurDamage(spriteNum) < 0) + goto next_sprite; + + for (bsize_t k=0; k<16; k++) + { + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(), r4 = krand2(), r5 = krand2(); + j = A_InsertSprite(SECT(spriteNum), SX(spriteNum), SY(spriteNum), SZ(spriteNum) - (r5 % (48 << 8)), + SCRAP3 + (r4 & 3), -8, 48, 48, r3 & 2047, (r2 & 63) + 64, + -(r1 & 4095) - (sprite[spriteNum].zvel >> 2), spriteNum, 5); + + sprite[j].pal = 2; + } + + j = A_Spawn(spriteNum,EXPLOSION2); + A_PlaySound(PIPEBOMB_EXPLODE,j); + A_PlaySound(GLASS_HEAVYBREAK,j); + + if ((int16_t)pSprite->hitag > 0) + { + for (SPRITES_OF(STAT_STANDABLE, j)) + { + // XXX: This block seems to be CODEDUP'd a lot of times. + if (pSprite->hitag == sprite[j].hitag && (sprite[j].picnum == OOZFILTER || sprite[j].picnum == SEENINE)) + if (sprite[j].shade != -32) + sprite[j].shade = -32; + } + + int const dmg = pSprite->extra; + A_RadiusDamage(spriteNum, g_pipebombRadius,dmg>>2, dmg-(dmg>>1),dmg-(dmg>>2), dmg); + j = A_Spawn(spriteNum,EXPLOSION2); + A_PlaySound(PIPEBOMB_EXPLODE,j); + + goto DETONATE; + } + else + { + A_RadiusDamage(spriteNum,g_seenineRadius,10,15,20,25); + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + goto next_sprite; + } + else if (pSprite->picnum == OOZFILTER || pSprite->picnum == SEENINE || pSprite->picnum == SEENINEDEAD || pSprite->picnum == SEENINEDEAD+1) + { + if (pSprite->shade != -32 && pSprite->shade != -33) + { + if (pSprite->xrepeat) + j = (A_IncurDamage(spriteNum) >= 0); + else + j = 0; + + if (j || pSprite->shade == -31) + { + if (j) pSprite->lotag = 0; + + pData[3] = 1; + + for (SPRITES_OF(STAT_STANDABLE, j)) + { + if (pSprite->hitag == sprite[j].hitag && (sprite[j].picnum == SEENINE || sprite[j].picnum == OOZFILTER)) + sprite[j].shade = -32; + } + } + } + else + { + if (pSprite->shade == -32) + { + if ((int16_t)pSprite->lotag > 0) + { + pSprite->lotag -= 3; + if ((int16_t)pSprite->lotag <= 0) + pSprite->lotag = -99; + } + else + pSprite->shade = -33; + } + else + { + if (pSprite->xrepeat > 0) + { + T3(spriteNum)++; + if (T3(spriteNum) == 3) + { + if (pSprite->picnum == OOZFILTER) + { + T3(spriteNum) = 0; + goto DETONATE; + } + + if (pSprite->picnum != (SEENINEDEAD+1)) + { + T3(spriteNum) = 0; + + if (pSprite->picnum == SEENINEDEAD) + pSprite->picnum++; + else if (pSprite->picnum == SEENINE) + pSprite->picnum = SEENINEDEAD; + } + else goto DETONATE; + } + goto next_sprite; + } + +DETONATE: + g_earthquakeTime = 16; + + for (SPRITES_OF(STAT_EFFECTOR, j)) + { + if (pSprite->hitag == sprite[j].hitag) + { + if (sprite[j].lotag == SE_13_EXPLOSIVE) + { + if (actor[j].t_data[2] == 0) + actor[j].t_data[2] = 1; + } + else if (sprite[j].lotag == SE_8_UP_OPEN_DOOR_LIGHTS) + actor[j].t_data[4] = 1; + else if (sprite[j].lotag == SE_18_INCREMENTAL_SECTOR_RISE_FALL) + { + if (actor[j].t_data[0] == 0) + actor[j].t_data[0] = 1; + } + else if (sprite[j].lotag == SE_21_DROP_FLOOR) + actor[j].t_data[0] = 1; + } + } + + pSprite->z -= ZOFFSET5; + + if ((pData[3] == 1 && pSprite->xrepeat) || (int16_t)pSprite->lotag == -99) + { + int const newSprite = A_Spawn(spriteNum,EXPLOSION2); + int const dmg = pSprite->extra; + + A_RadiusDamage(spriteNum,g_seenineRadius,dmg>>2, dmg-(dmg>>1),dmg-(dmg>>2), dmg); + A_PlaySound(PIPEBOMB_EXPLODE, newSprite); + } + + if (pSprite->xrepeat) + for (bsize_t x=0; x<8; x++) + RANDOMSCRAP(pSprite, spriteNum); + + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + } + goto next_sprite; + } + else if (pSprite->picnum == MASTERSWITCH) + { + if (pSprite->yvel == 1) + { + if ((int16_t)--pSprite->hitag <= 0) + { + G_OperateSectors(sectNum,spriteNum); + + for (SPRITES_OF_SECT(sectNum, j)) + { + if (sprite[j].statnum == STAT_EFFECTOR) + { + switch (sprite[j].lotag) + { + case SE_2_EARTHQUAKE: + case SE_21_DROP_FLOOR: + case SE_31_FLOOR_RISE_FALL: + case SE_32_CEILING_RISE_FALL: + case SE_36_PROJ_SHOOTER: + actor[j].t_data[0] = 1; + break; + case SE_3_RANDOM_LIGHTS_AFTER_SHOT_OUT: + actor[j].t_data[4] = 1; + break; + } + } + else if (sprite[j].statnum == STAT_STANDABLE) + { + switch (DYNAMICTILEMAP(sprite[j].picnum)) + { + case SEENINE__STATIC: + case OOZFILTER__STATIC: + sprite[j].shade = -31; + break; + } + } + } + + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + } + goto next_sprite; + } + else + { + switchPic = pSprite->picnum; + + if (!RR && switchPic > SIDEBOLT1 && switchPic <= SIDEBOLT1 + 3) + switchPic = SIDEBOLT1; + else if (switchPic > BOLT1 && switchPic <= BOLT1 + 3) + switchPic = BOLT1; + switch (DYNAMICTILEMAP(switchPic)) + { + case VIEWSCREEN__STATIC: + case VIEWSCREEN2__STATIC: + if (RR) goto next_sprite; + + if (pSprite->xrepeat == 0) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + { + int32_t playerDist; + int const p = A_FindPlayer(pSprite, &playerDist); + const DukePlayer_t *const ps = g_player[p].ps; + + if (dist(&sprite[ps->i], pSprite) < VIEWSCREEN_ACTIVE_DISTANCE) + { +#if 0 + if (sprite[i].yvel == 1) // VIEWSCREEN_YVEL + g_curViewscreen = i; +#endif + } + else if (g_curViewscreen == spriteNum /*&& T1 == 1*/) + { + g_curViewscreen = -1; + sprite[spriteNum].yvel = 0; // VIEWSCREEN_YVEL + T1(spriteNum) = 0; + } + } + + goto next_sprite; + case TRASH__STATIC: + + if (pSprite->xvel == 0) + pSprite->xvel = 1; + if (A_SetSprite(spriteNum, CLIPMASK0)) + { + A_Fall(spriteNum); + if (krand2() & 1) + pSprite->zvel -= 256; + if ((pSprite->xvel) < 48) + pSprite->xvel += (krand2() & 3); + } + else + DELETE_SPRITE_AND_CONTINUE(spriteNum); + break; + + case SIDEBOLT1__STATIC: + // case SIDEBOLT1+1: + // case SIDEBOLT1+2: + // case SIDEBOLT1+3: + { + if (RR) goto next_sprite; + int32_t playerDist; + A_FindPlayer(pSprite, &playerDist); + if (playerDist > 20480) + goto next_sprite; + + CLEAR_THE_BOLT2: + if (pData[2]) + { + pData[2]--; + goto next_sprite; + } + if ((pSprite->xrepeat | pSprite->yrepeat) == 0) + { + pSprite->xrepeat = pData[0]; + pSprite->yrepeat = pData[1]; + } + if ((krand2() & 8) == 0) + { + pData[0] = pSprite->xrepeat; + pData[1] = pSprite->yrepeat; + pData[2] = g_globalRandom & 4; + pSprite->xrepeat = pSprite->yrepeat = 0; + goto CLEAR_THE_BOLT2; + } + pSprite->picnum++; + +#if 0 + // NOTE: Um, this 'l' was assigned to last at the beginning of this function. + // SIDEBOLT1 never gets translucent as a consequence, unlike BOLT1. + if (randomRepeat & 1) + pSprite->cstat ^= 2; +#endif + + if ((krand2() & 1) && sector[sectNum].floorpicnum == HURTRAIL) + A_PlaySound(SHORT_CIRCUIT, spriteNum); + + if (pSprite->picnum == SIDEBOLT1 + 4) + pSprite->picnum = SIDEBOLT1; + + goto next_sprite; + } + + case BOLT1__STATIC: + // case BOLT1+1: + // case BOLT1+2: + // case BOLT1+3: + { + int32_t playerDist; + A_FindPlayer(pSprite, &playerDist); + if (playerDist > 20480) + goto next_sprite; + + if (pData[3] == 0) + pData[3] = sector[sectNum].floorshade; + + CLEAR_THE_BOLT: + if (pData[2]) + { + pData[2]--; + sector[sectNum].floorshade = 20; + sector[sectNum].ceilingshade = 20; + goto next_sprite; + } + if ((pSprite->xrepeat | pSprite->yrepeat) == 0) + { + pSprite->xrepeat = pData[0]; + pSprite->yrepeat = pData[1]; + } + else if ((krand2() & 8) == 0) + { + pData[0] = pSprite->xrepeat; + pData[1] = pSprite->yrepeat; + pData[2] = g_globalRandom & 4; + pSprite->xrepeat = pSprite->yrepeat = 0; + goto CLEAR_THE_BOLT; + } + pSprite->picnum++; + + int const randomRepeat = g_globalRandom & 7; + pSprite->xrepeat = randomRepeat + 8; + + if (randomRepeat & 1) + pSprite->cstat ^= 2; + + if (pSprite->picnum == (BOLT1 + 1) + && (RR ? (krand2() & 1) != 0 : (krand2() & 7) == 0) && sector[sectNum].floorpicnum == HURTRAIL) + A_PlaySound(SHORT_CIRCUIT, spriteNum); + + if (pSprite->picnum == BOLT1 + 4) + pSprite->picnum = BOLT1; + + if (pSprite->picnum & 1) + { + sector[sectNum].floorshade = 0; + sector[sectNum].ceilingshade = 0; + } + else + { + sector[sectNum].floorshade = 20; + sector[sectNum].ceilingshade = 20; + } + goto next_sprite; + } + + case WATERDRIP__STATIC: + + if (pData[1]) + { + if (--pData[1] == 0) + pSprite->cstat &= 32767; + } + else + { + A_Fall(spriteNum); + A_SetSprite(spriteNum, CLIPMASK0); + if (pSprite->xvel > 0) + pSprite->xvel -= 2; + + if (pSprite->zvel == 0) + { + pSprite->cstat |= 32768; + + if (pSprite->pal != 2 && (RR || pSprite->hitag == 0)) + A_PlaySound(SOMETHING_DRIPPING, spriteNum); + + if (sprite[pSprite->owner].picnum != WATERDRIP) + { + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else + { + actor[spriteNum].bpos.z = pSprite->z = pData[0]; + pData[1] = 48 + (krand2() & 31); + } + } + } + + + goto next_sprite; + + case DOORSHOCK__STATIC: + pSprite->yrepeat = (klabs(sector[sectNum].ceilingz - sector[sectNum].floorz) >> 9) + 4; + pSprite->xrepeat = 16; + pSprite->z = sector[sectNum].floorz; + goto next_sprite; + + case TOUCHPLATE__STATIC: + if (pData[1] == 1 && (int16_t)pSprite->hitag >= 0) // Move the sector floor + { + int const floorZ = sector[sectNum].floorz; + + if (pData[3] == 1) + { + if (floorZ >= pData[2]) + { + sector[sectNum].floorz = floorZ; + pData[1] = 0; + } + else + { + sector[sectNum].floorz += sector[sectNum].extra; + int const playerNum = G_CheckPlayerInSector(sectNum); + if (playerNum >= 0) + g_player[playerNum].ps->pos.z += sector[sectNum].extra; + } + } + else + { + if (floorZ <= pSprite->z) + { + sector[sectNum].floorz = pSprite->z; + pData[1] = 0; + } + else + { + int32_t p; + sector[sectNum].floorz -= sector[sectNum].extra; + p = G_CheckPlayerInSector(sectNum); + if (p >= 0) + g_player[p].ps->pos.z -= sector[sectNum].extra; + } + } + goto next_sprite; + } + + if (pData[5] == 1) + goto next_sprite; + + { + int32_t p = G_CheckPlayerInSector(sectNum); + + if (p >= 0 && (g_player[p].ps->on_ground || pSprite->ang == 512)) + { + if (pData[0] == 0 && !G_CheckActivatorMotion(pSprite->lotag)) + { + pData[0] = 1; + pData[1] = 1; + pData[3] = !pData[3]; + G_OperateMasterSwitches(pSprite->lotag); + G_OperateActivators(pSprite->lotag, p); + if ((int16_t)pSprite->hitag > 0) + { + pSprite->hitag--; + if (pSprite->hitag == 0) + pData[5] = 1; + } + } + } + else + pData[0] = 0; + } + + if (pData[1] == 1) + { + for (SPRITES_OF(STAT_STANDABLE, j)) + { + if (j != spriteNum && sprite[j].picnum == TOUCHPLATE && sprite[j].lotag == pSprite->lotag) + { + actor[j].t_data[1] = 1; + actor[j].t_data[3] = pData[3]; + } + } + } + goto next_sprite; + + case CANWITHSOMETHING2__STATIC: + case CANWITHSOMETHING3__STATIC: + case CANWITHSOMETHING4__STATIC: + if (RR) goto next_sprite; + fallthrough__; + case CANWITHSOMETHING__STATIC: + A_Fall(spriteNum); + if (A_IncurDamage(spriteNum) >= 0) + { + A_PlaySound(VENT_BUST, spriteNum); + + for (j = 9; j >= 0; j--) RANDOMSCRAP(pSprite, spriteNum); + + if (pSprite->lotag) + A_Spawn(spriteNum, pSprite->lotag); + + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + goto next_sprite; + + case FLOORFLAME__STATIC: + if (RR) goto next_sprite; + fallthrough__; + case EXPLODINGBARREL__STATIC: + case WOODENHORSE__STATIC: + case HORSEONSIDE__STATIC: + case FIREBARREL__STATIC: + case FIREVASE__STATIC: + case NUKEBARREL__STATIC: + case NUKEBARRELDENTED__STATIC: + case NUKEBARRELLEAKED__STATIC: + case TOILETWATER__STATIC: + case RUBBERCAN__STATIC: + case STEAM__STATIC: + case CEILINGSTEAM__STATIC: + case WATERBUBBLEMAKER__STATIC: + if (!G_HaveActor(sprite[spriteNum].picnum)) + goto next_sprite; + { + int32_t playerDist; + int const playerNum = A_FindPlayer(pSprite, &playerDist); + A_Execute(spriteNum, playerNum, playerDist); + } + goto next_sprite; + } + } + + next_sprite: + spriteNum = nextSprite; + } +} + +ACTOR_STATIC void A_DoProjectileBounce(int const spriteNum) +{ + spritetype * const pSprite = &sprite[spriteNum]; + int32_t const hitSectnum = pSprite->sectnum; + int const firstWall = sector[hitSectnum].wallptr; + int const secondWall = wall[firstWall].point2; + int const wallAngle = getangle(wall[secondWall].x - wall[firstWall].x, wall[secondWall].y - wall[firstWall].y); + vec3_t vect = { mulscale10(pSprite->xvel, sintable[(pSprite->ang + 512) & 2047]), + mulscale10(pSprite->xvel, sintable[pSprite->ang & 2047]), pSprite->zvel }; + + int k = (pSprite->z<(actor[spriteNum].floorz + actor[spriteNum].ceilingz)>> 1) ? sector[hitSectnum].ceilingheinum + : sector[hitSectnum].floorheinum; + + vec3_t const da = { mulscale14(k, sintable[(wallAngle)&2047]), + mulscale14(k, sintable[(wallAngle + 1536) & 2047]), 4096 }; + + k = vect.x * da.x + vect.y * da.y + vect.z * da.z; + int l = da.x * da.x + da.y * da.y + da.z * da.z; + + if ((klabs(k) >> 14) < l) + { + k = divscale17(k, l); + vect.x -= mulscale16(da.x, k); + vect.y -= mulscale16(da.y, k); + vect.z -= mulscale16(da.z, k); + } + + pSprite->zvel = vect.z; + pSprite->xvel = ksqrt(dmulscale8(vect.x, vect.x, vect.y, vect.y)); + pSprite->ang = getangle(vect.x, vect.y); +} + +ACTOR_STATIC void P_HandleBeingSpitOn(DukePlayer_t * const ps) +{ + ps->q16horiz += F16(32); + ps->return_to_center = 8; + + if (ps->loogcnt) + return; + + if (!A_CheckSoundPlaying(ps->i, DUKE_LONGTERM_PAIN)) + A_PlaySound(DUKE_LONGTERM_PAIN,ps->i); + + int j = 3+(krand2()&3); + ps->numloogs = j; + ps->loogcnt = 24*4; + for (bssize_t x=0; x < j; x++) + { + ps->loogiex[x] = krand2()%xdim; + ps->loogiey[x] = krand2()%ydim; + } +} + +static void G_WeaponHitCeilingOrFloor(int32_t i, spritetype *s, int *j) +{ + if (actor[i].flags & SFLAG_DIDNOSE7WATER) + { + actor[i].flags &= ~SFLAG_DIDNOSE7WATER; + return; + } + + if (s->z < actor[i].ceilingz) + { + *j = 16384|s->sectnum; + s->zvel = -1; + } + else if (s->z > actor[i].floorz + (RR ? 0 : (ZOFFSET2*(sector[s->sectnum].lotag == ST_1_ABOVE_WATER)))) + { + *j = 16384|s->sectnum; + + if (sector[s->sectnum].lotag != ST_1_ABOVE_WATER) + s->zvel = 1; + } +} + +static void Proj_BounceOffWall(spritetype *s, int j) +{ + int k = getangle( + wall[wall[j].point2].x-wall[j].x, + wall[wall[j].point2].y-wall[j].y); + s->ang = ((k<<1) - s->ang)&2047; +} + +#define PROJ_DECAYVELOCITY(s) s->xvel >>= 1, s->zvel >>= 1 + +// Maybe damage a ceiling or floor as the consequence of projectile impact. +// Returns 1 if sprite should be killed. +// NOTE: Compare with Proj_MaybeDamageCF2() in sector.c +static int Proj_MaybeDamageCF(int spriteNum) +{ + uspritetype const * const s = (uspritetype const *)&sprite[spriteNum]; + + if (s->zvel < 0) + { + if ((sector[s->sectnum].ceilingstat&1) && sector[s->sectnum].ceilingpal == 0) + return 1; + + Sect_DamageCeiling(s->sectnum); + } + + return 0; +} + +ACTOR_STATIC void G_MoveWeapons(void) +{ + int spriteNum = headspritestat[STAT_PROJECTILE]; + + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + spritetype *const pSprite = &sprite[spriteNum]; + + if (pSprite->sectnum < 0) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + actor[spriteNum].bpos = *(vec3_t *)pSprite; + + // hard coded projectiles + switch (DYNAMICTILEMAP(pSprite->picnum)) + { + case KNEE__STATIC: + if (RR) goto next_sprite; + fallthrough__; + case RADIUSEXPLOSION__STATIC: DELETE_SPRITE_AND_CONTINUE(spriteNum); + case TONGUE__STATIC: + T1(spriteNum) = sintable[T2(spriteNum)&2047] >> 9; + T2(spriteNum) += 32; + if (T2(spriteNum) > 2047) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + if (sprite[pSprite->owner].statnum == MAXSTATUS && !A_CheckEnemySprite(&sprite[pSprite->owner])) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + pSprite->ang = sprite[pSprite->owner].ang; + pSprite->x = sprite[pSprite->owner].x; + pSprite->y = sprite[pSprite->owner].y; + + if (sprite[pSprite->owner].picnum == APLAYER) + pSprite->z = sprite[pSprite->owner].z - (34<<8); + + for (int i = 0; i < T1(spriteNum); i++) { + int const newSprite = A_InsertSprite(pSprite->sectnum, + pSprite->x+((i*sintable[(pSprite->ang+512)&2047])>>9), + pSprite->y+((i*sintable[pSprite->ang])>>9), + pSprite->z+((i*ksgn(pSprite->zvel))*klabs(pSprite->zvel/12)), TONGUE, -40+i*2, + 8, 8, 0, 0, 0, spriteNum, STAT_MISC); + + sprite[newSprite].cstat = 48; + sprite[newSprite].pal = 8; + } + + { + int const i = max(T1(spriteNum), 0); + int const newSprite = A_InsertSprite(pSprite->sectnum, + pSprite->x+((i*sintable[(pSprite->ang+512)&2047])>>9), + pSprite->y+((i*sintable[pSprite->ang])>>9), + pSprite->z+((i*ksgn(pSprite->zvel))*klabs(pSprite->zvel/12)), INNERJAW, -40, + 32, 32, 0, 0, 0, spriteNum, STAT_MISC); + + sprite[newSprite].cstat = 128; + if (T2(spriteNum) > 512 && T2(spriteNum) < 1024) + sprite[newSprite].picnum = INNERJAW+1; + } + goto next_sprite; + + case FREEZEBLAST__STATIC: + if (pSprite->yvel < 1 || pSprite->extra < 2 || (pSprite->xvel | pSprite->zvel) == 0) + { + int const newSprite = A_Spawn(spriteNum, TRANSPORTERSTAR); + sprite[newSprite].pal = 1; + sprite[newSprite].xrepeat = 32; + sprite[newSprite].yrepeat = 32; + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + fallthrough__; + case RPG2__STATICRR: + case RRTILE1790__STATICRR: + if (!RRRA && pSprite->picnum != FREEZEBLAST) goto next_sprite; + fallthrough__; + case SHRINKSPARK__STATIC: + case RPG__STATIC: + case FIRELASER__STATIC: + case SPIT__STATIC: + case COOLEXPLOSION1__STATIC: + case OWHIP__STATICRR: + case UWHIP__STATICRR: + { + if (!RR && pSprite->picnum == COOLEXPLOSION1) + if (!S_CheckSoundPlaying(spriteNum, WIERDSHOT_FLY)) + A_PlaySound(WIERDSHOT_FLY, spriteNum); + + int spriteXvel = pSprite->xvel; + int spriteZvel = pSprite->zvel; + + if ((pSprite->picnum == RPG || (RRRA && pSprite->picnum == RPG2)) && sector[pSprite->sectnum].lotag == ST_2_UNDERWATER) + { + spriteXvel >>= 1; + spriteZvel >>= 1; + } + + vec3_t davect = *(vec3_t *) pSprite; + + A_GetZLimits(spriteNum); + + if (pSprite->picnum == RPG && actor[spriteNum].picnum != BOSS2 && pSprite->xrepeat >= 10 + && sector[pSprite->sectnum].lotag != ST_2_UNDERWATER) + { + int const newSprite = A_Spawn(spriteNum, SMALLSMOKE); + sprite[newSprite].z += (1 << 8); + } + + if (RRRA) + { + if (pSprite->picnum == RPG2) + { + pSprite->hitag++; + if (actor[spriteNum].picnum != BOSS2 && pSprite->xrepeat >= 10 + && sector[pSprite->sectnum].lotag != ST_2_UNDERWATER) + { + int const newSprite = A_Spawn(spriteNum, SMALLSMOKE); + sprite[newSprite].z += (1 << 8); + if ((krand2() & 15) == 2) + A_Spawn(spriteNum, MONEY); + } + if (sprite[pSprite->lotag].extra <= 0) + pSprite->lotag = 0; + else if (pSprite->lotag != 0 && pSprite->hitag > 5) + { + spritetype *pTarget = &sprite[pSprite->lotag]; + int const angle = getangle(pTarget->x - pSprite->x, pTarget->y - pSprite->y); + int const angleDiff = angle - pSprite->ang; + int const angleDiffAbs = klabs(angleDiff); + if (angleDiff < 100) + { + if (angleDiffAbs > 1023) + pSprite->ang += 51; + else + pSprite->ang -= 51; + } + else if (angleDiff > 100) + { + if (angleDiffAbs > 1023) + pSprite->ang -= 51; + else + pSprite->ang += 51; + } + else + pSprite->ang = angle; + + if (pSprite->hitag > 180 && pSprite->zvel <= 0) + pSprite->zvel += 200; + } + } + else if (pSprite->picnum == RRTILE1790) + { + if (pSprite->extra) + { + pSprite->zvel = -(pSprite->extra * 250); + pSprite->extra--; + } + else + A_Fall(spriteNum); + if (pSprite->xrepeat >= 10 && sector[pSprite->sectnum].lotag != ST_2_UNDERWATER) + { + int const newSprite = A_Spawn(spriteNum, SMALLSMOKE); + sprite[newSprite].z += (1 << 8); + } + } + } + + vec3_t const tmpvect = { (spriteXvel * (sintable[(pSprite->ang + 512) & 2047])) >> 14, + (spriteXvel * (sintable[pSprite->ang & 2047])) >> 14, spriteZvel }; + + int moveSprite = A_MoveSprite(spriteNum, &tmpvect, CLIPMASK1); + + if ((pSprite->picnum == RPG || (RRRA && (pSprite->picnum == RPG2 || pSprite->picnum == RRTILE1790))) + && (unsigned) pSprite->yvel < MAXSPRITES) // RPG_YVEL + if (FindDistance2D(pSprite->x - sprite[pSprite->yvel].x, pSprite->y - sprite[pSprite->yvel].y) < 256) + moveSprite = 49152 | pSprite->yvel; + + //actor[spriteNum].movflag = moveSprite; + + if (pSprite->sectnum < 0) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + //if (RR && g_sectorExtra[pSprite->sectnum] == 800) + // DELETE_SPRITE_AND_CONTINUE(spriteNum); + + if ((moveSprite & 49152) != 49152 && pSprite->picnum != FREEZEBLAST) + G_WeaponHitCeilingOrFloor(spriteNum, pSprite, &moveSprite); + + if (pSprite->picnum == FIRELASER) + { + for (bssize_t k = -3; k < 2; k++) + { + int const newSprite + = A_InsertSprite(pSprite->sectnum, pSprite->x + ((k * sintable[(pSprite->ang + 512) & 2047]) >> 9), + pSprite->y + ((k * sintable[pSprite->ang & 2047]) >> 9), + pSprite->z + ((k * ksgn(pSprite->zvel)) * klabs(pSprite->zvel / 24)), FIRELASER, -40 + (k << 2), + pSprite->xrepeat, pSprite->yrepeat, 0, 0, 0, pSprite->owner, 5); + + sprite[newSprite].cstat = 128; + sprite[newSprite].pal = pSprite->pal; + } + } + else if (pSprite->picnum == SPIT) + if (pSprite->zvel < 6144) + pSprite->zvel += g_spriteGravity - 112; + + if (moveSprite != 0) + { + if (!RR && pSprite->picnum == COOLEXPLOSION1) + { + if ((moveSprite & 49152) == 49152 && sprite[moveSprite & (MAXSPRITES - 1)].picnum != APLAYER) + goto COOLEXPLOSION; + pSprite->xvel = 0; + pSprite->zvel = 0; + } + + switch (moveSprite & 49152) + { + case 49152: + moveSprite &= (MAXSPRITES - 1); + + if (RRRA && sprite[moveSprite].picnum == MINION && (pSprite->picnum == RPG || pSprite->picnum == RPG2) + && sprite[moveSprite].pal == 19) + { + int const newSprite = A_Spawn(spriteNum, EXPLOSION2); + A_PlaySound(RPG_EXPLODE, newSprite); + sprite[newSprite].x = davect.x; + sprite[newSprite].y = davect.y; + sprite[newSprite].z = davect.z; + goto next_sprite; + } + + if (!RRRA && pSprite->picnum == FREEZEBLAST && sprite[moveSprite].pal == 1) + if (A_CheckEnemySprite(&sprite[moveSprite]) || sprite[moveSprite].picnum == APLAYER) + { + int const newSprite = A_Spawn(spriteNum, TRANSPORTERSTAR); + sprite[newSprite].pal = 1; + sprite[newSprite].xrepeat = 32; + sprite[newSprite].yrepeat = 32; + + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + + A_DamageObject(moveSprite, spriteNum); + + if (sprite[moveSprite].picnum == APLAYER) + { + int const playerNum = P_Get(moveSprite); + A_PlaySound(PISTOL_BODYHIT, moveSprite); + + if (pSprite->picnum == SPIT) + { + if (RRRA && sprite[pSprite->owner].picnum == MAMA) + { + A_DoGuts(spriteNum, RABBITJIBA, 2); + A_DoGuts(spriteNum, RABBITJIBB, 2); + A_DoGuts(spriteNum, RABBITJIBC, 2); + } + P_HandleBeingSpitOn(g_player[playerNum].ps); + } + } + break; + + case 32768: + moveSprite &= (MAXWALLS - 1); + + if (RRRA && sprite[pSprite->owner].picnum == MAMA) + { + A_DoGuts(spriteNum, RABBITJIBA, 2); + A_DoGuts(spriteNum, RABBITJIBB, 2); + A_DoGuts(spriteNum, RABBITJIBC, 2); + } + + if (pSprite->picnum != RPG && (!RRRA || pSprite->picnum != RPG2) && pSprite->picnum != FREEZEBLAST && pSprite->picnum != SPIT + && (!RR || pSprite->picnum != SHRINKSPARK) && (wall[moveSprite].overpicnum == MIRROR || wall[moveSprite].picnum == MIRROR)) + { + Proj_BounceOffWall(pSprite, moveSprite); + pSprite->owner = spriteNum; + A_Spawn(spriteNum, TRANSPORTERSTAR); + goto next_sprite; + } + else + { + setsprite(spriteNum, &davect); + A_DamageWall(spriteNum, moveSprite, (vec3_t *)pSprite, pSprite->picnum); + + if (!RRRA && pSprite->picnum == FREEZEBLAST) + { + if (wall[moveSprite].overpicnum != MIRROR && wall[moveSprite].picnum != MIRROR) + { + pSprite->extra >>= 1; + if (RR) + { + if (pSprite->xrepeat > 8) + pSprite->xrepeat--; + if (pSprite->yrepeat > 8) + pSprite->yrepeat--; + } + pSprite->yvel--; + } + + Proj_BounceOffWall(pSprite, moveSprite); + goto next_sprite; + } + + if (RR && pSprite->picnum == SHRINKSPARK) + { + if (wall[moveSprite].picnum >= RRTILE3643 && wall[moveSprite].picnum < RRTILE3643+3) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + if (pSprite->extra <= 0) + { + pSprite->x += sintable[(pSprite->ang+512)&2047]>>7; + pSprite->y += sintable[pSprite->ang&2047]>>7; + + if (!RRRA || (sprite[pSprite->owner].picnum != CHEER && sprite[pSprite->owner].picnum != CHEERSTAYPUT)) + { + int const newSprite = A_Spawn(spriteNum, CIRCLESTUCK); + sprite[newSprite].xrepeat = 8; + sprite[newSprite].yrepeat = 8; + sprite[newSprite].cstat = 16; + sprite[newSprite].ang = (sprite[newSprite].ang+512)&2047; + sprite[newSprite].clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + } + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + if (wall[moveSprite].overpicnum != MIRROR && wall[moveSprite].picnum != MIRROR) + { + pSprite->extra -= 20; + pSprite->yvel--; + } + + Proj_BounceOffWall(pSprite, moveSprite); + goto next_sprite; + } + } + break; + + case 16384: + setsprite(spriteNum, &davect); + + if (RRRA && sprite[pSprite->owner].picnum == MAMA) + { + A_DoGuts(spriteNum, RABBITJIBA, 2); + A_DoGuts(spriteNum, RABBITJIBB, 2); + A_DoGuts(spriteNum, RABBITJIBC, 2); + } + + if (Proj_MaybeDamageCF(spriteNum)) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + if (!RRRA && pSprite->picnum == FREEZEBLAST) + { + A_DoProjectileBounce(spriteNum); + A_SetSprite(spriteNum, CLIPMASK1); + + pSprite->extra >>= 1; + + if (pSprite->xrepeat > 8) + pSprite->xrepeat -= 2; + + if (pSprite->yrepeat > 8) + pSprite->yrepeat -= 2; + + pSprite->yvel--; + goto next_sprite; + } + break; + default: break; + } + + switch (DYNAMICTILEMAP(pSprite->picnum)) + { + case COOLEXPLOSION1__STATIC: + if (RR) goto default_case; + fallthrough__; + case SPIT__STATIC: + case FREEZEBLAST__STATIC: + case FIRELASER__STATIC: break; + + case RPG__STATIC: + case RPG2__STATICRR: + case RRTILE1790__STATICRR: + { + if (!RRRA && (pSprite->picnum == RPG2 || pSprite->picnum == RRTILE1790)) + break; + int const newSprite = A_Spawn(spriteNum, EXPLOSION2); + if (pSprite->picnum == RPG2) + { + pSprite->extra = 150; + A_PlaySound(247, newSprite); + } + else if (pSprite->picnum == RRTILE1790) + { + pSprite->extra = 160; + A_PlaySound(RPG_EXPLODE, newSprite); + } + else + A_PlaySound(RPG_EXPLODE, newSprite); + Bmemcpy(&sprite[newSprite], &davect, sizeof(vec3_t)); + + if (pSprite->xrepeat < 10) + { + sprite[newSprite].xrepeat = 6; + sprite[newSprite].yrepeat = 6; + } + else if ((moveSprite & 49152) == 16384) + { + if (!RR && pSprite->zvel > 0) + A_Spawn(spriteNum, EXPLOSION2BOT); + else + { + sprite[newSprite].cstat |= 8; + sprite[newSprite].z += (48 << 8); + } + } + + if (pSprite->xrepeat >= 10) + { + int const x = pSprite->extra; + A_RadiusDamage(spriteNum, g_rpgRadius, x >> 2, x >> 1, x - (x >> 2), x); + } + else + { + int const x = pSprite->extra + (g_globalRandom & 3); + A_RadiusDamage(spriteNum, (g_rpgRadius >> 1), x >> 2, x >> 1, x - (x >> 2), x); + } + break; + } + + case SHRINKSPARK__STATIC: + if (RR) + break; + A_Spawn(spriteNum, SHRINKEREXPLOSION); + A_PlaySound(SHRINKER_HIT, spriteNum); + A_RadiusDamage(spriteNum, g_shrinkerRadius, 0, 0, 0, 0); + break; + + default: +default_case: + { + int const newSprite = A_Spawn(spriteNum, EXPLOSION2); + sprite[newSprite].xrepeat = sprite[newSprite].yrepeat = pSprite->xrepeat >> 1; + if ((moveSprite & 49152) == 16384) + { + if (pSprite->zvel < 0) + { + sprite[newSprite].cstat |= 8; + sprite[newSprite].z += (72 << 8); + } + } + break; + } + } + + if (RR || pSprite->picnum != COOLEXPLOSION1) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + + if (!RR && pSprite->picnum == COOLEXPLOSION1) + { + COOLEXPLOSION: + pSprite->shade++; + if (pSprite->shade >= 40) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else if ((pSprite->picnum == RPG || (RRRA && pSprite->picnum == RPG2)) && sector[pSprite->sectnum].lotag == ST_2_UNDERWATER && pSprite->xrepeat >= 10 && rnd(140)) + A_Spawn(spriteNum, WATERBUBBLE); + + goto next_sprite; + } + + case SHOTSPARK1__STATIC: + { + if (!G_HaveActor(sprite[spriteNum].picnum)) + goto next_sprite; + int32_t playerDist; + int const playerNum = A_FindPlayer(pSprite, &playerDist); + A_Execute(spriteNum, playerNum, playerDist); + goto next_sprite; + } + } + next_sprite: + spriteNum = nextSprite; + } +} + + +static int P_Submerge(int const spriteNum, int const playerNum, DukePlayer_t * const pPlayer, int const sectNum, int const otherSect) +{ + if ((!RR && pPlayer->on_ground && pPlayer->pos.z > sector[sectNum].floorz - ZOFFSET2 + && (TEST_SYNC_KEY(g_player[playerNum].input->bits, SK_CROUCH) || pPlayer->vel.z > 2048)) + || (RR && pPlayer->pos.z > (sector[sectNum].floorz-(6<<8))) || pPlayer->on_motorcycle) + // if( onfloorz && sectlotag == 1 && ps->pos.z > (sector[sect].floorz-(6<<8)) ) + { + if (pPlayer->on_boat) return 0; + + if (screenpeek == playerNum) + { + FX_StopAllSounds(); + S_ClearSoundLocks(); + } + + if (RR || sprite[pPlayer->i].extra > 0) + A_PlaySound(DUKE_UNDERWATER, spriteNum); + + pPlayer->opos.z = pPlayer->pos.z = sector[otherSect].ceilingz + (7<<8); + + if (!RR) + { + pPlayer->vel.x = 4096-(krand2()&8192); + pPlayer->vel.y = 4096-(krand2()&8192); + } + + if (pPlayer->on_motorcycle) + pPlayer->moto_underwater = 1; + + return 1; + } + + return 0; +} + +static int P_Emerge(int const spriteNum, int const playerNum, DukePlayer_t * const pPlayer, int const sectNum, int const otherSect) +{ + // r1449-: + if (pPlayer->pos.z < (sector[sectNum].ceilingz+(6<<8))) + // r1450+, breaks submergible slime in bobsp2: +// if (onfloorz && sectlotag == 2 && ps->pos.z <= sector[sect].ceilingz /*&& ps->vel.z == 0*/) + { + if (RR && sprite[pPlayer->i].extra <= 0) return 1; + if (screenpeek == playerNum) + { + FX_StopAllSounds(); + S_ClearSoundLocks(); + } + + A_PlaySound(DUKE_GASP, spriteNum); + + pPlayer->opos.z = pPlayer->pos.z = sector[otherSect].floorz - (7<<8); + //pPlayer->vel.z = 0; +// ps->vel.z += 1024; + + if (!RR) + { + pPlayer->jumping_toggle = 1; + pPlayer->jumping_counter = 0; + } + + return 1; + } + + return 0; +} + +static void P_FinishWaterChange(int const playerNum, DukePlayer_t * const pPlayer, int const sectLotag, int const spriteOwner, int const newSector) +{ + /*pPlayer->bobpos.x = */pPlayer->opos.x = pPlayer->pos.x; + /*pPlayer->bobpos.y = */pPlayer->opos.y = pPlayer->pos.y; + + if (spriteOwner < 0 || sprite[spriteOwner].owner != spriteOwner) + pPlayer->transporter_hold = -2; + + pPlayer->cursectnum = newSector; + changespritesect(playerNum, newSector); + + if (!RR) + { + vec3_t vect = pPlayer->pos; + vect.z += PHEIGHT; + setsprite(pPlayer->i, &vect); + } + + P_UpdateScreenPal(pPlayer); + + if ((krand2()&255) < 32) + A_Spawn(RR ? pPlayer->i : playerNum, WATERSPLASH2); + + if (!RR && sectLotag == ST_1_ABOVE_WATER) + { + for (bssize_t l = 0; l < 9; l++) + sprite[A_Spawn(pPlayer->i, WATERBUBBLE)].z += krand2() & 16383; + } +} + +// Check prevention of teleportation *when alive*. For example, commanders and +// octabrains would be transported by SE7 (both water and normal) only if dead. +static int A_CheckNonTeleporting(int const spriteNum) +{ + int const tileNum = sprite[spriteNum].picnum; + if (RRRA) + { + return !!(tileNum == SHARK || tileNum == CHEERBOAT || tileNum == HULKBOAT + || tileNum == MINIONBOAT || tileNum == UFO1); + } + else if (RR) + { + return !!(tileNum == SHARK || tileNum == UFO1 || tileNum == UFO2 + || tileNum == UFO3 || tileNum == UFO4 || tileNum == UFO5); + } + return !!(tileNum == SHARK || tileNum == COMMANDER || tileNum == OCTABRAIN + || (tileNum >= GREENSLIME && tileNum <= GREENSLIME + 7)); +} + +ACTOR_STATIC void G_MoveTransports(void) +{ + int spriteNum = headspritestat[STAT_TRANSPORT]; + + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + + if (OW(spriteNum) == spriteNum) + { + spriteNum = nextSprite; + continue; + } + + int const sectNum = SECT(spriteNum); + int const sectLotag = sector[sectNum].lotag; + int const onFloor = T5(spriteNum); // ONFLOORZ + + if (T1(spriteNum) > 0) + T1(spriteNum)--; + + int sectSprite = headspritesect[sectNum]; + while (sectSprite >= 0) + { + int const nextSectSprite = nextspritesect[sectSprite]; + + switch (sprite[sectSprite].statnum) + { + case STAT_PLAYER: + if (sprite[sectSprite].owner != -1) + { + int const playerNum = P_Get(sectSprite); + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + pPlayer->on_warping_sector = 1; + + if (pPlayer->transporter_hold == 0 && pPlayer->jumping_counter == 0) + { + if (pPlayer->on_ground && sectLotag == 0 && onFloor && pPlayer->jetpack_on == 0) + { + if (RR || sprite[spriteNum].pal == 0) + { + A_Spawn(spriteNum, TRANSPORTERBEAM); + A_PlaySound(TELEPORTER, spriteNum); + } + for (int TRAVERSE_CONNECT(otherPlayer)) + { + if (g_player[otherPlayer].ps->cursectnum == sprite[OW(spriteNum)].sectnum) + { + g_player[otherPlayer].ps->frag_ps = playerNum; + sprite[g_player[otherPlayer].ps->i].extra = 0; + } + } + + pPlayer->q16ang = fix16_from_int(sprite[OW(spriteNum)].ang); + + if (sprite[OW(spriteNum)].owner != OW(spriteNum)) + { + T1(spriteNum) = 13; + actor[OW(spriteNum)].t_data[0] = 13; + pPlayer->transporter_hold = 13; + } + + pPlayer->pos = *(vec3_t *)&sprite[OW(spriteNum)]; + pPlayer->pos.z -= PHEIGHT-(RR ? (4<<8) : 0); + pPlayer->opos = pPlayer->pos; + pPlayer->bobpos = *(vec2_t *)&pPlayer->pos; + + changespritesect(sectSprite, sprite[OW(spriteNum)].sectnum); + pPlayer->cursectnum = sprite[sectSprite].sectnum; + + if (RR || sprite[spriteNum].pal == 0) + { + int const newSprite = A_Spawn(OW(spriteNum), TRANSPORTERBEAM); + A_PlaySound(TELEPORTER, newSprite); + } + break; + } + } + else if (RR || !(sectLotag == ST_1_ABOVE_WATER && pPlayer->on_ground == 1)) + break; + + if (onFloor == 0 && klabs(SZ(spriteNum) - pPlayer->pos.z) < 6144) + if (!pPlayer->jetpack_on || TEST_SYNC_KEY(g_player[playerNum].input->bits, SK_JUMP) + || (TEST_SYNC_KEY(g_player[playerNum].input->bits, SK_CROUCH) ^ pPlayer->crouch_toggle)) + { + pPlayer->pos.x += sprite[OW(spriteNum)].x - SX(spriteNum); + pPlayer->pos.y += sprite[OW(spriteNum)].y - SY(spriteNum); + pPlayer->pos.z = (pPlayer->jetpack_on && (TEST_SYNC_KEY(g_player[playerNum].input->bits, SK_JUMP) + || pPlayer->jetpack_on < 11)) + ? sprite[OW(spriteNum)].z - 6144 + : sprite[OW(spriteNum)].z + 6144; + + if (!RR) + actor[pPlayer->i].bpos = pPlayer->pos; + pPlayer->opos = pPlayer->pos; + //pPlayer->bobpos = *(vec2_t *)&pPlayer->pos; + + changespritesect(sectSprite, sprite[OW(spriteNum)].sectnum); + pPlayer->cursectnum = sprite[OW(spriteNum)].sectnum; + + break; + } + + int doWater = 0; + + if (RRRA) + { + if (onFloor) + { + if (sectLotag == 160 && pPlayer->pos.z > (sector[sectNum].floorz-(48<<8))) + { + doWater = 2; + pPlayer->opos.z = pPlayer->pos.z = sector[sprite[OW(spriteNum)].sectnum].ceilingz+(7<<8); + } + else if (sectLotag == 161 && pPlayer->pos.z < (sector[sectNum].ceilingz+(6<<8)) && sprite[pPlayer->i].extra > 0) + { + doWater = 2; + pPlayer->opos.z = pPlayer->pos.z = sector[sprite[OW(spriteNum)].sectnum].floorz-(49<<8); + } + } + } + + if (onFloor) + { + if (sectLotag == ST_1_ABOVE_WATER) + doWater = P_Submerge(sectSprite, playerNum, pPlayer, sectNum, sprite[OW(spriteNum)].sectnum); + else if (sectLotag == ST_2_UNDERWATER) + doWater = P_Emerge(sectSprite, playerNum, pPlayer, sectNum, sprite[OW(spriteNum)].sectnum); + } + + if (doWater == 1) + { + pPlayer->pos.x += sprite[OW(spriteNum)].x - SX(spriteNum); + pPlayer->pos.y += sprite[OW(spriteNum)].y - SY(spriteNum); + + P_FinishWaterChange(sectSprite, pPlayer, sectLotag, OW(spriteNum), sprite[OW(spriteNum)].sectnum); + } + else if (doWater == 2) + { + pPlayer->pos.x += sprite[OW(spriteNum)].x - SX(spriteNum); + pPlayer->pos.y += sprite[OW(spriteNum)].y - SY(spriteNum); + pPlayer->opos.x = pPlayer->pos.x; + pPlayer->opos.y = pPlayer->pos.y; + + if (sprite[OW(spriteNum)].owner != OW(spriteNum)) + pPlayer->transporter_hold = -2; + + pPlayer->cursectnum = sprite[OW(spriteNum)].sectnum; + changespritesect(sectSprite, sprite[OW(spriteNum)].sectnum); + } + } + break; + + + ////////// Non-player teleportation ////////// + + case STAT_ACTOR: + if ((RR || sprite[sectSprite].extra > 0) && A_CheckNonTeleporting(sectSprite)) + goto JBOLT; + fallthrough__; + case STAT_PROJECTILE: + case STAT_MISC: + case STAT_FALLER: + case STAT_DUMMYPLAYER: + { + if (RR && sprite[sectSprite].statnum == STAT_FALLER) break; + //if ((totalclock & UINT8_MAX) != actor[sectSprite].lasttransport) + { + int const zvel = sprite[sectSprite].zvel; + int const absZvel = klabs(zvel); + int doWarp = 0; + int warpDir; + int absZdiff; + + if (zvel >= 0) + warpDir = 2; + else + warpDir = 1; + + if (absZvel != 0) + { + if (sectLotag == ST_2_UNDERWATER && sprite[sectSprite].z < (sector[sectNum].ceilingz + absZvel)) + doWarp = 1; + if (sectLotag == ST_1_ABOVE_WATER && sprite[sectSprite].z > (sector[sectNum].floorz - absZvel)) + if (!RRRA || (sprite[sectSprite].picnum != CHEERBOAT && sprite[sectSprite].picnum != HULKBOAT && sprite[sectSprite].picnum != MINIONBOAT)) + doWarp = 1; + } + + if (RRRA) + { + if (absZvel != 0 && sectLotag == 161 && sprite[sectSprite].z < (sector[sectNum].ceilingz + absZvel) && warpDir == 1) + { + doWarp = 1; + absZdiff = absZvel - klabs(sprite[sectSprite].z-sector[sectNum].ceilingz); + } + else if (sectLotag == 161 && sprite[sectSprite].z < (sector[sectNum].ceilingz + 1000) && warpDir == 1) + { + doWarp = 1; + absZdiff = 1; + } + if (absZvel != 0 && sectLotag == 160 && sprite[sectSprite].z > (sector[sectNum].floorz - absZvel) && warpDir == 2) + { + doWarp = 1; + absZdiff = absZvel - klabs(sector[sectNum].floorz-sprite[sectSprite].z); + } + else if (sectLotag == 160 && sprite[sectSprite].z > (sector[sectNum].floorz - 1000) && warpDir == 2) + { + doWarp = 1; + absZdiff = 1; + } + } + + if (sectLotag == 0 && (onFloor || klabs(sprite[sectSprite].z - SZ(spriteNum)) < 4096)) + { + if (sprite[OW(spriteNum)].owner != OW(spriteNum) && onFloor && T1(spriteNum) > 0 + && sprite[sectSprite].statnum != STAT_MISC) + { + T1(spriteNum)++; + goto next_sprite; + } + doWarp = 1; + } + + if (doWarp) + { + switch (DYNAMICTILEMAP(sprite[sectSprite].picnum)) + { + case TRIPBOMB__STATIC: + case BURNING2__STATIC: + case FIRE2__STATIC: + case TOILETWATER__STATIC: + case LASERLINE__STATIC: + if (RR) goto default_case; + fallthrough__; + case TRIPBOMBSPRITE__STATIC: + if (!RR && sprite[sectSprite].picnum == TRIPBOMBSPRITE) + goto default_case; + fallthrough__; + case TRANSPORTERSTAR__STATIC: + case TRANSPORTERBEAM__STATIC: + case BULLETHOLE__STATIC: + case WATERSPLASH2__STATIC: + case BURNING__STATIC: + case FIRE__STATIC: + case MUD__STATICRR: goto JBOLT; + case PLAYERONWATER__STATIC: + if (sectLotag == ST_2_UNDERWATER) + { + sprite[sectSprite].cstat &= 32767; + break; + } + fallthrough__; + default: +default_case: + if (sprite[sectSprite].statnum == STAT_MISC && !(sectLotag == ST_1_ABOVE_WATER || sectLotag == ST_2_UNDERWATER || (RRRA && (sectLotag == 160 || sectLotag == 161)))) + break; + fallthrough__; + case WATERBUBBLE__STATIC: + if (RR) + if( rnd(192) && sprite[sectSprite].picnum == WATERBUBBLE) + break; + + if (sectLotag > 0) + { + // Water SE7 teleportation. + int const osect = sprite[OW(spriteNum)].sectnum; + + Bassert(sectLotag == ST_1_ABOVE_WATER || sectLotag == ST_2_UNDERWATER || (RRRA && (sectLotag == 160 || sectLotag == 161))); + + int const newSprite = A_Spawn(sectSprite, WATERSPLASH2); + + if (sectLotag == ST_1_ABOVE_WATER && sprite[sectSprite].statnum == STAT_PROJECTILE) + { + sprite[newSprite].xvel = sprite[sectSprite].xvel >> 1; + sprite[newSprite].ang = sprite[sectSprite].ang; + A_SetSprite(newSprite, CLIPMASK0); + } + + actor[sectSprite].lasttransport = ((int32_t) totalclock & UINT8_MAX); + + if (sectLotag == ST_1_ABOVE_WATER || sectLotag == ST_2_UNDERWATER) + { + sprite[sectSprite].x += sprite[OW(spriteNum)].x - SX(spriteNum); + sprite[sectSprite].y += sprite[OW(spriteNum)].y - SY(spriteNum); + sprite[sectSprite].z = (sectLotag == ST_1_ABOVE_WATER) ? sector[osect].ceilingz+absZvel : sector[osect].floorz-absZvel; + + actor[sectSprite].bpos = *(vec3_t *)&sprite[sectSprite]; + + changespritesect(sectSprite, sprite[OW(spriteNum)].sectnum); + } + else + { + sprite[sectSprite].x += sprite[OW(spriteNum)].x - SX(spriteNum); + sprite[sectSprite].y += sprite[OW(spriteNum)].y - SY(spriteNum); + sprite[sectSprite].z = (sectLotag == 160) ? sector[osect].ceilingz+absZdiff : sector[osect].floorz-absZdiff; + + actor[sectSprite].bpos = *(vec3_t *)&sprite[sectSprite]; + + changespritesect(sectSprite, sprite[OW(spriteNum)].sectnum); + + vec3_t const vect = { + (sprite[sectSprite].xvel*sintable[(sprite[sectSprite].ang+512)&2047])>>14, + (sprite[sectSprite].xvel*sintable[sprite[sectSprite].ang])>>14, + 0 + }; + + A_MoveSprite(sectSprite, &vect, CLIPMASK1); + } + } + else if (Bassert(sectLotag == 0), 1) + { + // Non-water SE7 teleportation. + + if (onFloor) + { + if ((!RR && sprite[sectSprite].statnum == STAT_PROJECTILE) + || (G_CheckPlayerInSector(sectNum) == -1 + && G_CheckPlayerInSector(sprite[OW(spriteNum)].sectnum) == -1)) + { + sprite[sectSprite].x += (sprite[OW(spriteNum)].x - SX(spriteNum)); + sprite[sectSprite].y += (sprite[OW(spriteNum)].y - SY(spriteNum)); + sprite[sectSprite].z -= SZ(spriteNum) - sector[sprite[OW(spriteNum)].sectnum].floorz; + + sprite[sectSprite].ang = sprite[OW(spriteNum)].ang; + actor[sectSprite].bpos = *(vec3_t *)&sprite[sectSprite]; + + if (RR || sprite[spriteNum].pal == 0) + { + int newSprite = A_Spawn(spriteNum, TRANSPORTERBEAM); + A_PlaySound(TELEPORTER, newSprite); + + newSprite = A_Spawn(OW(spriteNum), TRANSPORTERBEAM); + A_PlaySound(TELEPORTER, newSprite); + } + + if (sprite[OW(spriteNum)].owner != OW(spriteNum)) + { + T1(spriteNum) = 13; + actor[OW(spriteNum)].t_data[0] = 13; + } + + changespritesect(sectSprite, sprite[OW(spriteNum)].sectnum); + } + } + else + { + sprite[sectSprite].x += (sprite[OW(spriteNum)].x - SX(spriteNum)); + sprite[sectSprite].y += (sprite[OW(spriteNum)].y - SY(spriteNum)); + sprite[sectSprite].z = sprite[OW(spriteNum)].z + 4096; + + actor[sectSprite].bpos = *(vec3_t *)&sprite[sectSprite]; + + changespritesect(sectSprite, sprite[OW(spriteNum)].sectnum); + } + } + + break; + } // switch (DYNAMICTILEMAP(sprite[j].picnum)) + } // if (doWarp) + } // if (totalclock > actor[j].lasttransport) + + break; + } // five cases + + } // switch (sprite[j].statnum) + JBOLT: + sectSprite = nextSectSprite; + } + next_sprite: + spriteNum = nextSprite; + } +} + +static int A_FindLocator(int const tag, int const sectNum) +{ + for (bssize_t SPRITES_OF(STAT_LOCATOR, spriteNum)) + { + if ((sectNum == -1 || sectNum == SECT(spriteNum)) && tag == SLT(spriteNum)) + return spriteNum; + } + + return -1; +} + +ACTOR_STATIC int A_PinSectorResetDown(int16_t const sectNum) +{ + if (GetAnimationGoal(§or[sectNum].ceilingz) == -1) + { + int const newZ = sector[sectNum].floorz; + SetAnimation(sectNum,§or[sectNum].ceilingz,newZ,64); + return 1; + } + return 0; +} + +ACTOR_STATIC int A_PinSectorResetUp(int16_t const sectNum) +{ + if (GetAnimationGoal(§or[sectNum].ceilingz) == -1) + { + int const newZ = sector[nextsectorneighborz(sectNum, sector[sectNum].ceilingz,-1,-1)].ceilingz; + SetAnimation(sectNum,§or[sectNum].ceilingz,newZ,64); + return 1; + } + return 0; +} + +ACTOR_STATIC void A_BallReturn(int16_t const pinSprite) +{ + int spriteNum = headspritestat[105]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + if (sprite[spriteNum].picnum == RRTILE281) + if (sprite[pinSprite].sectnum == sprite[spriteNum].sectnum) + { + int otherSprite = headspritestat[105]; + while (otherSprite >= 0) + { + int const otherSpriteNext = nextspritestat[otherSprite]; + if (sprite[otherSprite].picnum == RRTILE282) + if (sprite[spriteNum].hitag == sprite[otherSprite].hitag) + A_Spawn(otherSprite, BOWLINGBALLSPRITE); + if (sprite[otherSprite].picnum == RRTILE280) + if (sprite[spriteNum].hitag == sprite[otherSprite].hitag) + if (sprite[otherSprite].lotag == 0) + { + sprite[otherSprite].lotag = 100; + sprite[otherSprite].extra++; + A_PinSectorResetDown(sprite[otherSprite].sectnum); + } + otherSprite = otherSpriteNext; + } + } + + spriteNum = nextSprite; + } +} + +ACTOR_STATIC int A_CheckPins(int16_t const sectNum) +{ + uint8_t pins[10]; + int pinCount = 0; + int tag; + + Bmemset(pins, 0, sizeof(pins)); + + int spriteNum = headspritesect[sectNum]; + + while (spriteNum >= 0) + { + if (sprite[spriteNum].picnum == RRTILE3440) + { + pinCount++; + pins[sprite[spriteNum].lotag] = 1; + } + if (sprite[spriteNum].picnum == RRTILE280) + { + tag = sprite[spriteNum].hitag; + } + spriteNum = nextspritesect[spriteNum]; + } + + if (tag != 0) + { + int const tileNumber = LANEPICS + tag + 1; + TileFiles.tileMakeWritable(tileNumber); + tileCopySection(LANEPICS+1, 0, 0, 128, 64, tileNumber, 0, 0); + + for (int pin = 0; pin < 10; pin++) + { + if (pins[pin] == 1) + { + int x, y; + switch (pin) + { + case 0: + x = 64; + y = 48; + break; + case 1: + x = 56; + y = 40; + break; + case 2: + x = 72; + y = 40; + break; + case 3: + x = 48; + y = 32; + break; + case 4: + x = 64; + y = 32; + break; + case 5: + x = 80; + y = 32; + break; + case 6: + x = 40; + y = 24; + break; + case 7: + x = 56; + y = 24; + break; + case 8: + x = 72; + y = 24; + break; + case 9: + x = 88; + y = 24; + break; + } + tileCopySection(LANEPICS, 0, 0, 8, 8, tileNumber, x - 4, y - 10); + } + } + } + + return pinCount; +} + +ACTOR_STATIC void A_ResetPins(int16_t sect) +{ + int step = 0; + int tag = 0; + int spriteNum = headspritesect[sect]; + while (spriteNum >= 0) + { + if (spriteNum > MAXSECTORSV7 || step > 1000) + break; + int const nextSprite = headspritesect[spriteNum]; + if (sprite[spriteNum].picnum == RRTILE3440) + deletesprite(spriteNum); + spriteNum = nextSprite; + step++; + } + spriteNum = headspritesect[sect]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritesect[spriteNum]; + if (sprite[spriteNum].picnum == RRTILE283) + { + int const newSprite = A_Spawn(spriteNum, RRTILE3440); + sprite[newSprite].lotag = sprite[spriteNum].lotag; + krand2(); + sprite[newSprite].clipdist = 48; + sprite[newSprite].ang -= ((krand2()&32)-(krand2()&64))&2047; + } + if (sprite[spriteNum].picnum == RRTILE280) + tag = sprite[spriteNum].hitag; + spriteNum = nextSprite; + } + if (tag != 0) + { + int const tileNumber = LANEPICS + tag + 1; + TileFiles.tileMakeWritable(tileNumber); + tileCopySection(LANEPICS+1, 0, 0, 128, 64, tileNumber, 0, 0); + + for (int pin = 0; pin < 10; pin++) + { + int x, y; + switch (pin) + { + case 0: + x = 64; + y = 48; + break; + case 1: + x = 56; + y = 40; + break; + case 2: + x = 72; + y = 40; + break; + case 3: + x = 48; + y = 32; + break; + case 4: + x = 64; + y = 32; + break; + case 5: + x = 80; + y = 32; + break; + case 6: + x = 40; + y = 24; + break; + case 7: + x = 56; + y = 24; + break; + case 8: + x = 72; + y = 24; + break; + case 9: + x = 88; + y = 24; + break; + } + tileCopySection(LANEPICS, 0, 0, 8, 8, tileNumber, x - 4, y - 10); + } + } +} + +void A_ResetLanePics(void) +{ + for (int tag = 1; tag <= 4; tag++) + { + int const tileNumber = LANEPICS + tag + 1; + TileFiles.tileMakeWritable(tileNumber); + tileCopySection(LANEPICS + 1, 0, 0, 128, 64, tileNumber, 0, 0); + + for (int pin = 0; pin < 10; pin++) + { + int x, y; + switch (pin) + { + case 0: + x = 64; + y = 48; + break; + case 1: + x = 56; + y = 40; + break; + case 2: + x = 72; + y = 40; + break; + case 3: + x = 48; + y = 32; + break; + case 4: + x = 64; + y = 32; + break; + case 5: + x = 80; + y = 32; + break; + case 6: + x = 40; + y = 24; + break; + case 7: + x = 56; + y = 24; + break; + case 8: + x = 72; + y = 24; + break; + case 9: + x = 88; + y = 24; + break; + } + tileCopySection(LANEPICS, 0, 0, 8, 8, tileNumber, x - 4, y - 10); + } + } +} + +ACTOR_STATIC void G_MoveActors(void) +{ + int spriteNum; + + if (!DEER && g_jailDoorCnt) + G_DoJailDoor(); + + if (!DEER && g_mineCartCnt) + G_MoveMineCart(); + + int bBoom = 0; + + if (!DEER && RRRA) + { + int spriteNum = headspritestat[117]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + if (sprite[spriteNum].hitag > 2) + sprite[spriteNum].hitag = 0; + if ((sprite[spriteNum].picnum == RRTILE8488 || sprite[spriteNum].picnum == RRTILE8490) && sprite[spriteNum].hitag != 2) + { + sprite[spriteNum].hitag = 2; + sprite[spriteNum].extra = -100; + } + if (sprite[spriteNum].hitag == 0) + { + sprite[spriteNum].extra++; + if (sprite[spriteNum].extra >= 30) + sprite[spriteNum].hitag = 1; + } + else if (sprite[spriteNum].hitag == 1) + { + sprite[spriteNum].extra--; + if (sprite[spriteNum].extra <= -30) + sprite[spriteNum].hitag = 0; + } + else if (sprite[spriteNum].hitag == 2) + { + sprite[spriteNum].extra--; + if (sprite[spriteNum].extra <= -104) + { + A_Spawn(spriteNum, sprite[spriteNum].lotag); + deletesprite(spriteNum); + } + } + + vec3_t const vect = { 0, 0, sprite[spriteNum].extra * 2}; + + A_MoveSprite(spriteNum, &vect, CLIPMASK0); + spriteNum = nextSprite; + } + + spriteNum = headspritestat[118]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + if (sprite[spriteNum].hitag > 1) + sprite[spriteNum].hitag = 0; + if (sprite[spriteNum].hitag == 0) + { + sprite[spriteNum].extra++; + if (sprite[spriteNum].extra >= 20) + sprite[spriteNum].hitag = 1; + } + else if (sprite[spriteNum].hitag == 1) + { + sprite[spriteNum].extra--; + if (sprite[spriteNum].extra <= -20) + sprite[spriteNum].hitag = 0; + } + + vec3_t const vect = { 0, 0, sprite[spriteNum].extra }; + + A_MoveSprite(spriteNum, &vect, CLIPMASK0); + spriteNum = nextSprite; + } + + if (g_player[myconnectindex].ps->level_end_timer > 0) + { + if (--g_player[myconnectindex].ps->level_end_timer == 0) + { + for (bssize_t TRAVERSE_CONNECT(playerNum)) + g_player[playerNum].ps->gm = MODE_EOL; + ud.eog = 1; + ud.level_number++; + if (ud.level_number > 6) + ud.level_number = 0; + m_level_number = ud.level_number; + } + } + + if (g_changeEnemySize > 0) + { + for (bssize_t enemySprite = 0; enemySprite < MAXSPRITES; enemySprite++) + { + switch (DYNAMICTILEMAP(sprite[enemySprite].picnum)) + { + case BILLYCOCK__STATICRR: + case BILLYRAY__STATICRR: + case BILLYRAYSTAYPUT__STATICRR: + case BRAYSNIPER__STATICRR: + case DOGRUN__STATICRR: + case LTH__STATICRR: + case HULKJUMP__STATICRR: + case HULK__STATICRR: + case HULKSTAYPUT__STATICRR: + case HEN__STATICRR: + case DRONE__STATIC: + case PIG__STATICRR: + case MINION__STATICRR: + case MINIONSTAYPUT__STATICRR: + case UFO1__STATICRR: + case UFO2__STATICRR: + case UFO3__STATICRR: + case UFO4__STATICRR: + case UFO5__STATICRR: + case COOT__STATICRR: + case COOTSTAYPUT__STATICRR: + case VIXEN__STATICRR: + case BIKERB__STATICRR: + case BIKERBV2__STATICRR: + case BIKER__STATICRR: + case MAKEOUT__STATICRR: + case CHEERB__STATICRR: + case CHEER__STATICRR: + case CHEERSTAYPUT__STATICRR: + case COOTPLAY__STATICRR: + case BILLYPLAY__STATICRR: + case MINIONBOAT__STATICRR: + case HULKBOAT__STATICRR: + case CHEERBOAT__STATICRR: + case RABBIT__STATICRR: + case MAMA__STATICRR: + if (g_changeEnemySize == 3) + { + sprite[enemySprite].xrepeat = sprite[enemySprite].xrepeat << 1; + sprite[enemySprite].yrepeat = sprite[enemySprite].yrepeat << 1; + sprite[enemySprite].clipdist = mulscale7(sprite[enemySprite].xrepeat, tilesiz[sprite[enemySprite].picnum].x); + } + else if (g_changeEnemySize == 2) + { + sprite[enemySprite].xrepeat = sprite[enemySprite].xrepeat >> 1; + sprite[enemySprite].yrepeat = sprite[enemySprite].yrepeat >> 1; + sprite[enemySprite].clipdist = mulscale7(sprite[enemySprite].xrepeat, tilesiz[sprite[enemySprite].picnum].x); + } + break; + } + } + g_changeEnemySize = 0; + } + + spriteNum = headspritestat[121]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + sprite[spriteNum].extra++; + if (sprite[spriteNum].extra < 100) + { + if (sprite[spriteNum].extra == 90) + { + sprite[spriteNum].picnum--; + if (sprite[spriteNum].picnum < PIG + 7) + sprite[spriteNum].picnum = PIG + 7; + sprite[spriteNum].extra = 1; + } + + vec3_t const vect = { 0, 0, -300 }; + A_MoveSprite(spriteNum, &vect, CLIPMASK0); + if (sector[sprite[spriteNum].sectnum].ceilingz + (4 << 8) > sprite[spriteNum].z) + { + sprite[spriteNum].picnum = 0; + sprite[spriteNum].extra = 100; + } + } + else if (sprite[spriteNum].extra == 200) + { + vec3_t const pos = { sprite[spriteNum].x, sprite[spriteNum].y, sector[sprite[spriteNum].sectnum].floorz - 10 }; + setsprite(spriteNum, &pos); + sprite[spriteNum].extra = 1; + sprite[spriteNum].picnum = PIG + 11; + A_Spawn(spriteNum, TRANSPORTERSTAR); + } + spriteNum = nextSprite; + } + + spriteNum = headspritestat[119]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + if (sprite[spriteNum].hitag > 0) + { + if (sprite[spriteNum].extra == 0) + { + sprite[spriteNum].hitag--; + sprite[spriteNum].extra = 150; + A_Spawn(spriteNum, RABBIT); + } + else + sprite[spriteNum].extra--; + } + spriteNum = nextSprite; + } + spriteNum = headspritestat[116]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + if (sprite[spriteNum].extra) + { + if (sprite[spriteNum].extra == sprite[spriteNum].lotag) + S_PlaySound(183); + sprite[spriteNum].extra--; + vec3_t const vect = { + (sprite[spriteNum].hitag*sintable[(sprite[spriteNum].ang + 512) & 2047]) >> 14, + (sprite[spriteNum].hitag*sintable[sprite[spriteNum].ang & 2047]) >> 14, + sprite[spriteNum].hitag << 1 + }; + if (A_MoveSprite(spriteNum, &vect, CLIPMASK0) > 0) + { + A_PlaySound(PIPEBOMB_EXPLODE, spriteNum); + deletesprite(spriteNum); + } + if (sprite[spriteNum].extra == 0) + { + S_PlaySound(215); + deletesprite(spriteNum); + g_earthquakeTime = 32; + P_PalFrom(g_player[myconnectindex].ps, 48, 32, 32, 32); + } + } + spriteNum = nextSprite; + } + + spriteNum = headspritestat[115]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + if (sprite[spriteNum].extra) + { + if (sprite[spriteNum].picnum != RRTILE8162) + sprite[spriteNum].picnum = RRTILE8162; + sprite[spriteNum].extra--; + if (sprite[spriteNum].extra == 0) + { + int const fortune = krand2()&127; + if (fortune < 96) + { + sprite[spriteNum].picnum = RRTILE8162 + 3; + } + else if (fortune < 112) + { + if (g_slotWin & 1) + { + sprite[spriteNum].picnum = RRTILE8162 + 3; + } + else + { + sprite[spriteNum].picnum = RRTILE8162 + 2; + A_Spawn(spriteNum, BATTERYAMMO); + g_slotWin |= 1; + A_PlaySound(52, spriteNum); + } + } + else if (fortune < 120) + { + if (g_slotWin & 2) + { + sprite[spriteNum].picnum = RRTILE8162 + 3; + } + else + { + sprite[spriteNum].picnum = RRTILE8162 + 6; + A_Spawn(spriteNum, HEAVYHBOMB); + g_slotWin |= 2; + A_PlaySound(52, spriteNum); + } + } + else if (fortune < 126) + { + if (g_slotWin & 4) + { + sprite[spriteNum].picnum = RRTILE8162 + 3; + } + else + { + sprite[spriteNum].picnum = RRTILE8162 + 5; + A_Spawn(spriteNum, SIXPAK); + g_slotWin |= 4; + A_PlaySound(52, spriteNum); + } + } + else + { + if (g_slotWin & 8) + { + sprite[spriteNum].picnum = RRTILE8162 + 3; + } + else + { + sprite[spriteNum].picnum = RRTILE8162 + 4; + A_Spawn(spriteNum, ATOMICHEALTH); + g_slotWin |= 8; + A_PlaySound(52, spriteNum); + } + } + } + } + spriteNum = nextSprite; + } + + spriteNum = headspritestat[122]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + if (sprite[spriteNum].extra) + { + if (sprite[spriteNum].picnum != RRTILE8589) + sprite[spriteNum].picnum = RRTILE8589; + sprite[spriteNum].extra--; + if (sprite[spriteNum].extra == 0) + { + int const fortune = krand2()&127; + if (fortune < 96) + { + sprite[spriteNum].picnum = RRTILE8589 + 4; + } + else if (fortune < 112) + { + if (g_slotWin & 1) + { + sprite[spriteNum].picnum = RRTILE8589 + 4; + } + else + { + sprite[spriteNum].picnum = RRTILE8589 + 5; + A_Spawn(spriteNum, BATTERYAMMO); + g_slotWin |= 1; + A_PlaySound(342, spriteNum); + } + } + else if (fortune < 120) + { + if (g_slotWin & 2) + { + sprite[spriteNum].picnum = RRTILE8589 + 4; + } + else + { + sprite[spriteNum].picnum = RRTILE8589 + 6; + A_Spawn(spriteNum, HEAVYHBOMB); + g_slotWin |= 2; + A_PlaySound(342, spriteNum); + } + } + else if (fortune < 126) + { + if (g_slotWin & 4) + { + sprite[spriteNum].picnum = RRTILE8589 + 4; + } + else + { + sprite[spriteNum].picnum = RRTILE8589 + 2; + A_Spawn(spriteNum, SIXPAK); + g_slotWin |= 4; + A_PlaySound(342, spriteNum); + } + } + else + { + if (g_slotWin & 8) + { + sprite[spriteNum].picnum = RRTILE8589 + 4; + } + else + { + sprite[spriteNum].picnum = RRTILE8589 + 3; + A_Spawn(spriteNum, ATOMICHEALTH); + g_slotWin |= 8; + A_PlaySound(342, spriteNum); + } + } + } + } + spriteNum = nextSprite; + } + + spriteNum = headspritestat[123]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + if (sprite[spriteNum].lotag == 5) + if (!S_CheckSoundPlaying(spriteNum, 330)) + A_PlaySound(330, spriteNum); + spriteNum = nextSprite; + } + } + + if (!DEER && RR) + { + spriteNum = headspritestat[107]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + + if (sprite[spriteNum].hitag == 100) + { + sprite[spriteNum].z += (4 << 8); + if (sprite[spriteNum].z >= sector[sprite[spriteNum].sectnum].floorz + 15168) + sprite[spriteNum].z = sector[sprite[spriteNum].sectnum].floorz + 15168; + } + + if (sprite[spriteNum].picnum == LUMBERBLADE) + { + sprite[spriteNum].extra++; + if (sprite[spriteNum].extra == 192) + { + sprite[spriteNum].hitag = 0; + sprite[spriteNum].z = sector[sprite[spriteNum].sectnum].floorz - 15168; + sprite[spriteNum].extra = 0; + sprite[spriteNum].picnum = RRTILE3410; + int otherSprite = headspritestat[0]; + while (otherSprite >= 0) + { + int const nextOtherSprite = nextspritestat[otherSprite]; + if (sprite[otherSprite].picnum == DIPSWITCH3 + 1) + if (sprite[otherSprite].hitag == 999) + sprite[otherSprite].picnum = DIPSWITCH3; + otherSprite = nextOtherSprite; + } + } + } + spriteNum = nextSprite; + } + + if (g_chickenPlant) + { + spriteNum = headspritestat[106]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + switch (DYNAMICTILEMAP(sprite[spriteNum].picnum)) + { + case RRTILE285__STATICRR: + sprite[spriteNum].lotag--; + if (sprite[spriteNum].lotag < 0) + { + int const newSprite = A_Spawn(spriteNum, RRTILE3190); + sprite[newSprite].ang = sprite[spriteNum].ang; + sprite[spriteNum].lotag = 128; + } + break; + case RRTILE286__STATICRR: + sprite[spriteNum].lotag--; + if (sprite[spriteNum].lotag < 0) + { + int const newSprite = A_Spawn(spriteNum, RRTILE3192); + sprite[newSprite].ang = sprite[spriteNum].ang; + sprite[spriteNum].lotag = 256; + } + break; + case RRTILE287__STATICRR: + sprite[spriteNum].lotag--; + if (sprite[spriteNum].lotag < 0) + { + A_SpawnMultiple(spriteNum, MONEY, (krand2()&3)+4); + sprite[spriteNum].lotag = 84; + } + break; + case RRTILE288__STATICRR: + sprite[spriteNum].lotag--; + if (sprite[spriteNum].lotag < 0) + { + int const newSprite = A_Spawn(spriteNum, RRTILE3132); + sprite[spriteNum].lotag = 96; + if (!RRRA) + A_PlaySound(472, newSprite); + } + break; + case RRTILE289__STATICRR: + sprite[spriteNum].lotag--; + if (sprite[spriteNum].lotag < 0) + { + int const newSprite = A_Spawn(spriteNum, RRTILE3120); + sprite[newSprite].ang = sprite[spriteNum].ang; + sprite[spriteNum].lotag = 448; + } + break; + case RRTILE290__STATICRR: + sprite[spriteNum].lotag--; + if (sprite[spriteNum].lotag < 0) + { + int const newSprite = A_Spawn(spriteNum, RRTILE3122); + sprite[newSprite].ang = sprite[spriteNum].ang; + sprite[spriteNum].lotag = 64; + } + break; + case RRTILE291__STATICRR: + sprite[spriteNum].lotag--; + if (sprite[spriteNum].lotag < 0) + { + int const newSprite = A_Spawn(spriteNum, RRTILE3123); + sprite[newSprite].ang = sprite[spriteNum].ang; + sprite[spriteNum].lotag = 512; + } + break; + case RRTILE292__STATICRR: + sprite[spriteNum].lotag--; + if (sprite[spriteNum].lotag < 0) + { + int const newSprite = A_Spawn(spriteNum, RRTILE3124); + sprite[newSprite].ang = sprite[spriteNum].ang; + sprite[spriteNum].lotag = 224; + } + break; + case RRTILE293__STATICRR: + sprite[spriteNum].lotag--; + if (sprite[spriteNum].lotag < 0) + { + A_DoGuts(spriteNum, JIBS1, 1); + A_DoGuts(spriteNum, JIBS2, 1); + A_DoGuts(spriteNum, JIBS3, 1); + A_DoGuts(spriteNum, JIBS4, 1); + sprite[spriteNum].lotag = 256; + } + break; + } + spriteNum = nextSprite; + } + } + + spriteNum = headspritestat[105]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + if (sprite[spriteNum].picnum == RRTILE280) + if (sprite[spriteNum].lotag == 100) + { + if (A_PinSectorResetUp(SECT(spriteNum))) + { + sprite[spriteNum].lotag = 0; + if (sprite[spriteNum].extra == 1) + { + if (!A_CheckPins(SECT(spriteNum))) + { + sprite[spriteNum].extra = 2; + } + } + if (sprite[spriteNum].extra == 2) + { + sprite[spriteNum].extra = 0; + A_ResetPins(SECT(spriteNum)); + } + } + } + spriteNum = nextSprite; + } + + spriteNum = headspritestat[108]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + + spritetype *const pSprite= &sprite[spriteNum]; + if (pSprite->picnum == RRTILE296) + { + int playerDist; + DukePlayer_t *const pPlayer = g_player[A_FindPlayer(pSprite, &playerDist)].ps; + + if (playerDist < 2047) + { + int otherSprite = headspritestat[108]; + while (otherSprite >= 0) + { + int const nextOtherSprite = nextspritestat[otherSprite]; + if (sprite[otherSprite].picnum == RRTILE297) + { + pPlayer->q16ang = F16(sprite[otherSprite].ang); + pPlayer->pos = *(vec3_t*)&sprite[otherSprite]; + pPlayer->pos.z -= (36<<8); + + pPlayer->opos = pPlayer->pos; + pPlayer->bobpos = *(vec2_t*)&pPlayer->pos; + + changespritesect(pPlayer->i, sprite[otherSprite].sectnum); + pPlayer->cursectnum = sprite[otherSprite].sectnum; + + A_PlaySound(TELEPORTER, otherSprite); + + A_DeleteSprite(otherSprite); + } + otherSprite = nextOtherSprite; + } + } + } + spriteNum = nextSprite; + } + } + + spriteNum = headspritestat[STAT_ACTOR]; + + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + spritetype *const pSprite = &sprite[spriteNum]; + int const sectNum = pSprite->sectnum; + int32_t *const pData = actor[spriteNum].t_data; + int deleteAfterExecute = 0; + + int switchPic; + + if (pSprite->xrepeat == 0 || sectNum < 0 || sectNum >= MAXSECTORS) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + Bmemcpy(&actor[spriteNum].bpos, pSprite, sizeof(vec3_t)); + + switchPic = pSprite->picnum; + + if (!RR && pSprite->picnum > GREENSLIME && pSprite->picnum <= GREENSLIME+7) + switchPic = GREENSLIME; + + if (RR && (switchPic == RRTILE3440 + 1 || switchPic == HENSTAND + 1)) + switchPic--; + + + if (!DEER) + switch (DYNAMICTILEMAP(switchPic)) + { + case DUCK__STATIC: + case TARGET__STATIC: + if (RR) break; + if (pSprite->cstat&32) + { + pData[0]++; + if (pData[0] > 60) + { + pData[0] = 0; + pSprite->cstat = 128+257+16; + pSprite->extra = 1; + } + } + else + { + if (A_IncurDamage(spriteNum) >= 0) + { + int doEffects = 1; + + pSprite->cstat = 32+128; + + for (bssize_t SPRITES_OF(STAT_ACTOR, actorNum)) + { + if ((sprite[actorNum].lotag == pSprite->lotag && sprite[actorNum].picnum == pSprite->picnum) + && ((sprite[actorNum].hitag != 0) ^ ((sprite[actorNum].cstat & 32) != 0))) + { + doEffects = 0; + break; + } + } + + if (doEffects == 1) + { + G_OperateActivators(pSprite->lotag, -1); + G_OperateForceFields(spriteNum, pSprite->lotag); + G_OperateMasterSwitches(pSprite->lotag); + } + } + } + goto next_sprite; + + case RESPAWNMARKERRED__STATIC: + case RESPAWNMARKERYELLOW__STATIC: + case RESPAWNMARKERGREEN__STATIC: + if (++T1(spriteNum) > g_itemRespawnTime) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + if (T1(spriteNum) >= (g_itemRespawnTime>>1) && T1(spriteNum) < ((g_itemRespawnTime>>1)+(g_itemRespawnTime>>2))) + PN(spriteNum) = RESPAWNMARKERYELLOW; + else if (T1(spriteNum) > ((g_itemRespawnTime>>1)+(g_itemRespawnTime>>2))) + PN(spriteNum) = RESPAWNMARKERGREEN; + + A_Fall(spriteNum); + break; + + case HELECOPT__STATIC: + case DUKECAR__STATIC: + if (RR) break; + pSprite->z += pSprite->zvel; + pData[0]++; + + if (pData[0] == 4) + A_PlaySound(WAR_AMBIENCE2,spriteNum); + + if (pData[0] > (GAMETICSPERSEC*8)) + { + g_earthquakeTime = 16; + S_PlaySound(RPG_EXPLODE); + + for (bssize_t j = 0; j < 32; j++) + RANDOMSCRAP(pSprite, spriteNum); + + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else if ((pData[0]&3) == 0) + A_Spawn(spriteNum,EXPLOSION2); + + A_SetSprite(spriteNum,CLIPMASK0); + break; + + case RAT__STATIC: + A_Fall(spriteNum); + if (A_SetSprite(spriteNum, CLIPMASK0)) + { + if (!RRRA && (krand2()&255) < 3) A_PlaySound(RATTY,spriteNum); + pSprite->ang += (krand2()&31)-15+(sintable[(pData[0]<<8)&2047]>>11); + } + else + { + T1(spriteNum)++; + if (T1(spriteNum) > 1) + { + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else pSprite->ang = (krand2()&2047); + } + if (pSprite->xvel < 128) + pSprite->xvel+=2; + pSprite->ang += (krand2()&3)-6; + break; + + case RRTILE3190__STATICRR: + case RRTILE3191__STATICRR: + case RRTILE3192__STATICRR: + { + if (!g_chickenPlant) DELETE_SPRITE_AND_CONTINUE(spriteNum); + if (sector[SECT(spriteNum)].lotag == 903) + A_Fall(spriteNum); + + vec3_t const vect = { + (pSprite->xvel*(sintable[(pSprite->ang + 512) & 2047])) >> 14, + (pSprite->xvel*(sintable[pSprite->ang & 2047])) >> 14, + pSprite->zvel + }; + int const moveSprite = A_MoveSprite(spriteNum, &vect, CLIPMASK0); + switch (sector[SECT(spriteNum)].lotag) + { + case 901: + sprite[spriteNum].picnum = RRTILE3191; + break; + case 902: + sprite[spriteNum].picnum = RRTILE3192; + break; + case 903: + if (SZ(spriteNum) >= sector[SECT(spriteNum)].floorz - ZOFFSET3) { DELETE_SPRITE_AND_CONTINUE(spriteNum); } + break; + case 904: + DELETE_SPRITE_AND_CONTINUE(spriteNum); + break; + } + if (moveSprite & 49152) + { + if ((moveSprite & 49152) == 32768) { DELETE_SPRITE_AND_CONTINUE(spriteNum); } + else if ((moveSprite & 49152) == 49152) { DELETE_SPRITE_AND_CONTINUE(spriteNum); } + } + break; + } + + case RRTILE3120__STATICRR: + case RRTILE3122__STATICRR: + case RRTILE3123__STATICRR: + case RRTILE3124__STATICRR: + { + if (!g_chickenPlant) DELETE_SPRITE_AND_CONTINUE(spriteNum); + A_Fall(spriteNum); + + vec3_t const vect = { + (pSprite->xvel*(sintable[(pSprite->ang + 512) & 2047])) >> 14, + (pSprite->xvel*(sintable[pSprite->ang & 2047])) >> 14, + pSprite->zvel + }; + int const moveSprite = A_MoveSprite(spriteNum, &vect, CLIPMASK0); + if (moveSprite & 49152) + { + if ((moveSprite & 49152) == 32768) { DELETE_SPRITE_AND_CONTINUE(spriteNum); } + else if ((moveSprite & 49152) == 49152) { DELETE_SPRITE_AND_CONTINUE(spriteNum); } + } + if (sector[pSprite->sectnum].lotag == 903) + { + if (SZ(spriteNum) >= sector[SECT(spriteNum)].floorz - (4 << 8)) + { + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + } + else if (sector[pSprite->sectnum].lotag == 904) + { + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + break; + } + + case RRTILE3132__STATICRR: + { + if (!g_chickenPlant) DELETE_SPRITE_AND_CONTINUE(spriteNum); + A_Fall(spriteNum); + + vec3_t const vect = { + (pSprite->xvel*(sintable[(pSprite->ang + 512) & 2047])) >> 14, + (pSprite->xvel*(sintable[pSprite->ang & 2047])) >> 14, + pSprite->zvel + }; + A_MoveSprite(spriteNum, &vect, CLIPMASK0); + if (pSprite->z >= sector[pSprite->sectnum].floorz - (8 << 8)) + { + if (sector[pSprite->sectnum].lotag == 1) + { + int const newSprite = A_Spawn(spriteNum, WATERSPLASH2); + sprite[newSprite].z = sector[sprite[newSprite].sectnum].floorz; + } + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + break; + } + + case BOWLINGBALL__STATICRR: + if (pSprite->xvel) + { + if (!A_CheckSoundPlaying(spriteNum, 356)) + A_PlaySound(356, spriteNum); + } + else + { + A_Spawn(spriteNum, BOWLINGBALLSPRITE); + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + if (sector[pSprite->sectnum].lotag == 900) + { + S_StopEnvSound(356, spriteNum); + } + fallthrough__; + case RRTILE3440__STATICRR: + case HENSTAND__STATICRR: + if (pSprite->picnum == HENSTAND || pSprite->picnum == HENSTAND + 1) + { + if (--pSprite->lotag == 0) + { + A_Spawn(spriteNum, HEN); + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + } + if (sector[pSprite->sectnum].lotag == 900) + pSprite->xvel = 0; + if (pSprite->xvel) + { + A_Fall(spriteNum); + + vec3_t const vect = { + (pSprite->xvel*(sintable[(pSprite->ang + 512) & 2047])) >> 14, + (pSprite->xvel*(sintable[pSprite->ang & 2047])) >> 14, + pSprite->zvel + }; + int moveSprite = A_MoveSprite(spriteNum, &vect, CLIPMASK0); + if (moveSprite & 49152) + { + if ((moveSprite & 49152) == 32768) + { + moveSprite &= (MAXWALLS - 1); + Proj_BounceOffWall(pSprite, moveSprite); + } + else if ((moveSprite & 49152) == 49152) + { + moveSprite &= (MAXSPRITES - 1); + A_DamageObject(spriteNum, moveSprite); + if (sprite[moveSprite].picnum == HEN) + { + int const newSprite = A_Spawn(moveSprite, HENSTAND); + A_DeleteSprite(moveSprite); + sprite[newSprite].xvel = 32; + sprite[newSprite].lotag = 40; + sprite[newSprite].ang = pSprite->ang; + } + } + } + if (--pSprite->xvel < 0) pSprite->xvel = 0; + pSprite->cstat = 257; + if (pSprite->picnum == RRTILE3440) + { + pSprite->cstat |= 4 & pSprite->xvel; + pSprite->cstat |= 8 & pSprite->xvel; + if (krand2() & 1) + pSprite->picnum = RRTILE3440 + 1; + } + else if (pSprite->picnum == HENSTAND) + { + pSprite->cstat |= 4 & pSprite->xvel; + pSprite->cstat |= 8 & pSprite->xvel; + if (krand2() & 1) + pSprite->picnum = HENSTAND + 1; + if (!pSprite->xvel) + deleteAfterExecute = 1; + } + if (pSprite->picnum == RRTILE3440 || (pSprite->picnum == RRTILE3440 + 1 && !pSprite->xvel)) + deleteAfterExecute = 1; + } + else if (sector[pSprite->sectnum].lotag == 900) + { + if (pSprite->picnum == BOWLINGBALL) + A_BallReturn(spriteNum); + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + break; + + case QUEBALL__STATIC: + case STRIPEBALL__STATIC: + if (pSprite->xvel) + { + for (bssize_t SPRITES_OF(STAT_DEFAULT, hitObject)) + if (sprite[hitObject].picnum == POCKET && ldist(&sprite[hitObject],pSprite) < 52) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + int hitObject = clipmove((vec3_t *)pSprite, &pSprite->sectnum, + (((pSprite->xvel * (sintable[(pSprite->ang + 512) & 2047])) >> 14) * TICSPERFRAME) << 11, + (((pSprite->xvel * (sintable[pSprite->ang & 2047])) >> 14) * TICSPERFRAME) << 11, 24L, ZOFFSET6, + ZOFFSET6, CLIPMASK1); + + if (hitObject & 49152) + { + if ((hitObject & 49152) == 32768) + { + hitObject &= (MAXWALLS - 1); + Proj_BounceOffWall(pSprite, hitObject); + } + else if ((hitObject & 49152) == 49152) + { + hitObject &= (MAXSPRITES - 1); + A_DamageObject(spriteNum, hitObject); + } + } + + if (--pSprite->xvel < 0) + pSprite->xvel = 0; + + if (pSprite->picnum == STRIPEBALL) + { + pSprite->cstat = 257; + pSprite->cstat |= (4 & pSprite->xvel) | (8 & pSprite->xvel); + } + } + else + { + int32_t playerDist; + int const playerNum = A_FindPlayer(pSprite,&playerDist); + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + // I'm 50/50 on this being either a typo or a stupid hack + if (playerDist < 1596) + { + int const angDiff = G_GetAngleDelta(fix16_to_int(pPlayer->q16ang),getangle(pSprite->x-pPlayer->pos.x,pSprite->y-pPlayer->pos.y)); + + if (angDiff > -64 && angDiff < 64 && TEST_SYNC_KEY(g_player[playerNum].input->bits, SK_OPEN) + && pPlayer->toggle_key_flag == 1) + { + int ballSprite; + + for (SPRITES_OF(STAT_ACTOR, ballSprite)) + { + if (sprite[ballSprite].picnum == QUEBALL || sprite[ballSprite].picnum == STRIPEBALL) + { + int const angDiff2 = G_GetAngleDelta( + fix16_to_int(pPlayer->q16ang), getangle(sprite[ballSprite].x - pPlayer->pos.x, sprite[ballSprite].y - pPlayer->pos.y)); + + if (angDiff2 > -64 && angDiff2 < 64) + { + int32_t ballDist; + A_FindPlayer(&sprite[ballSprite], &ballDist); + + if (playerDist > ballDist) + break; + } + } + } + + if (ballSprite == -1) + { + pSprite->xvel = (pSprite->pal == 12) ? 164 : 140; + pSprite->ang = fix16_to_int(pPlayer->q16ang); + + pPlayer->toggle_key_flag = 2; + } + } + } + + if (playerDist < 512 && pSprite->sectnum == pPlayer->cursectnum) + { + pSprite->ang = getangle(pSprite->x-pPlayer->pos.x,pSprite->y-pPlayer->pos.y); + pSprite->xvel = 48; + } + } + + break; + + case FORCESPHERE__STATIC: + if (pSprite->yvel == 0) + { + pSprite->yvel = 1; + + for (bssize_t l = 512; l < (2048 - 512); l += 128) + { + for (bssize_t j = 0; j < 2048; j += 128) + { + int const newSprite = A_Spawn(spriteNum, FORCESPHERE); + sprite[newSprite].cstat = 257 + 128; + sprite[newSprite].clipdist = 64; + sprite[newSprite].ang = j; + sprite[newSprite].zvel = sintable[l & 2047] >> 5; + sprite[newSprite].xvel = sintable[(l + 512) & 2047] >> 9; + sprite[newSprite].owner = spriteNum; + } + } + } + + if (pData[3] > 0) + { + if (pSprite->zvel < 6144) + pSprite->zvel += 192; + + pSprite->z += pSprite->zvel; + + if (pSprite->z > sector[sectNum].floorz) + pSprite->z = sector[sectNum].floorz; + + if (--pData[3] == 0) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else if (pData[2] > 10) + { + for (bssize_t SPRITES_OF(STAT_MISC, miscSprite)) + { + if (sprite[miscSprite].owner == spriteNum && sprite[miscSprite].picnum == FORCESPHERE) + actor[miscSprite].t_data[1] = 1 + (krand2() & 63); + } + + pData[3] = 64; + } + + goto next_sprite; + + case RECON__STATIC: + case UFO1__STATICRR: + case UFO2__STATICRR: + case UFO3__STATICRR: + case UFO4__STATICRR: + case UFO5__STATICRR: + { + int playerNum; + DukePlayer_t *pPlayer; + + A_GetZLimits(spriteNum); + + pSprite->shade += (sector[pSprite->sectnum].ceilingstat & 1) ? (sector[pSprite->sectnum].ceilingshade - pSprite->shade) >> 1 + : (sector[pSprite->sectnum].floorshade - pSprite->shade) >> 1; + + if (pSprite->z < sector[sectNum].ceilingz + ZOFFSET5) + pSprite->z = sector[sectNum].ceilingz + ZOFFSET5; + +#if 0 //def POLYMER + gamelights[gamelightcount&(PR_MAXLIGHTS-1)].sector = s->sectnum; + gamelights[gamelightcount&(PR_MAXLIGHTS-1)].x = s->x; + gamelights[gamelightcount&(PR_MAXLIGHTS-1)].y = s->y; + gamelights[gamelightcount&(PR_MAXLIGHTS-1)].z = s->z + 10248; + gamelights[gamelightcount&(PR_MAXLIGHTS-1)].range = 8192; + + gamelights[gamelightcount&(PR_MAXLIGHTS-1)].angle = s->ang; + gamelights[gamelightcount&(PR_MAXLIGHTS-1)].horiz = 100; + gamelights[gamelightcount&(PR_MAXLIGHTS-1)].radius = 256; + gamelights[gamelightcount&(PR_MAXLIGHTS-1)].faderadius = 200; + + gamelights[gamelightcount&(PR_MAXLIGHTS-1)].color[0] = 255; + gamelights[gamelightcount&(PR_MAXLIGHTS-1)].color[1] = 255; + gamelights[gamelightcount&(PR_MAXLIGHTS-1)].color[2] = 255; + + gamelights[gamelightcount&(PR_MAXLIGHTS-1)].priority = PR_LIGHT_PRIO_MAX_GAME; + + if (gamelightcount < PR_MAXLIGHTS) + gamelightcount++; +#endif + + if (!g_netServer && ud.multimode < 2) + { + if (g_noEnemies == 1) + { + pSprite->cstat = 32768; + goto next_sprite; + } + else if (g_noEnemies == 2) pSprite->cstat = 257; + } + if (A_IncurDamage(spriteNum) >= 0) + { + if (pSprite->extra < 0 && pData[0] != -1) + { + pData[0] = -1; + pSprite->extra = 0; + } + + if (!RR) + A_PlaySound(RECO_PAIN,spriteNum); + RANDOMSCRAP(pSprite, spriteNum); + } + + if (pData[0] == -1) + { + pSprite->z += 1024; + pData[2]++; + + if ((pData[2]&3) == 0) + A_Spawn(spriteNum,EXPLOSION2); + + A_GetZLimits(spriteNum); + pSprite->ang += 96; + pSprite->xvel = 128; + + if (A_SetSprite(spriteNum, CLIPMASK0) != 1 || pSprite->z > actor[spriteNum].floorz) + { + for (bssize_t l = 0; l < 16; l++) + RANDOMSCRAP(pSprite, spriteNum); + + //int const newSprite = A_Spawn(spriteNum, EXPLOSION2); + A_PlaySound(LASERTRIP_EXPLODE, spriteNum); + if (RR) + { + if (RRRA && g_ufoSpawnMinion) + A_Spawn(spriteNum, MINION); + else if (pSprite->picnum == UFO1) + A_Spawn(spriteNum, HEN); + else if (pSprite->picnum == UFO2) + A_Spawn(spriteNum, COOT); + else if (pSprite->picnum == UFO3) + A_Spawn(spriteNum, COW); + else if (pSprite->picnum == UFO4) + A_Spawn(spriteNum, PIG); + else if (pSprite->picnum == UFO5) + A_Spawn(spriteNum, BILLYRAY); + } + else + A_Spawn(spriteNum, PIGCOP); + P_AddKills(g_player[myconnectindex].ps, 1); + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + + goto next_sprite; + } + else + { + if (pSprite->z > actor[spriteNum].floorz-(48<<8)) + pSprite->z = actor[spriteNum].floorz-(48<<8); + } + + int32_t playerDist; + playerNum = A_FindPlayer(pSprite, &playerDist); + pPlayer = g_player[playerNum].ps; + + int const spriteOwner = pSprite->owner; + + // 3 = findplayerz, 4 = shoot + + if (pData[0] >= 4) + { + if ((++pData[2] & 15) == 0) + { + int const saveAng = pSprite->ang; + pSprite->ang = actor[spriteNum].tempang; + if (!RR) + A_PlaySound(RECO_ATTACK, spriteNum); + A_Shoot(spriteNum, FIRELASER); + pSprite->ang = saveAng; + } + if (pData[2] > (GAMETICSPERSEC * 3) + || !cansee(pSprite->x, pSprite->y, pSprite->z - ZOFFSET2, pSprite->sectnum, pPlayer->pos.x, pPlayer->pos.y, + pPlayer->pos.z, pPlayer->cursectnum)) + { + pData[0] = 0; + pData[2] = 0; + } + else actor[spriteNum].tempang += G_GetAngleDelta(actor[spriteNum].tempang, + getangle(pPlayer->pos.x - pSprite->x, + pPlayer->pos.y - pSprite->y)) / 3; + } + else if (pData[0] == 2 || pData[0] == 3) + { + pData[3] = 0; + pSprite->xvel = (pSprite->xvel > 0) ? pSprite->xvel - 16 : 0; + + if (pData[0] == 2) + { + int const zDiff = pPlayer->pos.z - pSprite->z; + + if (klabs(zDiff) < (48 << 8)) + pData[0] = 3; + else + pSprite->z += ksgn(pPlayer->pos.z - pSprite->z) << (RR ? 8 : 10); + } + else + { + pData[2]++; + if (pData[2] > (GAMETICSPERSEC*3) || + !cansee(pSprite->x,pSprite->y,pSprite->z-ZOFFSET2,pSprite->sectnum, pPlayer->pos.x,pPlayer->pos.y,pPlayer->pos.z,pPlayer->cursectnum)) + { + pData[0] = 1; + pData[2] = 0; + } + else if ((pData[2]&15) == 0) + { + if (!RR) + A_PlaySound(RECO_ATTACK,spriteNum); + A_Shoot(spriteNum,FIRELASER); + } + } + pSprite->ang += G_GetAngleDelta(pSprite->ang, getangle(pPlayer->pos.x - pSprite->x, pPlayer->pos.y - pSprite->y)) >> 2; + } + + if (pData[0] != 2 && pData[0] != 3) + { + int newAngle; + int locatorDist = ldist(&sprite[spriteOwner], pSprite); + if (locatorDist <= 1524) + { + newAngle = pSprite->ang; + pSprite->xvel >>= 1; + } + else newAngle = getangle(sprite[spriteOwner].x - pSprite->x, sprite[spriteOwner].y - pSprite->y); + + if (pData[0] == 1 || pData[0] == 4) // Found a locator and going with it + { + locatorDist = dist(&sprite[spriteOwner], pSprite); + + if (locatorDist <= 1524) + { + pData[0] = (pData[0] == 1) ? 0 : 5; + } + else + { + // Control speed here + if (pSprite->xvel < 256) pSprite->xvel += 32; + } + + if (pData[0] < 2) pData[2]++; + + if (playerDist < 6144 && pData[0] < 2 && pData[2] > (GAMETICSPERSEC*4)) + { + pData[0] = 2+(krand2()&2); + pData[2] = 0; + actor[spriteNum].tempang = pSprite->ang; + } + } + + int locatorSprite = pSprite->owner; + + if (pData[0] == 0 || pData[0] == 5) + { + pData[0] = (pData[0] == 0) ? 1 : 4; + pSprite->owner = A_FindLocator(pSprite->hitag, -1); + locatorSprite = pSprite->owner; + + if (locatorSprite == -1) + { + locatorSprite = actor[spriteNum].t_data[5]; + pSprite->hitag = locatorSprite; + pSprite->owner = A_FindLocator(locatorSprite, -1); + locatorSprite = pSprite->owner; + + if (locatorSprite == -1) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else pSprite->hitag++; + } + + // RECON_T4 + pData[3] = G_GetAngleDelta(pSprite->ang,newAngle); + pSprite->ang += pData[3]>>3; + + if (pSprite->z < sprite[locatorSprite].z) + pSprite->z += 1024; + else + pSprite->z -= 1024; + } + + int sndNum = RR ? 457 : RECO_ROAM; + + if (!A_CheckSoundPlaying(spriteNum,sndNum)) + A_PlaySound(sndNum,spriteNum); + + A_SetSprite(spriteNum,CLIPMASK0); + + goto next_sprite; + } + + case OOZ2__STATIC: + if (RR) break; + fallthrough__; + case OOZ__STATIC: + { + A_GetZLimits(spriteNum); + + int const yrepeat = min((actor[spriteNum].floorz - actor[spriteNum].ceilingz) >> 9, 255); + int const xrepeat = clamp(25 - (yrepeat >> 1), 8, 48); + + pSprite->yrepeat = yrepeat; + pSprite->xrepeat = xrepeat; + pSprite->z = actor[spriteNum].floorz; + + goto next_sprite; + } + + case GREENSLIME__STATIC: + { + if (RR) break; + // #ifndef VOLUMEONE + if (!g_netServer && ud.multimode < 2) + { + if (g_noEnemies == 1) + { + pSprite->cstat = 32768; + goto next_sprite; + } + else if (g_noEnemies == 2) pSprite->cstat = 257; + } + // #endif + + pData[1]+=128; + + if (sector[sectNum].floorstat&1) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + int32_t playerDist; + int const playerNum = A_FindPlayer(pSprite, &playerDist); + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + if (playerDist > 20480) + { + if (++actor[spriteNum].timetosleep > SLEEPTIME) + { + actor[spriteNum].timetosleep = 0; + changespritestat(spriteNum, STAT_ZOMBIEACTOR); + goto next_sprite; + } + } + + if (pData[0] == -5) // FROZEN + { + pData[3]++; + if (pData[3] > 280) + { + pSprite->pal = 0; + pData[0] = 0; + goto next_sprite; + } + A_Fall(spriteNum); + + pSprite->cstat = 257; + pSprite->picnum = GREENSLIME + 2; + pSprite->extra = 1; + pSprite->pal = 1; + + int const damageTile = A_IncurDamage(spriteNum); + if (damageTile >= 0) + { + if (damageTile == FREEZEBLAST) + goto next_sprite; + + P_AddKills(pPlayer, 1); + + for (bssize_t j = 16; j >= 0; --j) + { + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(); + int32_t newSprite = A_InsertSprite(SECT(spriteNum), SX(spriteNum), SY(spriteNum), SZ(spriteNum), + GLASSPIECES + (j % 3), -32, 36, 36, r3 & 2047, 32 + (r2 & 63), + 1024 - (r1 & 1023), spriteNum, 5); + sprite[newSprite].pal = 1; + } + + A_PlaySound(GLASS_BREAKING, spriteNum); + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else if (playerDist < 1024 && pPlayer->quick_kick == 0) + { + int const angDiff = G_GetAngleDelta(fix16_to_int(pPlayer->q16ang), getangle(SX(spriteNum) - pPlayer->pos.x, + SY(spriteNum) - pPlayer->pos.y)); + + if (angDiff > -128 && angDiff < 128) + pPlayer->quick_kick = 14; + } + + goto next_sprite; + } + + pSprite->cstat = (playerDist < 1596) ? 0 : 257; + + if (pData[0] == -4) //On the player + { + if (sprite[pPlayer->i].extra < 1) + { + pData[0] = 0; + goto next_sprite; + } + + setsprite(spriteNum,(vec3_t *)pSprite); + + pSprite->ang = fix16_to_int(pPlayer->q16ang); + + if ((TEST_SYNC_KEY(g_player[playerNum].input->bits, SK_FIRE) || (pPlayer->quick_kick > 0)) && sprite[pPlayer->i].extra > 0) + if (pPlayer->quick_kick > 0 || + (pPlayer->curr_weapon != HANDREMOTE_WEAPON && pPlayer->curr_weapon != HANDBOMB_WEAPON && + pPlayer->curr_weapon != TRIPBOMB_WEAPON && pPlayer->ammo_amount[pPlayer->curr_weapon] >= 0)) + { + for (bssize_t x = 0; x < 8; ++x) + { + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(), r4 = krand2(); + int const j + = A_InsertSprite(sectNum, pSprite->x, pSprite->y, pSprite->z - ZOFFSET3, SCRAP3 + (r4 & 3), -8, 48, 48, + r3 & 2047, (r2 & 63) + 64, -(r1 & 4095) - (pSprite->zvel >> 2), spriteNum, 5); + sprite[j].pal = 6; + } + + A_PlaySound(SLIM_DYING,spriteNum); + A_PlaySound(SQUISHED,spriteNum); + + if ((krand2()&255) < 32) + { + int const j = A_Spawn(spriteNum,BLOODPOOL); + sprite[j].pal = 0; + } + + P_AddKills(pPlayer, 1); + pData[0] = -3; + + if (pPlayer->somethingonplayer == spriteNum) + pPlayer->somethingonplayer = -1; + + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + + pSprite->z = pPlayer->pos.z + pPlayer->pyoff - pData[2] + ZOFFSET3 + (fix16_to_int(F16(100) - pPlayer->q16horiz) << 4); + + if (pData[2] > 512) + pData[2] -= 128; + + if (pData[2] < 348) + pData[2] += 128; + + if (pPlayer->newowner >= 0) + G_ClearCameraView(pPlayer); + + if (pData[3] > 0) + { + static const char slimeFrames[] = { 5, 5, 6, 6, 7, 7, 6, 5 }; + + pSprite->picnum = GREENSLIME + slimeFrames[pData[3]]; + + if (pData[3] == 5) + { + sprite[pPlayer->i].extra += -(5 + (krand2() & 3)); + A_PlaySound(SLIM_ATTACK, spriteNum); + } + + if (pData[3] < 7) + pData[3]++; + else + pData[3] = 0; + } + else + { + pSprite->picnum = GREENSLIME + 5; + if (rnd(32)) + pData[3] = 1; + } + + pSprite->xrepeat = 20 + (sintable[pData[1] & 2047] >> 13); + pSprite->yrepeat = 15 + (sintable[pData[1] & 2047] >> 13); + pSprite->x = pPlayer->pos.x + (sintable[(fix16_to_int(pPlayer->q16ang) + 512) & 2047] >> 7); + pSprite->y = pPlayer->pos.y + (sintable[fix16_to_int(pPlayer->q16ang) & 2047] >> 7); + + goto next_sprite; + } + + else if (pSprite->xvel < 64 && playerDist < 768) + { + if (pPlayer->somethingonplayer == -1) + { + pPlayer->somethingonplayer = spriteNum; + if (pData[0] == 3 || pData[0] == 2) // Falling downward + pData[2] = (12 << 8); + else + pData[2] = -(13 << 8); // Climbing up player + pData[0] = -4; + } + } + + int const damageTile = A_IncurDamage(spriteNum); + if (damageTile >= 0) + { + A_PlaySound(SLIM_DYING,spriteNum); + + P_AddKills(pPlayer, 1); + + if (pPlayer->somethingonplayer == spriteNum) + pPlayer->somethingonplayer = -1; + + if (damageTile == FREEZEBLAST) + { + A_PlaySound(SOMETHINGFROZE, spriteNum); + pData[0] = -5; + pData[3] = 0; + goto next_sprite; + } + + if ((krand2()&255) < 32) + { + int const j = A_Spawn(spriteNum,BLOODPOOL); + sprite[j].pal = 0; + } + + for (bssize_t x=0; x<8; x++) + { + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(), r4 = krand2(); + int const j = A_InsertSprite(sectNum, pSprite->x, pSprite->y, pSprite->z - ZOFFSET3, SCRAP3 + (r4 & 3), -8, + 48, 48, r3 & 2047, (r2 & 63) + 64, -(r1 & 4095) - (pSprite->zvel >> 2), + spriteNum, 5); + sprite[j].pal = 6; + } + pData[0] = -3; + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + // All weap + if (pData[0] == -1) //Shrinking down + { + A_Fall(spriteNum); + + pSprite->cstat &= 65535-8; + pSprite->picnum = GREENSLIME+4; + + // if(s->yrepeat > 62) + // A_DoGuts(s,JIBS6,5,myconnectindex); + + if (pSprite->xrepeat > 32) pSprite->xrepeat -= krand2()&7; + if (pSprite->yrepeat > 16) pSprite->yrepeat -= krand2()&7; + else + { + pSprite->xrepeat = 40; + pSprite->yrepeat = 16; + pData[5] = -1; + pData[0] = 0; + } + + goto next_sprite; + } + else if (pData[0] != -2) A_GetZLimits(spriteNum); + + if (pData[0] == -2) //On top of somebody + { + A_Fall(spriteNum); + sprite[pData[5]].xvel = 0; + + int const ang = sprite[pData[5]].ang; + pSprite->x = sprite[pData[5]].x + (sintable[(ang + 512) & 2047] >> 11); + pSprite->y = sprite[pData[5]].y + (sintable[ang & 2047] >> 11); + pSprite->z = sprite[pData[5]].z; + + pSprite->picnum = GREENSLIME + 2 + (g_globalRandom & 1); + + if (pSprite->yrepeat < 64) + pSprite->yrepeat += 2; + else + { + if (pSprite->xrepeat < 32) + pSprite->xrepeat += 4; + else + { + pData[0] = -1; + playerDist = ldist(pSprite, &sprite[pData[5]]); + + if (playerDist < 768) + sprite[pData[5]].xrepeat = 0; + } + } + + goto next_sprite; + } + + //Check randomly to see of there is an actor near + if (rnd(32)) + { + for (bssize_t SPRITES_OF_SECT(sectNum, j)) + { + if (A_CheckSpriteFlags(j, SFLAG_GREENSLIMEFOOD)) + { + if (ldist(pSprite, &sprite[j]) < 768 && (klabs(pSprite->z - sprite[j].z) < 8192)) // Gulp them + { + pData[5] = j; + pData[0] = -2; + pData[1] = 0; + goto next_sprite; + } + } + } + } + + //Moving on the ground or ceiling + + if (pData[0] == 0 || pData[0] == 2) + { + pSprite->picnum = GREENSLIME; + + if ((krand2()&511) == 0) + A_PlaySound(SLIM_ROAM,spriteNum); + + if (pData[0]==2) + { + pSprite->zvel = 0; + pSprite->cstat &= (65535-8); + + if ((sector[sectNum].ceilingstat&1) || (actor[spriteNum].ceilingz+6144) < pSprite->z) + { + pSprite->z += 2048; + pData[0] = 3; + goto next_sprite; + } + } + else + { + pSprite->cstat |= 8; + A_Fall(spriteNum); + } + + if (everyothertime&1) A_SetSprite(spriteNum,CLIPMASK0); + + if (pSprite->xvel > 96) + { + pSprite->xvel -= 2; + goto next_sprite; + } + else + { + if (pSprite->xvel < 32) pSprite->xvel += 4; + pSprite->xvel = 64 - (sintable[(pData[1]+512)&2047]>>9); + + pSprite->ang += G_GetAngleDelta(pSprite->ang, + getangle(pPlayer->pos.x-pSprite->x,pPlayer->pos.y-pSprite->y))>>3; + // TJR + } + + pSprite->xrepeat = 36 + (sintable[(pData[1]+512)&2047]>>11); + pSprite->yrepeat = 16 + (sintable[pData[1]&2047]>>13); + + if (rnd(4) && (sector[sectNum].ceilingstat&1) == 0 && + klabs(actor[spriteNum].floorz-actor[spriteNum].ceilingz) + < (192<<8)) + { + pSprite->zvel = 0; + pData[0]++; + } + + } + + if (pData[0]==1) + { + pSprite->picnum = GREENSLIME; + if (pSprite->yrepeat < 40) pSprite->yrepeat+=8; + if (pSprite->xrepeat > 8) pSprite->xrepeat-=4; + if (pSprite->zvel > -(2048+1024)) + pSprite->zvel -= 348; + pSprite->z += pSprite->zvel; + if (pSprite->z < actor[spriteNum].ceilingz+4096) + { + pSprite->z = actor[spriteNum].ceilingz+4096; + pSprite->xvel = 0; + pData[0] = 2; + } + } + + if (pData[0]==3) + { + pSprite->picnum = GREENSLIME+1; + + A_Fall(spriteNum); + + if (pSprite->z > actor[spriteNum].floorz-ZOFFSET3) + { + pSprite->yrepeat-=4; + pSprite->xrepeat+=2; + } + else + { + if (pSprite->yrepeat < (40-4)) pSprite->yrepeat+=8; + if (pSprite->xrepeat > 8) pSprite->xrepeat-=4; + } + + if (pSprite->z > actor[spriteNum].floorz-2048) + { + pSprite->z = actor[spriteNum].floorz-2048; + pData[0] = 0; + pSprite->xvel = 0; + } + } + goto next_sprite; + } + + case EMPTYBIKE__STATICRR: + if(!RRRA) break; + A_Fall(spriteNum); + A_GetZLimits(spriteNum); + if (sector[sectNum].lotag == ST_1_ABOVE_WATER) + { + vec3_t const pos = { pSprite->x, pSprite->y, actor[spriteNum].floorz + ZOFFSET2 }; + setsprite(spriteNum, &pos); + } + break; + + case EMPTYBOAT__STATICRR: + if (!RRRA) break; + A_Fall(spriteNum); + A_GetZLimits(spriteNum); + break; + + case TRIPBOMBSPRITE__STATIC: + if (!RR) break; + if (!RRRA || (sector[sectNum].lotag != ST_1_ABOVE_WATER && sector[sectNum].lotag != 160)) + if (pSprite->xvel) + { + vec3_t const vect = { + (pSprite->xvel*(sintable[(pSprite->ang + 512) & 2047])) >> 14, + (pSprite->xvel*(sintable[pSprite->ang & 2047])) >> 14, + pSprite->zvel + }; + + A_MoveSprite(spriteNum, &vect, CLIPMASK0); + pSprite->xvel--; + } + break; + + case BOUNCEMINE__STATIC: + if (RR) break; + fallthrough__; + case MORTER__STATIC: + if (!RR) + { + int const j = A_Spawn(spriteNum, FRAMEEFFECT1); + actor[j].t_data[0] = 3; + } + fallthrough__; + case HEAVYHBOMB__STATIC: + case CHEERBOMB__STATICRR: + { + int playerNum; + DukePlayer_t *pPlayer; + int detonatePlayer; + + if ((pSprite->cstat&32768)) + { + if (--pData[2] <= 0) + { + A_PlaySound(TELEPORTER, spriteNum); + A_Spawn(spriteNum, TRANSPORTERSTAR); + pSprite->cstat = 257; + } + goto next_sprite; + } + + int32_t playerDist; + playerNum = A_FindPlayer(pSprite, &playerDist); + pPlayer = g_player[playerNum].ps; + + if (playerDist < 1220) + pSprite->cstat &= ~257; + else + pSprite->cstat |= 257; + + if (pData[3] == 0) + { + if (A_IncurDamage(spriteNum) >= 0) + { + pData[3] = 1; + pData[4] = 0; + detonatePlayer = 0; + pSprite->xvel = 0; + goto DETONATEB; + } + } + + if (RR || pSprite->picnum != BOUNCEMINE) + { + A_Fall(spriteNum); + + if (sector[sectNum].lotag != ST_1_ABOVE_WATER && (!RRRA || sector[sectNum].lotag != 160) && pSprite->z >= actor[spriteNum].floorz-(ZOFFSET) && pSprite->yvel < 3) + { + if (pSprite->yvel > 0 || (pSprite->yvel == 0 && actor[spriteNum].floorz == sector[sectNum].floorz)) + { + if (RRRA && pSprite->picnum == CHEERBOMB) + { + pData[3] = 1; + pData[4] = 1; + detonatePlayer = 0; + goto DETONATEB; + } + else + A_PlaySound(PIPEBOMB_BOUNCE,spriteNum); + } + pSprite->zvel = -((4-pSprite->yvel)<<8); + if (sector[pSprite->sectnum].lotag == ST_2_UNDERWATER) + pSprite->zvel >>= 2; + pSprite->yvel++; + } + if (RR) + { + if ((!RRRA || pSprite->picnum != CHEERBOMB) && pSprite->z < actor[spriteNum].ceilingz+(16<<8) && sector[sectNum].lotag != ST_2_UNDERWATER ) + { + pSprite->z = actor[spriteNum].ceilingz+(16<<8); + pSprite->zvel = 0; + } + } + else + { + if (pSprite->z < actor[spriteNum].ceilingz) // && sector[sect].lotag != ST_2_UNDERWATER ) + { + pSprite->z = actor[spriteNum].ceilingz+(3<<8); + pSprite->zvel = 0; + } + } + } + + // can't initialize this because of the goto above + vec3_t tmpvect; + tmpvect.x = (pSprite->xvel * (sintable[(pSprite->ang + 512) & 2047])) >> 14; + tmpvect.y = (pSprite->xvel * (sintable[pSprite->ang & 2047])) >> 14; + tmpvect.z = pSprite->zvel; + + int moveSprite; + moveSprite = A_MoveSprite(spriteNum, &tmpvect, CLIPMASK0); + + //actor[spriteNum].movflag = moveSprite; + + if (sector[SECT(spriteNum)].lotag == ST_1_ABOVE_WATER && pSprite->zvel == 0) + { + pSprite->z += ZOFFSET5; + if (pData[5] == 0) + { + pData[5] = 1; + A_Spawn(spriteNum,WATERSPLASH2); + if (RRRA && pSprite->picnum == MORTER) + pSprite->xvel = 0; + } + } + else pData[5] = 0; + + if (pData[3] == 0 && ((!RR && pSprite->picnum == BOUNCEMINE) || pSprite->picnum == MORTER || (RRRA && pSprite->picnum == CHEERBOMB)) + && (moveSprite || playerDist < 844)) + { + pData[3] = 1; + pData[4] = 0; + detonatePlayer = 0; + pSprite->xvel = 0; + goto DETONATEB; + } + + if (sprite[pSprite->owner].picnum == APLAYER) + detonatePlayer = P_Get(pSprite->owner); + else detonatePlayer = -1; + + if (pSprite->xvel > 0) + { + pSprite->xvel -= 5; + if (sector[sectNum].lotag == ST_2_UNDERWATER) + pSprite->xvel -= 10; + + if (pSprite->xvel < 0) + pSprite->xvel = 0; + if (pSprite->xvel&8) pSprite->cstat ^= 4; + } + + if ((moveSprite&49152) == 32768) + { + vec3_t davect = *(vec3_t *)pSprite; + moveSprite &= (MAXWALLS - 1); + A_DamageWall(spriteNum, moveSprite, &davect, pSprite->picnum); + if (RRRA && pSprite->picnum == CHEERBOMB) + { + pData[3] = 1; + pData[4] = 0; + detonatePlayer = 0; + pSprite->xvel = 0; + goto DETONATEB; + } + Proj_BounceOffWall(pSprite, moveSprite); + pSprite->xvel >>= 1; + } + +DETONATEB: + if (!NAM_WW2GI) + bBoom = 0; + if ((detonatePlayer >= 0 && g_player[detonatePlayer].ps->hbomb_on == 0) || pData[3] == 1) + bBoom = 1; + if (NAM_WW2GI && pSprite->picnum == HEAVYHBOMB) + { + pSprite->extra--; + if (pSprite->extra <= 0) + bBoom = 1; + } + + if (bBoom) + { + pData[4]++; + + if (pData[4] == 2) + { + int const x = pSprite->extra; + int radius = 0; + + switch (DYNAMICTILEMAP(pSprite->picnum)) + { + case TRIPBOMBSPRITE__STATIC: if(RR) radius = g_tripbombRadius; break; + case HEAVYHBOMB__STATIC: radius = g_pipebombRadius; break; + case HBOMBAMMO__STATIC: if (RR) radius = g_pipebombRadius; break; + case MORTER__STATIC: radius = g_morterRadius; break; + case BOUNCEMINE__STATIC: if (!RR) radius = g_bouncemineRadius; break; + case CHEERBOMB__STATICRR: if (RRRA) radius = g_morterRadius; break; + } + + if (!RR || sector[pSprite->sectnum].lotag != 800) + { + A_RadiusDamage(spriteNum, radius, x >> 2, x >> 1, x - (x >> 2), x); + + int const j = A_Spawn(spriteNum, EXPLOSION2); + A_PlaySound(PIPEBOMB_EXPLODE, j); + + if (RRRA && pSprite->picnum == CHEERBOMB) + A_Spawn(spriteNum, BURNING); + + if (!RR && pSprite->zvel == 0) + A_Spawn(spriteNum,EXPLOSION2BOT); + + for (bssize_t x = 0; x < 8; ++x) + RANDOMSCRAP(pSprite, spriteNum); + } + } + + if (pSprite->yrepeat) + { + pSprite->yrepeat = 0; + goto next_sprite; + } + + if (pData[4] > 20) + { + if (RR || pSprite->owner != spriteNum || ud.respawn_items == 0) + { + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else + { + pData[4] = g_itemRespawnTime; + A_Spawn(spriteNum,RESPAWNMARKERRED); + pSprite->cstat = 32768; + pSprite->yrepeat = 9; + goto next_sprite; + } + } + if (RRRA && pSprite->picnum == CHEERBOMB) + { + A_Spawn(spriteNum, BURNING); + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + } + else if (pSprite->picnum == HEAVYHBOMB && playerDist < 788 && pData[0] > 7 && pSprite->xvel == 0) + { + if (cansee(pSprite->x, pSprite->y, pSprite->z - ZOFFSET3, pSprite->sectnum, + pPlayer->pos.x, pPlayer->pos.y, pPlayer->pos.z, pPlayer->cursectnum)) + { + if (pPlayer->ammo_amount[HANDBOMB_WEAPON] < pPlayer->max_ammo_amount[HANDBOMB_WEAPON] && (!RR || pSprite->pal == 0)) + { + if ((g_gametypeFlags[ud.coop] & GAMETYPE_WEAPSTAY) && (RR || pSprite->owner == spriteNum)) + { + for (bssize_t j = 0; j < pPlayer->weapreccnt; j++) + { + if (pPlayer->weaprecs[j] == (RR ? spriteNum : pSprite->picnum)) + goto next_sprite; + } + + if (pPlayer->weapreccnt < MAX_WEAPON_RECS-1) + pPlayer->weaprecs[pPlayer->weapreccnt++] = (RR ? spriteNum : pSprite->picnum); + } + + P_AddAmmo(pPlayer, HANDBOMB_WEAPON, 1); + if (RR) + P_AddAmmo(pPlayer, RPG_WEAPON, 1); + A_PlaySound(DUKE_GET, pPlayer->i); + + if ((pPlayer->gotweapon & (1<owner == pPlayer->i) + P_AddWeapon(pPlayer, HANDBOMB_WEAPON); + + if (sprite[pSprite->owner].picnum != APLAYER) + P_PalFrom(pPlayer, 32, 0, 32, 0); + + if ((RR && actor[pSprite->owner].picnum != HEAVYHBOMB) || (!RR && pSprite->owner != spriteNum) + || ud.respawn_items == 0) + { + if ((!RR || (pSprite->picnum == HEAVYHBOMB && sprite[pSprite->owner].picnum != APLAYER)) && (RR || pSprite->owner == spriteNum) && (g_gametypeFlags[ud.coop] & GAMETYPE_WEAPSTAY)) + goto next_sprite; + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else + { + pData[2] = g_itemRespawnTime; + A_Spawn(spriteNum, RESPAWNMARKERRED); + pSprite->cstat = 32768; + } + } + } + } + + if (pData[0] < 8) + pData[0]++; + + goto next_sprite; + } + + case REACTORBURNT__STATIC: + case REACTOR2BURNT__STATIC: + goto next_sprite; + + case REACTOR__STATIC: + case REACTOR2__STATIC: + { + if (pData[4] == 1) + { + for (bssize_t SPRITES_OF_SECT(sectNum, j)) + { + switch (DYNAMICTILEMAP(sprite[j].picnum)) + { + case SECTOREFFECTOR__STATIC: + if (sprite[j].lotag == 1) + { + sprite[j].lotag = 65535u; + sprite[j].hitag = 65535u; + } + break; + case REACTOR__STATIC: + sprite[j].picnum = REACTORBURNT; + break; + case REACTOR2__STATIC: + sprite[j].picnum = REACTOR2BURNT; + break; + case REACTORSPARK__STATIC: + case REACTOR2SPARK__STATIC: + sprite[j].cstat = 32768; + break; + } + } + + goto next_sprite; + } + + if (pData[1] >= 20) + { + pData[4] = 1; + goto next_sprite; + } + + int32_t playerDist; + int playerNum = A_FindPlayer(pSprite, &playerDist); + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + if (++pData[2] == 4) + pData[2] = 0; + + if (playerDist < 4096) + { + if ((krand2() & 255) < 16) + { + if (!A_CheckSoundPlaying(pPlayer->i, DUKE_LONGTERM_PAIN)) + A_PlaySound(DUKE_LONGTERM_PAIN, pPlayer->i); + + A_PlaySound(SHORT_CIRCUIT, spriteNum); + sprite[pPlayer->i].extra--; + P_PalFrom(pPlayer, 32, 32, 0, 0); + } + + pData[0] += 128; + + if (pData[3] == 0) + pData[3] = 1; + } + else pData[3] = 0; + + if (pData[1]) + { + pData[1]++; + pData[4] = pSprite->z; + pSprite->z = sector[sectNum].floorz - (krand2() % (sector[sectNum].floorz - sector[sectNum].ceilingz)); + + switch (pData[1]) + { + case 3: + // Turn on all of those flashing sectoreffector. + A_RadiusDamage(spriteNum, 4096, g_impactDamage << 2, g_impactDamage << 2, g_impactDamage << 2, g_impactDamage << 2); + + for (bssize_t SPRITES_OF(STAT_STANDABLE, j)) + { + if (sprite[j].picnum == MASTERSWITCH && sprite[j].hitag == pSprite->hitag && sprite[j].yvel == 0) + sprite[j].yvel = 1; + } + break; + + case 4: + case 7: + case 10: + case 15: + for (bssize_t SPRITES_OF_SECT(sectNum, j)) + { + if (j != spriteNum) + { + A_DeleteSprite(j); + break; + } + } + + break; + } + + for (bssize_t x = 0; x < 16; x++) + RANDOMSCRAP(pSprite, spriteNum); + + pSprite->z = pData[4]; + pData[4] = 0; + } + else if (A_IncurDamage(spriteNum) >= 0) + { + for (bssize_t x = 0; x < 32; x++) + RANDOMSCRAP(pSprite, spriteNum); + + if (pSprite->extra < 0) + pData[1] = 1; + } + goto next_sprite; + } + + case CAMERA1__STATIC: + if (pData[0] == 0) + { + pData[1]+=8; + if (g_damageCameras) + { + if (A_IncurDamage(spriteNum) >= 0) + { + pData[0] = 1; // static + pSprite->cstat = 32768; + + for (bssize_t x = 0; x < 5; x++) + RANDOMSCRAP(pSprite, spriteNum); + + goto next_sprite; + } + } + + if (pSprite->hitag > 0) + { + if (pData[1] < pSprite->hitag) pSprite->ang += 8; + else if (pData[1] < pSprite->hitag * 3) pSprite->ang -= 8; + else if (pData[1] < (pSprite->hitag << 2)) pSprite->ang += 8; + else + { + pData[1] = 8; + pSprite->ang += 16; + } + } + } + goto next_sprite; + } + + if (!g_netServer && ud.multimode < 2 && A_CheckEnemySprite(pSprite)) + { + if (g_noEnemies == 1) + { + pSprite->cstat = 32768; + goto next_sprite; + } + else if (g_noEnemies == 2) + { + pSprite->cstat = 257; + } + } + + if (G_HaveActor(sprite[spriteNum].picnum)) + { + int32_t playerDist; + int playerNum = A_FindPlayer(pSprite, &playerDist); + A_Execute(spriteNum, playerNum, playerDist); + } + if (deleteAfterExecute) + A_DeleteSprite(spriteNum); +next_sprite: + spriteNum = nextSprite; + } +} + +ACTOR_STATIC void G_MoveMisc(void) // STATNUM 5 +{ + int spriteNum = headspritestat[STAT_MISC]; + + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + int32_t playerDist; + int32_t *const pData = actor[spriteNum].t_data; + spritetype *const pSprite = &sprite[spriteNum]; + int sectNum = pSprite->sectnum; // XXX: not const + int switchPic; + + if (sectNum < 0 || pSprite->xrepeat == 0) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + Bmemcpy(&actor[spriteNum].bpos, pSprite, sizeof(vec3_t)); + + switchPic = pSprite->picnum; + + if (!RR && pSprite->picnum > NUKEBUTTON && pSprite->picnum <= NUKEBUTTON+3) + switchPic = NUKEBUTTON; + + if (pSprite->picnum > GLASSPIECES && pSprite->picnum <= GLASSPIECES+2) + switchPic = GLASSPIECES; + + if (pSprite->picnum == INNERJAW+1) + switchPic--; + + if ((pSprite->picnum == MONEY+1) || (!RR && (pSprite->picnum == MAIL+1 || pSprite->picnum == PAPER+1))) + { + actor[spriteNum].floorz = pSprite->z = getflorzofslope(pSprite->sectnum,pSprite->x,pSprite->y); + if (RR && sector[pSprite->sectnum].lotag == 800) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else switch (DYNAMICTILEMAP(switchPic)) + { + //case APLAYER__STATIC: pSprite->cstat = 32768; goto next_sprite; + + case SHOTGUNSPRITE__STATIC: + if (!RR) break; + if (sector[pSprite->sectnum].lotag == 800 && pSprite->z >= sector[pSprite->sectnum].floorz - ZOFFSET3) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + break; + + case NEON1__STATIC: + case NEON2__STATIC: + case NEON3__STATIC: + case NEON4__STATIC: + case NEON5__STATIC: + case NEON6__STATIC: + pSprite->shade = ((tabledivide32_noinline(g_globalRandom, pSprite->lotag + 1) & 31) > 4) ? -127 : 127; + goto next_sprite; + + case BLOODSPLAT1__STATIC: + case BLOODSPLAT2__STATIC: + case BLOODSPLAT3__STATIC: + case BLOODSPLAT4__STATIC: + if (pData[0] == 7 * GAMETICSPERSEC) + goto next_sprite; + + pSprite->z += 16 + (krand2() & 15); + + if ((++pData[0] % 9) == 0) + pSprite->yrepeat++; + + + goto next_sprite; + + case NUKEBUTTON__STATIC: + // case NUKEBUTTON+1: + // case NUKEBUTTON+2: + // case NUKEBUTTON+3: + + if (RR) break; + + if (pData[0]) + { + pData[0]++; + if (pData[0] == 8) + pSprite->picnum = NUKEBUTTON + 1; + else if (pData[0] == 16) + { + pSprite->picnum = NUKEBUTTON + 2; + g_player[P_Get(pSprite->owner)].ps->fist_incs = 1; + } + if (g_player[P_Get(pSprite->owner)].ps->fist_incs == GAMETICSPERSEC) + pSprite->picnum = NUKEBUTTON + 3; + } + goto next_sprite; + + case FORCESPHERE__STATIC: + { + int forceRepeat = pSprite->xrepeat; + if (pData[1] > 0) + { + pData[1]--; + if (pData[1] == 0) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + if (actor[pSprite->owner].t_data[1] == 0) + { + if (pData[0] < 64) + { + pData[0]++; + forceRepeat += 3; + } + } + else if (pData[0] > 64) + { + pData[0]--; + forceRepeat -= 3; + } + + *(vec3_t *)pSprite = *(vec3_t *)&sprite[pSprite->owner]; + pSprite->ang += actor[pSprite->owner].t_data[0]; + + forceRepeat = clamp2(forceRepeat, 1, 64); + pSprite->xrepeat = forceRepeat; + pSprite->yrepeat = forceRepeat; + pSprite->shade = (forceRepeat >> 1) - 48; + + for (bsize_t j = pData[0]; j > 0; j--) + A_SetSprite(spriteNum, CLIPMASK0); + goto next_sprite; + } + + case MUD__STATICRR: + pData[0]++; + if (pData[0] == 1) + { + if (sector[sectNum].floorpicnum != RRTILE3073) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + if (!S_CheckSoundPlaying(spriteNum,ITEM_SPLASH)) + A_PlaySound(ITEM_SPLASH,spriteNum); + } + if (pData[0] == 3) + { + pData[0] = 0; + pData[1]++; // WATERSPLASH_T2 + } + if (pData[1] == 5) + A_DeleteSprite(spriteNum); + goto next_sprite; + + case WATERSPLASH2__STATIC: + pData[0]++; + if (pData[0] == 1) + { + if (sector[sectNum].lotag != ST_1_ABOVE_WATER && sector[sectNum].lotag != ST_2_UNDERWATER) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + /* + else + { + l = getflorzofslope(sect,s->x,s->y)-s->z; + if( l > ZOFFSET2 ) KILLIT(i); + } + else + */ + if (!S_CheckSoundPlaying(spriteNum,ITEM_SPLASH)) + A_PlaySound(ITEM_SPLASH,spriteNum); + } + if (pData[0] == 3) + { + pData[0] = 0; + pData[1]++; // WATERSPLASH_T2 + } + if (pData[1] == 5) + A_DeleteSprite(spriteNum); + goto next_sprite; + case FRAMEEFFECT1__STATIC: + + if (pSprite->owner >= 0) + { + pData[0]++; + + if (pData[0] > 7) + { + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else if (pData[0] > 4) + pSprite->cstat |= 512 + 2; + else if (pData[0] > 2) + pSprite->cstat |= 2; + pSprite->xoffset = sprite[pSprite->owner].xoffset; + pSprite->yoffset = sprite[pSprite->owner].yoffset; + } + goto next_sprite; + case INNERJAW__STATIC: + { + // case INNERJAW+1: + int32_t playerDist, playerNum = A_FindPlayer(pSprite,&playerDist); + + if (playerDist < 512) + { + P_PalFrom(g_player[playerNum].ps, 32, 32,0,0); + sprite[g_player[playerNum].ps->i].extra -= 4; + } + } + fallthrough__; + case COOLEXPLOSION1__STATIC: + if (!RR && switchPic == COOLEXPLOSION1) + break; + fallthrough__; + case OWHIP__STATICRR: + case UWHIP__STATICRR: + case FIRELASER__STATIC: + if (pSprite->extra != 999) + pSprite->extra = 999; + else DELETE_SPRITE_AND_CONTINUE(spriteNum); + break; + case TONGUE__STATIC: + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + case MONEY__STATIC: + case MAIL__STATIC: + case PAPER__STATIC: + { + if (RR && (switchPic == MAIL || switchPic == PAPER)) + break; + pSprite->xvel = (krand2()&7)+(sintable[T1(spriteNum)&2047]>>9); + T1(spriteNum) += (krand2()&63); + if ((T1(spriteNum)&2047) > 512 && (T1(spriteNum)&2047) < 1596) + { + if (sector[sectNum].lotag == ST_2_UNDERWATER) + { + if (pSprite->zvel < 64) + pSprite->zvel += (g_spriteGravity>>5)+(krand2()&7); + } + else if (pSprite->zvel < 144) + pSprite->zvel += (g_spriteGravity>>5)+(krand2()&7); + } + + A_SetSprite(spriteNum, CLIPMASK0); + + if ((krand2()&3) == 0) + setsprite(spriteNum, (vec3_t *) pSprite); + + if (pSprite->sectnum == -1) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + int const floorZ = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y); + + if (pSprite->z > floorZ) + { + pSprite->z = floorZ; + A_AddToDeleteQueue(spriteNum); + PN(spriteNum)++; + + for (bssize_t SPRITES_OF(STAT_MISC, j)) + { + if (sprite[j].picnum == BLOODPOOL && ldist(pSprite, &sprite[j]) < 348) + { + pSprite->pal = 2; + break; + } + } + } + + + if (RR && sector[pSprite->sectnum].lotag == 800 && pSprite->z >= sector[pSprite->sectnum].floorz - ZOFFSET3) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + break; + } + + case HEADJIB1__STATIC: + case ARMJIB1__STATIC: + case LEGJIB1__STATIC: + case LIZMANHEAD1__STATIC: + case LIZMANARM1__STATIC: + case LIZMANLEG1__STATIC: + if (RR) break; + goto jib_code; + case RRTILE2460__STATICRR: + case RRTILE2465__STATICRR: + case BIKEJIBA__STATICRR: + case BIKEJIBB__STATICRR: + case BIKEJIBC__STATICRR: + case BIKERJIBA__STATICRR: + case BIKERJIBB__STATICRR: + case BIKERJIBC__STATICRR: + case BIKERJIBD__STATICRR: + case CHEERJIBA__STATICRR: + case CHEERJIBB__STATICRR: + case CHEERJIBC__STATICRR: + case CHEERJIBD__STATICRR: + case FBOATJIBA__STATICRR: + case FBOATJIBB__STATICRR: + case RABBITJIBA__STATICRR: + case RABBITJIBB__STATICRR: + case RABBITJIBC__STATICRR: + case MAMAJIBA__STATICRR: + case MAMAJIBB__STATICRR: + if (!RRRA) break; + goto jib_code; + case JIBS1__STATIC: + case JIBS2__STATIC: + case JIBS3__STATIC: + case JIBS4__STATIC: + case JIBS5__STATIC: + case JIBS6__STATIC: + case DUKETORSO__STATIC: + case DUKEGUN__STATIC: + case DUKELEG__STATIC: + case BILLYJIBA__STATICRR: + case BILLYJIBB__STATICRR: + case HULKJIBA__STATICRR: + case HULKJIBB__STATICRR: + case HULKJIBC__STATICRR: + case MINJIBA__STATICRR: + case MINJIBB__STATICRR: + case MINJIBC__STATICRR: + case COOTJIBA__STATICRR: + case COOTJIBB__STATICRR: + case COOTJIBC__STATICRR: +jib_code: + { + pSprite->xvel = (pSprite->xvel > 0) ? pSprite->xvel - 1 : 0; + + if (!RR) + { + if (pData[5] < (30*10)) + pData[5]++; + else + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + + if (pSprite->zvel > 1024 && pSprite->zvel < 1280) + { + setsprite(spriteNum, (vec3_t *) pSprite); + sectNum = pSprite->sectnum; + } + + if (RR) + setsprite(spriteNum, (vec3_t * ) pSprite); + + int32_t floorZ, ceilZ; + getzsofslope(sectNum, pSprite->x, pSprite->y, &ceilZ, &floorZ); + + if (ceilZ == floorZ || sectNum < 0 || sectNum >= MAXSECTORS) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + if (pSprite->z < floorZ-(2<<8)) + { + if (pData[1] < 2) pData[1]++; + else if (sector[sectNum].lotag != ST_2_UNDERWATER) + { + pData[1] = 0; + + if (pSprite->picnum == DUKELEG || pSprite->picnum == DUKETORSO || pSprite->picnum == DUKEGUN) + { + pData[0] = (pData[0] > 6) ? 0 : pData[0] + 1; + } + else + { + pData[0] = (pData[0] > 2) ? 0 : pData[0] + 1; + } + } + + if (pSprite->zvel < 6144) + { + if (sector[sectNum].lotag == ST_2_UNDERWATER) + { + if (pSprite->zvel < 1024) + pSprite->zvel += 48; + else pSprite->zvel = 1024; + } + else pSprite->zvel += g_spriteGravity-50; + } + + pSprite->x += (pSprite->xvel*sintable[(pSprite->ang+512)&2047])>>14; + pSprite->y += (pSprite->xvel*sintable[pSprite->ang&2047])>>14; + pSprite->z += pSprite->zvel; + + if (RR && pSprite->z >= sector[pSprite->sectnum].floorz) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else + { + if (RRRA || (pSprite->picnum == RRTILE2465 || pSprite->picnum == RRTILE2560)) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + if (pData[2] == 0) + { + if (pSprite->sectnum == -1) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + if ((sector[pSprite->sectnum].floorstat&2)) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + pData[2]++; + } + + floorZ = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y); + pSprite->z = floorZ - (2 << 8); + pSprite->xvel = 0; + + if (pSprite->picnum == JIBS6) + { + pData[1]++; + + if ((pData[1]&3) == 0 && pData[0] < 7) + pData[0]++; + + if (pData[1] > 20) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else + { + pSprite->picnum = JIBS6; + pData[0] = 0; + pData[1] = 0; + } + } + + if (RR && sector[pSprite->sectnum].lotag == 800 && pSprite->z >= sector[pSprite->sectnum].floorz - ZOFFSET3) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + goto next_sprite; + } + + case PUKE__STATIC: + if (RR) break; + fallthrough__; + case BLOODPOOL__STATIC: + { + if (pData[0] == 0) + { + pData[0] = 1; + if (sector[sectNum].floorstat&2) + { + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else A_AddToDeleteQueue(spriteNum); + } + + A_Fall(spriteNum); + + int32_t playerDist; + int const playerNum = A_FindPlayer(pSprite, &playerDist); + pSprite->z = actor[spriteNum].floorz - ZOFFSET; + + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + if (pData[2] < 32) + { + pData[2]++; + + if (actor[spriteNum].picnum == TIRE) + { + if (pSprite->xrepeat < 64 && pSprite->yrepeat < 64) + { + pSprite->xrepeat += krand2()&3; + pSprite->yrepeat += krand2()&3; + } + } + else + { + if (pSprite->xrepeat < 32 && pSprite->yrepeat < 32) + { + pSprite->xrepeat += krand2()&3; + pSprite->yrepeat += krand2()&3; + } + } + } + + if (playerDist < 844 && pSprite->xrepeat > 6 && pSprite->yrepeat > 6) + { + if (pSprite->pal == 0 && (krand2()&255) < 16 && (RR || pSprite->picnum != PUKE)) + { + if (pPlayer->inv_amount[GET_BOOTS] > 0) + pPlayer->inv_amount[GET_BOOTS]--; + else + { + if (!A_CheckSoundPlaying(pPlayer->i,DUKE_LONGTERM_PAIN)) + A_PlaySound(DUKE_LONGTERM_PAIN,pPlayer->i); + + sprite[pPlayer->i].extra --; + + P_PalFrom(pPlayer, 32, 16,0,0); + } + } + + if (pData[1] == 1) goto next_sprite; + + pData[1] = 1; + + pPlayer->footprintcount = (actor[spriteNum].picnum == TIRE) ? 10 : 3; + pPlayer->footprintpal = pSprite->pal; + pPlayer->footprintshade = pSprite->shade; + + if (pData[2] == 32) + { + pSprite->xrepeat -= 6; + pSprite->yrepeat -= 6; + } + } + else pData[1] = 0; + + if (RR && sector[pSprite->sectnum].lotag == 800 && pSprite->z >= sector[pSprite->sectnum].floorz - ZOFFSET3) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + goto next_sprite; + } + + case BURNING2__STATIC: + case FECES__STATIC: + case SHRINKEREXPLOSION__STATIC: + case EXPLOSION2BOT__STATIC: + case LASERSITE__STATIC: + if (RR) break; + fallthrough__; + case BURNING__STATIC: + case WATERBUBBLE__STATIC: + case SMALLSMOKE__STATIC: + case EXPLOSION2__STATIC: + case EXPLOSION3__STATICRR: + case BLOOD__STATIC: + case FORCERIPPLE__STATIC: + case TRANSPORTERSTAR__STATIC: + case TRANSPORTERBEAM__STATIC: + { + if (!G_HaveActor(sprite[spriteNum].picnum)) + goto next_sprite; + int const playerNum = A_FindPlayer(pSprite, &playerDist); + A_Execute(spriteNum, playerNum, playerDist); + goto next_sprite; + } + + + case SHELL__STATIC: + case SHOTGUNSHELL__STATIC: + + A_SetSprite(spriteNum,CLIPMASK0); + + if (sectNum < 0 || (!RR && (sector[sectNum].floorz + (24<<8)) < pSprite->z)) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + if (sector[sectNum].lotag == ST_2_UNDERWATER) + { + pData[1]++; + if (pData[1] > 8) + { + pData[1] = 0; + pData[0]++; + pData[0] &= 3; + } + if (pSprite->zvel < 128) pSprite->zvel += (g_spriteGravity/13); // 8 + else pSprite->zvel -= 64; + if (pSprite->xvel > 0) + pSprite->xvel -= 4; + else pSprite->xvel = 0; + } + else + { + pData[1]++; + if (pData[1] > 3) + { + pData[1] = 0; + pData[0]++; + pData[0] &= 3; + } + if (pSprite->zvel < 512) pSprite->zvel += (g_spriteGravity/3); // 52; + if (pSprite->xvel > 0) + pSprite->xvel --; + else + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + + goto next_sprite; + + case GLASSPIECES__STATIC: + case POPCORN__STATICRR: + // case GLASSPIECES+1: + // case GLASSPIECES+2: + + A_Fall(spriteNum); + + if (pSprite->zvel > 4096) pSprite->zvel = 4096; + if (sectNum < 0) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + if (pSprite->z == actor[spriteNum].floorz-(ZOFFSET) && pData[0] < 3) + { + pSprite->zvel = -((3-pData[0])<<8)-(krand2()&511); + if (sector[sectNum].lotag == ST_2_UNDERWATER) + pSprite->zvel >>= 1; + pSprite->xrepeat >>= 1; + pSprite->yrepeat >>= 1; + if (rnd(96)) + setsprite(spriteNum,(vec3_t *)pSprite); + pData[0]++;//Number of bounces + } + else if (pData[0] == 3) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + if (pSprite->xvel > 0) + { + pSprite->xvel -= 2; + pSprite->cstat = ((pSprite->xvel&3)<<2); + } + else pSprite->xvel = 0; + + A_SetSprite(spriteNum,CLIPMASK0); + + goto next_sprite; + } + + if (PN(spriteNum) >= SCRAP6 && PN(spriteNum) <= SCRAP5+3) + { + if (pSprite->xvel > 0) + pSprite->xvel--; + else pSprite->xvel = 0; + + if (pSprite->zvel > 1024 && pSprite->zvel < 1280) + { + setsprite(spriteNum,(vec3_t *)pSprite); + sectNum = pSprite->sectnum; + } + + if (pSprite->z < sector[sectNum].floorz-(2<<8)) + { + if (pData[1] < 1) pData[1]++; + else + { + pData[1] = 0; + + if (pSprite->picnum < SCRAP6 + 8) + pData[0] = (pData[0] > 6) ? 0 : pData[0] + 1; + else + pData[0] = (pData[0] > 2) ? 0 : pData[0] + 1; + } + if (pSprite->zvel < 4096) + pSprite->zvel += g_spriteGravity - 50; + pSprite->x += (pSprite->xvel*sintable[(pSprite->ang+512)&2047])>>14; + pSprite->y += (pSprite->xvel*sintable[pSprite->ang&2047])>>14; + pSprite->z += pSprite->zvel; + } + else + { + if (pSprite->picnum == SCRAP1 && pSprite->yvel > 0 && pSprite->yvel < MAXUSERTILES) + { + int32_t j = A_Spawn(spriteNum, pSprite->yvel); + + setsprite(j,(vec3_t *)pSprite); + A_GetZLimits(j); + sprite[j].hitag = sprite[j].lotag = 0; + } + + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + goto next_sprite; + } + +next_sprite: + spriteNum = nextSprite; + } +} + + +// i: SE spritenum +static void HandleSE31(int spriteNum, int setFloorZ, int spriteZ, int SEdir, int zDifference) +{ + const spritetype *pSprite = &sprite[spriteNum]; + sectortype *const pSector = §or[sprite[spriteNum].sectnum]; + int32_t *const pData = actor[spriteNum].t_data; + + if (klabs(pSector->floorz - spriteZ) < SP(spriteNum)) + { + if (setFloorZ) + pSector->floorz = spriteZ; + + pData[2] = SEdir; + pData[0] = 0; + if (!RR) + pData[3] = pSprite->hitag; + + A_CallSound(pSprite->sectnum, spriteNum); + } + else + { + int const zChange = ksgn(zDifference) * SP(spriteNum); + + pSector->floorz += zChange; + + for (bssize_t SPRITES_OF_SECT(pSprite->sectnum, j)) + { + if (sprite[j].picnum == APLAYER && sprite[j].owner >= 0) + { + int const playerNum = P_Get(j); + + if (g_player[playerNum].ps->on_ground == 1) + g_player[playerNum].ps->pos.z += zChange; + } + + if (sprite[j].zvel == 0 && sprite[j].statnum != STAT_EFFECTOR && (RR || sprite[j].statnum != STAT_PROJECTILE)) + { + sprite[j].z += zChange; + actor[j].bpos.z = sprite[j].z; + actor[j].floorz = pSector->floorz; + } + } + } +} + +// s: SE sprite +static void MaybeTrainKillPlayer(const spritetype *pSprite, int const setOPos) +{ + for (bssize_t TRAVERSE_CONNECT(playerNum)) + { + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + if (sprite[pPlayer->i].extra > 0) + { + int16_t playerSectnum = pPlayer->cursectnum; + + updatesector(pPlayer->pos.x, pPlayer->pos.y, &playerSectnum); + + if ((playerSectnum == -1 && !ud.noclip) || (pPlayer->cursectnum != pSprite->sectnum && playerSectnum == pSprite->sectnum)) + { + *(vec2_t *)pPlayer = *(vec2_t const *)pSprite; + + if (setOPos) + *(vec2_t *)&pPlayer->opos = *(vec2_t *)pPlayer; + + pPlayer->cursectnum = pSprite->sectnum; + + setsprite(pPlayer->i, (vec3_t const *)pSprite); + P_QuickKill(pPlayer); + } + } + } +} + +// i: SE spritenum +static void MaybeTrainKillEnemies(int const spriteNum, int const gutSpawnCnt) +{ + int findSprite = headspritesect[sprite[OW(spriteNum)].sectnum]; + + do + { + int const nextSprite = nextspritesect[findSprite]; + + if (sprite[findSprite].statnum == STAT_ACTOR && A_CheckEnemySprite(&sprite[findSprite])) + { + int16_t sectNum = sprite[findSprite].sectnum; + + updatesector(sprite[findSprite].x,sprite[findSprite].y,§Num); + + if (sprite[findSprite].extra >= 0 && sectNum == sprite[spriteNum].sectnum) + { + A_DoGutsDir(findSprite, JIBS6, gutSpawnCnt); + A_PlaySound(SQUISHED, findSprite); + A_DeleteSprite(findSprite); + } + } + + findSprite = nextSprite; + } + while (findSprite >= 0); +} + +ACTOR_STATIC void G_MoveEffectors(void) //STATNUM 3 +{ + int32_t q = 0, j, k, l, m, x; + int spriteNum = headspritestat[STAT_EFFECTOR]; + + for (native_t TRAVERSE_CONNECT(playerNum)) + { + vec2_t & fric = g_player[playerNum].ps->fric; + fric.x = fric.y = 0; + } + + while (spriteNum >= 0) + { + int const nextSprite = nextspritestat[spriteNum]; + spritetype *const pSprite = &sprite[spriteNum]; + int32_t playerDist; + int playerNum = A_FindPlayer(pSprite, &playerDist); + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + sectortype *const pSector = §or[pSprite->sectnum]; + int const spriteLotag = pSprite->lotag; + int const spriteHitag = pSprite->hitag; + int32_t *const pData = &actor[spriteNum].t_data[0]; + + switch (spriteLotag) + { + case SE_0_ROTATING_SECTOR: + { + int32_t zchange = 0; + + j = pSprite->owner; + + if ((uint16_t)sprite[j].lotag == UINT16_MAX) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + q = pSector->extra>>3; + l = 0; + + if (pSector->lotag == ST_30_ROTATE_RISE_BRIDGE) + { + q >>= 2; + + if (sprite[spriteNum].extra == 1) + { + if (actor[spriteNum].tempang < 256) + { + actor[spriteNum].tempang += 4; + if (actor[spriteNum].tempang >= 256) + A_CallSound(pSprite->sectnum,spriteNum); + if (pSprite->clipdist) l = 1; + else l = -1; + } + else actor[spriteNum].tempang = 256; + + if (pSector->floorz > pSprite->z) //z's are touching + { + pSector->floorz -= 512; + zchange = -512; + if (pSector->floorz < pSprite->z) + pSector->floorz = pSprite->z; + } + else if (pSector->floorz < pSprite->z) //z's are touching + { + pSector->floorz += 512; + zchange = 512; + if (pSector->floorz > pSprite->z) + pSector->floorz = pSprite->z; + } + } + else if (sprite[spriteNum].extra == 3) + { + if (actor[spriteNum].tempang > 0) + { + actor[spriteNum].tempang -= 4; + if (actor[spriteNum].tempang <= 0) + A_CallSound(pSprite->sectnum,spriteNum); + if (pSprite->clipdist) l = -1; + else l = 1; + } + else actor[spriteNum].tempang = 0; + + if (pSector->floorz > T4(spriteNum)) //z's are touching + { + pSector->floorz -= 512; + zchange = -512; + if (pSector->floorz < T4(spriteNum)) + pSector->floorz = T4(spriteNum); + } + else if (pSector->floorz < T4(spriteNum)) //z's are touching + { + pSector->floorz += 512; + zchange = 512; + if (pSector->floorz > T4(spriteNum)) + pSector->floorz = T4(spriteNum); + } + } + } + else + { + if (actor[j].t_data[0] == 0) break; + if (actor[j].t_data[0] == 2) DELETE_SPRITE_AND_CONTINUE(spriteNum); + + l = (sprite[j].ang > 1024) ? -1 : 1; + + if (pData[3] == 0) + pData[3] = ldist(pSprite,&sprite[j]); + pSprite->xvel = pData[3]; + pSprite->x = sprite[j].x; + pSprite->y = sprite[j].y; + } + + pSprite->ang += (l*q); + pData[2] += (l*q); + + if (l && (pSector->floorstat&64)) + { + for (TRAVERSE_CONNECT(playerNum)) + { + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + if (pPlayer->cursectnum == pSprite->sectnum && pPlayer->on_ground == 1) + { + pPlayer->q16ang += fix16_from_int(l*q); + pPlayer->q16ang &= 0x7FFFFFF; + + pPlayer->pos.z += zchange; + + vec2_t r; + rotatepoint(*(vec2_t *)&sprite[j],*(vec2_t *)&pPlayer->pos,(q*l),&r); + + pPlayer->bobpos.x += r.x-pPlayer->pos.x; + pPlayer->bobpos.y += r.y-pPlayer->pos.y; + + *(vec2_t *)&pPlayer->pos = r; + + if (sprite[pPlayer->i].extra <= 0) + *(vec2_t *)&sprite[pPlayer->i] = r; + } + } + + for (bssize_t SPRITES_OF_SECT(pSprite->sectnum, p)) + { + // KEEPINSYNC1 + if (sprite[p].statnum != STAT_EFFECTOR && sprite[p].statnum != STAT_PROJECTILE) + if (RR || sprite[p].picnum != LASERLINE) + { + if (sprite[p].picnum == APLAYER && sprite[p].owner >= 0) + continue; + + sprite[p].ang += (l*q); + sprite[p].ang &= 2047; + + sprite[p].z += zchange; + + rotatepoint(*(vec2_t *)&sprite[j], *(vec2_t *)&sprite[p], (q * l), (vec2_t *)&sprite[p].x); + } + } + + } + + A_MoveSector(spriteNum); + } + break; + + case SE_1_PIVOT: //Nothing for now used as the pivot + if (pSprite->owner == -1) //Init + { + pSprite->owner = spriteNum; + + for (SPRITES_OF(STAT_EFFECTOR, j)) + { + if (sprite[j].lotag == SE_19_EXPLOSION_LOWERS_CEILING && sprite[j].hitag == spriteHitag) + { + pData[0] = 0; + break; + } + } + } + break; + + case SE_6_SUBWAY: + k = pSector->extra; + + if (pData[4] > 0) + { + pData[4]--; + if (pData[4] >= (k-(k>>3))) + pSprite->xvel -= (k>>5); + if (pData[4] > ((k>>1)-1) && pData[4] < (k-(k>>3))) + pSprite->xvel = 0; + if (pData[4] < (k>>1)) + pSprite->xvel += (k>>5); + if (pData[4] < ((k>>1)-(k>>3))) + { + pData[4] = 0; + pSprite->xvel = k; + if (RR && (!RRRA || g_lastLevel) && g_hulkSpawn) + { + g_hulkSpawn--; + int newSprite = A_Spawn(spriteNum, HULK); + sprite[newSprite].z = sector[sprite[newSprite].sectnum].ceilingz; + sprite[newSprite].pal = 33; + if (!g_hulkSpawn) + { + newSprite = A_InsertSprite(pSprite->sectnum, pSprite->x, pSprite->y, + sector[pSprite->sectnum].ceilingz + 119428, RRTILE3677, -8, 16, 16, 0, 0, 0, spriteNum, STAT_MISC); + sprite[newSprite].cstat = 514; + sprite[newSprite].pal = 7; + sprite[newSprite].xrepeat = 80; + sprite[newSprite].yrepeat = 255; + newSprite = A_Spawn(spriteNum, RRTILE296); + sprite[newSprite].cstat = 0; + sprite[newSprite].cstat |= 32768; + sprite[newSprite].z = sector[pSprite->sectnum].floorz - 6144; + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + } + } + } + else + { + pSprite->xvel = k; + if (RR) + { + int otherSprite = headspritesect[pSprite->sectnum]; + while (otherSprite >= 0) + { + int const nextOtherSprite = nextspritesect[otherSprite]; + if (sprite[otherSprite].picnum == UFOBEAM) + if (g_ufoSpawn) + if (++g_ufoCnt == 64) + { + g_ufoCnt = 0; + g_ufoSpawn--; + int ufoTile = UFO1; + switch (krand2()&3) + { + case 0: + ufoTile = UFO1; + break; + case 1: + ufoTile = UFO2; + break; + case 2: + ufoTile = UFO3; + break; + case 3: + ufoTile = UFO4; + break; + } + if (RRRA) + ufoTile = UFO1; + int const newSprite = A_Spawn(spriteNum, ufoTile); + sprite[newSprite].z = sector[sprite[newSprite].sectnum].ceilingz; + } + otherSprite = nextOtherSprite; + } + } + } + + for (SPRITES_OF(STAT_EFFECTOR, j)) + { + if (sprite[j].lotag == SE_14_SUBWAY_CAR && spriteHitag == sprite[j].hitag && actor[j].t_data[0] == pData[0]) + { + sprite[j].xvel = pSprite->xvel; + // if( t[4] == 1 ) + { + if (actor[j].t_data[5] == 0) + actor[j].t_data[5] = dist(&sprite[j],pSprite); + x = ksgn(dist(&sprite[j],pSprite)-actor[j].t_data[5]); + if (sprite[j].extra) + x = -x; + pSprite->xvel += x; + } + actor[j].t_data[4] = pData[4]; + } + } + x = 0; // XXX: This assignment is dead? + fallthrough__; + + case SE_14_SUBWAY_CAR: + if (pSprite->owner==-1) + pSprite->owner = A_FindLocator((int16_t)pData[3],(int16_t)pData[0]); + + if (pSprite->owner == -1) + { + // debugging subway cars (mapping-wise) is freakin annoying + // let's at least have a helpful message... + Bsprintf(tempbuf,"Could not find any locators in sector %d" + " for SE# 6 or 14 with hitag %d.\n", (int)pData[0], (int)pData[3]); + G_GameExit(tempbuf); + } + + j = ldist(&sprite[pSprite->owner],pSprite); + + if (j < 1024L) + { + if (spriteLotag==SE_6_SUBWAY) + if (sprite[pSprite->owner].hitag&1) + pData[4]=pSector->extra; //Slow it down + pData[3]++; + pSprite->owner = A_FindLocator(pData[3],pData[0]); + if (pSprite->owner==-1) + { + pData[3]=0; + pSprite->owner = A_FindLocator(0,pData[0]); + } + } + + if (pSprite->xvel) + { +#ifdef YAX_ENABLE + int32_t firstrun = 1; +#endif + x = getangle(sprite[pSprite->owner].x-pSprite->x,sprite[pSprite->owner].y-pSprite->y); + q = G_GetAngleDelta(pSprite->ang,x)>>3; + + pData[2] += q; + pSprite->ang += q; + + if (pSprite->xvel == pSector->extra) + { + if (RR) + { + if (!S_CheckSoundPlaying(spriteNum,actor[spriteNum].lastv.x)) + A_PlaySound(actor[spriteNum].lastv.x,spriteNum); + } + if (!RR && (pSector->floorstat&1) == 0 && (pSector->ceilingstat&1) == 0) + { + if (!S_CheckSoundPlaying(spriteNum,actor[spriteNum].lastv.x)) + A_PlaySound(actor[spriteNum].lastv.x,spriteNum); + } + else if (ud.monsters_off == 0 && pSector->floorpal == 0 && (pSector->floorstat&1) && rnd(8)) + { + if (playerDist < 20480) + { + j = pSprite->ang; + pSprite->ang = getangle(pSprite->x-g_player[playerNum].ps->pos.x,pSprite->y-g_player[playerNum].ps->pos.y); + A_Shoot(spriteNum,RPG); + pSprite->ang = j; + } + } + } + + if (pSprite->xvel <= 64 && (RR || ((pSector->floorstat&1) == 0 && (pSector->ceilingstat&1) == 0))) + S_StopEnvSound(actor[spriteNum].lastv.x,spriteNum); + + if ((pSector->floorz-pSector->ceilingz) < (108<<8)) + { + if (ud.noclip == 0 && pSprite->xvel >= 192) + MaybeTrainKillPlayer(pSprite, 0); + } + + m = (pSprite->xvel*sintable[(pSprite->ang+512)&2047])>>14; + x = (pSprite->xvel*sintable[pSprite->ang&2047])>>14; + + for (TRAVERSE_CONNECT(playerNum)) + { + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + // might happen when squished into void space + if (pPlayer->cursectnum < 0) + break; + + if (sector[pPlayer->cursectnum].lotag != ST_2_UNDERWATER) + { + if (g_playerSpawnPoints[playerNum].sect == pSprite->sectnum) + { + g_playerSpawnPoints[playerNum].pos.x += m; + g_playerSpawnPoints[playerNum].pos.y += x; + } + + if (pSprite->sectnum == sprite[pPlayer->i].sectnum +#ifdef YAX_ENABLE + || (pData[9]>=0 && pData[9] == sprite[pPlayer->i].sectnum) +#endif + ) + { + rotatepoint(*(vec2_t *)pSprite, *(vec2_t *)&pPlayer->pos, q, (vec2_t *)&pPlayer->pos); + + pPlayer->pos.x += m; + pPlayer->pos.y += x; + + pPlayer->bobpos.x += m; + pPlayer->bobpos.y += x; + + pPlayer->q16ang += fix16_from_int(q); + pPlayer->q16ang &= 0x7FFFFFF; + + if (g_netServer || numplayers > 1) + { + pPlayer->opos.x = pPlayer->pos.x; + pPlayer->opos.y = pPlayer->pos.y; + } + if (sprite[pPlayer->i].extra <= 0) + { + sprite[pPlayer->i].x = pPlayer->pos.x; + sprite[pPlayer->i].y = pPlayer->pos.y; + } + } + } + } + + // NOTE: special loop handling + j = headspritesect[pSprite->sectnum]; + while (j >= 0) + { + // KEEPINSYNC2 + // XXX: underwater check? + if (sprite[j].statnum != STAT_PLAYER && sector[sprite[j].sectnum].lotag != ST_2_UNDERWATER && + (sprite[j].picnum != SECTOREFFECTOR || (sprite[j].lotag == SE_49_POINT_LIGHT||sprite[j].lotag == SE_50_SPOT_LIGHT)) + && sprite[j].picnum != LOCATORS) + { + rotatepoint(*(vec2_t *)pSprite,*(vec2_t *)&sprite[j],q,(vec2_t *)&sprite[j].x); + + sprite[j].x+= m; + sprite[j].y+= x; + + sprite[j].ang+=q; + + if (g_netServer || numplayers > 1) + { + actor[j].bpos.x = sprite[j].x; + actor[j].bpos.y = sprite[j].y; + } + } + j = nextspritesect[j]; +#ifdef YAX_ENABLE + if (j < 0) + { + if (pData[9]>=0 && firstrun) + { + firstrun = 0; + j = headspritesect[pData[9]]; + } + } +#endif + } + + A_MoveSector(spriteNum); + setsprite(spriteNum,(vec3_t *)pSprite); + + if ((pSector->floorz-pSector->ceilingz) < (108<<8)) + { + if (ud.noclip == 0 && pSprite->xvel >= 192) + MaybeTrainKillPlayer(pSprite, 1); + + MaybeTrainKillEnemies(spriteNum, 72); + } + } + + break; + + case SE_30_TWO_WAY_TRAIN: + if (pSprite->owner == -1) + { + pData[3] = !pData[3]; + pSprite->owner = A_FindLocator(pData[3],pData[0]); + } + else + { + + if (pData[4] == 1) // Starting to go + { + if (ldist(&sprite[pSprite->owner],pSprite) < (2048-128)) + pData[4] = 2; + else + { + if (pSprite->xvel == 0) + G_OperateActivators(pSprite->hitag+(!pData[3]),-1); + if (pSprite->xvel < 256) + pSprite->xvel += 16; + } + } + if (pData[4] == 2) + { + l = FindDistance2D(sprite[pSprite->owner].x-pSprite->x,sprite[pSprite->owner].y-pSprite->y); + + if (l <= 128) + pSprite->xvel = 0; + + if (pSprite->xvel > 0) + pSprite->xvel -= 16; + else + { + pSprite->xvel = 0; + G_OperateActivators(pSprite->hitag+(int16_t)pData[3],-1); + pSprite->owner = -1; + pSprite->ang += 1024; + pData[4] = 0; + G_OperateForceFields(spriteNum,pSprite->hitag); + + for (SPRITES_OF_SECT(pSprite->sectnum, j)) + { + if (sprite[j].picnum != SECTOREFFECTOR && sprite[j].picnum != LOCATORS) + { + actor[j].bpos.x = sprite[j].x; + actor[j].bpos.y = sprite[j].y; + } + } + + } + } + } + + if (pSprite->xvel) + { + l = (pSprite->xvel*sintable[(pSprite->ang+512)&2047])>>14; + x = (pSprite->xvel*sintable[pSprite->ang&2047])>>14; + + if ((pSector->floorz-pSector->ceilingz) < (108<<8)) + if (ud.noclip == 0) + MaybeTrainKillPlayer(pSprite, 0); + + for (int TRAVERSE_CONNECT(playerNum)) + { + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + if (sprite[pPlayer->i].sectnum == pSprite->sectnum) + { + pPlayer->pos.x += l; + pPlayer->pos.y += x; + + if (g_netServer || numplayers > 1) + { + pPlayer->opos.x = pPlayer->pos.x; + pPlayer->opos.y = pPlayer->pos.y; + } + + pPlayer->bobpos.x += l; + pPlayer->bobpos.y += x; + } + + if (g_playerSpawnPoints[playerNum].sect == pSprite->sectnum) + { + g_playerSpawnPoints[playerNum].pos.x += l; + g_playerSpawnPoints[playerNum].pos.y += x; + } + } + + for (SPRITES_OF_SECT(pSprite->sectnum, j)) + { + // TODO: replace some checks for SE 49/50 with statnum LIGHT instead? + if ((sprite[j].picnum != SECTOREFFECTOR || sprite[j].lotag==SE_49_POINT_LIGHT || sprite[j].lotag==SE_50_SPOT_LIGHT) + && sprite[j].picnum != LOCATORS) + { + if (numplayers < 2 && !g_netServer) + { + actor[j].bpos.x = sprite[j].x; + actor[j].bpos.y = sprite[j].y; + } + + sprite[j].x += l; + sprite[j].y += x; + + if (g_netServer || numplayers > 1) + { + actor[j].bpos.x = sprite[j].x; + actor[j].bpos.y = sprite[j].y; + } + } + } + + A_MoveSector(spriteNum); + setsprite(spriteNum,(vec3_t *)pSprite); + + if (pSector->floorz-pSector->ceilingz < (108<<8)) + { + if (ud.noclip == 0) + MaybeTrainKillPlayer(pSprite, 1); + + MaybeTrainKillEnemies(spriteNum, 24); + } + } + + break; + + + case SE_2_EARTHQUAKE://Quakes + if (pData[4] > 0 && pData[0] == 0) + { + if (pData[4] < spriteHitag) + pData[4]++; + else pData[0] = 1; + } + + if (pData[0] > 0) + { + pData[0]++; + + pSprite->xvel = 3; + + if (pData[0] > 96) + { + pData[0] = -1; //Stop the quake + pData[4] = -1; + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else + { + if ((pData[0]&31) == 8) + { + g_earthquakeTime = 48; + A_PlaySound(EARTHQUAKE,g_player[screenpeek].ps->i); + } + + pSector->floorheinum = (klabs(pSector->floorheinum - pData[5]) < 8) + ? pData[5] + : pSector->floorheinum + (ksgn(pData[5] - pSector->floorheinum) << 4); + } + + vec2_t const vect = { (pSprite->xvel * sintable[(pSprite->ang + 512) & 2047]) >> 14, + (pSprite->xvel * sintable[pSprite->ang & 2047]) >> 14 }; + + for (TRAVERSE_CONNECT(playerNum)) + { + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + if (pPlayer->cursectnum == pSprite->sectnum && pPlayer->on_ground) + { + pPlayer->pos.x += vect.x; + pPlayer->pos.y += vect.y; + + pPlayer->bobpos.x += vect.x; + pPlayer->bobpos.y += vect.y; + } + } + + for (bssize_t nextSprite, SPRITES_OF_SECT_SAFE(pSprite->sectnum, sectSprite, nextSprite)) + { + if (sprite[sectSprite].picnum != SECTOREFFECTOR) + { + sprite[sectSprite].x+=vect.x; + sprite[sectSprite].y+=vect.y; + setsprite(sectSprite,(vec3_t *)&sprite[sectSprite]); + } + } + + A_MoveSector(spriteNum); + setsprite(spriteNum,(vec3_t *)pSprite); + } + break; + + //Flashing sector lights after reactor EXPLOSION2 + + case SE_3_RANDOM_LIGHTS_AFTER_SHOT_OUT: + { + if (pData[4] == 0) break; + + // if(t[5] > 0) { t[5]--; break; } + + if ((tabledivide32_noinline(g_globalRandom, spriteHitag+1)&31) < 4 && !pData[2]) + { + // t[5] = 4+(g_globalRandom&7); + pSector->ceilingpal = pSprite->owner >> 8; + pSector->floorpal = pSprite->owner & 0xff; + pData[0] = pSprite->shade + (g_globalRandom & 15); + } + else + { + // t[5] = 4+(g_globalRandom&3); + pSector->ceilingpal = pSprite->pal; + pSector->floorpal = pSprite->pal; + pData[0] = pData[3]; + } + + pSector->ceilingshade = pData[0]; + pSector->floorshade = pData[0]; + + walltype *pWall = &wall[pSector->wallptr]; + + for (x=pSector->wallnum; x > 0; x--,pWall++) + { + if (pWall->hitag != 1) + { + pWall->shade = pData[0]; + + if ((pWall->cstat & 2) && pWall->nextwall >= 0) + wall[pWall->nextwall].shade = pWall->shade; + } + } + + break; + } + + case SE_4_RANDOM_LIGHTS: + { + // See A_Spawn(): + // s->owner: original ((ceilingpal<<8) | floorpal) + // t[2]: original floor shade + // t[3]: max wall shade + int lightFlag; + + if ((tabledivide32_noinline(g_globalRandom, spriteHitag+1)&31) < 4) + { + pData[1] = pSprite->shade + (g_globalRandom & 15); // Got really bright + pData[0] = pSprite->shade + (g_globalRandom & 15); + pSector->ceilingpal = pSprite->owner >> 8; + pSector->floorpal = pSprite->owner & 0xff; + lightFlag = 1; + } + else + { + pData[1] = pData[2]; + pData[0] = pData[3]; + + pSector->ceilingpal = pSprite->pal; + pSector->floorpal = pSprite->pal; + + lightFlag = 0; + } + + pSector->floorshade = pData[1]; + pSector->ceilingshade = pData[1]; + + walltype *pWall = &wall[pSector->wallptr]; + + for (x=pSector->wallnum; x > 0; x--,pWall++) + { + if (lightFlag) pWall->pal = (pSprite->owner&0xff); + else pWall->pal = pSprite->pal; + + if (pWall->hitag != 1) + { + pWall->shade = pData[0]; + if ((pWall->cstat&2) && pWall->nextwall >= 0) + wall[pWall->nextwall].shade = pWall->shade; + } + } + + for (bssize_t SPRITES_OF_SECT(SECT(spriteNum), sectSprite)) + { + if (sprite[sectSprite].cstat&16) + sprite[sectSprite].shade = (pSector->ceilingstat & 1) ? pSector->ceilingshade : pSector->floorshade; + } + + if (pData[4]) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + break; + } + + //BOSS + case SE_5: + { + if (playerDist < 8192) + { + int const saveAng = pSprite->ang; + pSprite->ang = getangle(pSprite->x - pPlayer->pos.x, pSprite->y - pPlayer->pos.y); + A_Shoot(spriteNum, FIRELASER); + pSprite->ang = saveAng; + } + + if (pSprite->owner==-1) //Start search + { + pData[4] = 0; + int closestLocatorDist = INT32_MAX; + int closestLocator = pSprite->owner; + + //Find the shortest dist + do + { + pSprite->owner = A_FindLocator((int16_t)pData[4], -1); // t[0] hold sectnum + + if (pSprite->owner == -1) + break; + + int const locatorDist = ldist(&sprite[pPlayer->i],&sprite[pSprite->owner]); + + if (closestLocatorDist > locatorDist) + { + closestLocator = pSprite->owner; + closestLocatorDist = locatorDist; + } + + pData[4]++; + } + while (1); + + pSprite->owner = closestLocator; + pSprite->zvel = ksgn(sprite[closestLocator].z - pSprite->z) << 4; + } + + if (ldist(&sprite[pSprite->owner],pSprite) < 1024) + { + pSprite->owner = -1; + goto next_sprite; + } + else pSprite->xvel=256; + + int const angInc = G_GetAngleDelta(pSprite->ang, getangle(sprite[pSprite->owner].x-pSprite->x, + sprite[pSprite->owner].y-pSprite->y))>>3; + pSprite->ang += angInc; + + if (rnd(32)) + { + pData[2] += angInc; + pSector->ceilingshade = 127; + } + else + { + pData[2] += G_GetAngleDelta(pData[2] + 512, getangle(pPlayer->pos.x - pSprite->x, pPlayer->pos.y - pSprite->y)) >> 2; + pSector->ceilingshade = 0; + } + + if (A_IncurDamage(spriteNum) >= 0) + { + if (++pData[3] == 5) + { + pSprite->zvel += 1024; + P_DoQuote(QUOTE_WASTED, g_player[myconnectindex].ps); + } + } + + pSprite->z += pSprite->zvel; + pSector->ceilingz += pSprite->zvel; + sector[pData[0]].ceilingz += pSprite->zvel; + + A_MoveSector(spriteNum); + setsprite(spriteNum, (vec3_t *)pSprite); + break; + } + + case SE_8_UP_OPEN_DOOR_LIGHTS: + case SE_9_DOWN_OPEN_DOOR_LIGHTS: + { + + // work only if its moving + + int animGoal = -1; + + if (actor[spriteNum].t_data[4]) + { + if (++actor[spriteNum].t_data[4] > 8) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + animGoal = 1; + } + else animGoal = GetAnimationGoal(&pSector->ceilingz); + + if (animGoal >= 0) + { + int shadeInc = ((pSector->lotag & 0x8000u) || actor[spriteNum].t_data[4]) ? -pData[3] : pData[3]; + + if (spriteLotag == SE_9_DOWN_OPEN_DOOR_LIGHTS) + shadeInc = -shadeInc; + + for (bssize_t SPRITES_OF(STAT_EFFECTOR, sectorEffector)) + { + if (sprite[sectorEffector].lotag == spriteLotag && sprite[sectorEffector].hitag == spriteHitag) + { + int const sectNum = sprite[sectorEffector].sectnum; + int const spriteShade = sprite[sectorEffector].shade; + + walltype *pWall = &wall[sector[sectNum].wallptr]; + + for (bsize_t l=sector[sectNum].wallnum; l>0; l--, pWall++) + { + if (pWall->hitag == 1) + continue; + + pWall->shade += shadeInc; + + if (pWall->shade < spriteShade) + pWall->shade = spriteShade; + else if (pWall->shade > actor[sectorEffector].t_data[2]) + pWall->shade = actor[sectorEffector].t_data[2]; + + if (pWall->nextwall >= 0 && wall[pWall->nextwall].hitag != 1) + wall[pWall->nextwall].shade = pWall->shade; + } + + sector[sectNum].floorshade += shadeInc; + sector[sectNum].ceilingshade += shadeInc; + + if (sector[sectNum].floorshade < spriteShade) + sector[sectNum].floorshade = spriteShade; + else if (sector[sectNum].floorshade > actor[sectorEffector].t_data[0]) + sector[sectNum].floorshade = actor[sectorEffector].t_data[0]; + + if (sector[sectNum].ceilingshade < spriteShade) + sector[sectNum].ceilingshade = spriteShade; + else if (sector[sectNum].ceilingshade > actor[sectorEffector].t_data[1]) + sector[sectNum].ceilingshade = actor[sectorEffector].t_data[1]; + + if (RR && sector[sectNum].hitag == 1) + sector[sectNum].ceilingshade = actor[sectorEffector].t_data[1]; + } + } + } + break; + } + + case SE_10_DOOR_AUTO_CLOSE: + // XXX: 32791, what the hell? + if ((pSector->lotag&0xff) == ST_27_STRETCH_BRIDGE || (pSector->floorz > pSector->ceilingz && (pSector->lotag&0xff) != ST_23_SWINGING_DOOR) || pSector->lotag == (int16_t)32791u) + { + j = 1; + + if ((pSector->lotag&0xff) != ST_27_STRETCH_BRIDGE) + for (bssize_t TRAVERSE_CONNECT(playerNum)) + if (pSector->lotag != ST_30_ROTATE_RISE_BRIDGE && pSector->lotag != ST_31_TWO_WAY_TRAIN && pSector->lotag != 0 + && pSprite->sectnum == sprite[g_player[playerNum].ps->i].sectnum) + j = 0; + + if (j == 1) + { + if (pData[0] > spriteHitag) + switch (sector[pSprite->sectnum].lotag) + { + case ST_20_CEILING_DOOR: + case ST_21_FLOOR_DOOR: + case ST_22_SPLITTING_DOOR: + case ST_26_SPLITTING_ST_DOOR: + if (!RR && GetAnimationGoal(§or[pSprite->sectnum].ceilingz) >= 0) + break; + fallthrough__; + default: + G_ActivateBySector(pSprite->sectnum,spriteNum); + pData[0] = 0; + break; + } + else pData[0]++; + } + } + else pData[0]=0; + break; + + case SE_11_SWINGING_DOOR: //Swingdoor + + if (pData[5] > 0) + { + pData[5]--; + break; + } + + if (pData[4]) + { + int const endWall = pSector->wallptr+pSector->wallnum; + + l = (SP(spriteNum) >> 3) * pData[3]; + for (j=pSector->wallptr; j 0 && A_CheckEnemySprite(&sprite[k]) + && clipinsidebox((vec2_t *)&sprite[k], j, 256) == 1) + goto next_sprite; + } + for (SPRITES_OF(STAT_PLAYER, k)) + { + if (sprite[k].owner >= 0 && clipinsidebox((vec2_t *)&sprite[k], j, 144) == 1) + { + pData[5] = 8; // Delay + pData[2] -= l; + pData[4] -= l; + A_MoveSector(spriteNum); + setsprite(spriteNum, (vec3_t *)pSprite); + goto next_sprite; + } + } + } + + pData[2] += l; + pData[4] += l; + A_MoveSector(spriteNum); + setsprite(spriteNum, (vec3_t *)pSprite); + + if (pData[4] <= -511 || pData[4] >= 512) + { + pData[4] = 0; + pData[2] &= 0xffffff00; + A_MoveSector(spriteNum); + setsprite(spriteNum, (vec3_t *) pSprite); + break; + } + } + break; + + case SE_12_LIGHT_SWITCH: + if (pData[0] == 3 || pData[3] == 1) //Lights going off + { + pSector->floorpal = 0; + pSector->ceilingpal = 0; + + walltype *pWall = &wall[pSector->wallptr]; + + for (j = pSector->wallnum; j > 0; j--, pWall++) + { + if (pWall->hitag != 1) + { + pWall->shade = pData[1]; + pWall->pal = 0; + } + } + + pSector->floorshade = pData[1]; + pSector->ceilingshade = pData[2]; + pData[0] = 0; + + for (SPRITES_OF_SECT(SECT(spriteNum), j)) + { + if (sprite[j].cstat & 16) + sprite[j].shade = (pSector->ceilingstat & 1) ? pSector->ceilingshade : pSector->floorshade; + } + + if (pData[3] == 1) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + + if (pData[0] == 1) //Lights flickering on + { + if (pSector->floorshade > pSprite->shade) + { + pSector->floorpal = pSprite->pal; + pSector->ceilingpal = pSprite->pal; + + pSector->floorshade -= 2; + pSector->ceilingshade -= 2; + + walltype *pWall = &wall[pSector->wallptr]; + for (j = pSector->wallnum; j > 0; j--, pWall++) + { + if (pWall->hitag != 1) + { + pWall->pal = pSprite->pal; + pWall->shade -= 2; + } + } + } + else pData[0] = 2; + + for (SPRITES_OF_SECT(SECT(spriteNum), j)) + { + if (sprite[j].cstat&16) + { + if (sprite[j].cstat & 16) + sprite[j].shade = (pSector->ceilingstat & 1) ? pSector->ceilingshade : pSector->floorshade; + } + } + } + break; + + case 47: + if (!RRRA) + break; + if (pData[0] == 3 || pData[3] == 1) //Lights going off + { + pSector->floorpal = 0; + pSector->ceilingpal = 0; + + walltype *pWall = &wall[pSector->wallptr]; + + for (j = pSector->wallnum; j > 0; j--, pWall++) + { + if (pWall->hitag != 1) + { + pWall->shade = pData[1]; + pWall->pal = 0; + } + } + + pSector->floorshade = pData[1]; + pSector->ceilingshade = pData[2]; + pData[0] = 0; + + for (SPRITES_OF_SECT(SECT(spriteNum), j)) + { + if (sprite[j].cstat & 16) + sprite[j].shade = (pSector->ceilingstat & 1) ? pSector->ceilingshade : pSector->floorshade; + } + + if (pData[3] == 1) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + + if (pData[0] == 1) //Lights flickering on + { + if (pSector->floorshade > pSprite->shade) + { + pSector->floorpal = pSprite->pal; + + pSector->floorshade -= 2; + + walltype *pWall = &wall[pSector->wallptr]; + for (j = pSector->wallnum; j > 0; j--, pWall++) + { + if (pWall->hitag != 1) + { + pWall->pal = pSprite->pal; + pWall->shade -= 2; + } + } + } + else pData[0] = 2; + + for (SPRITES_OF_SECT(SECT(spriteNum), j)) + { + if (sprite[j].cstat&16) + { + if (sprite[j].cstat & 16) + sprite[j].shade = (pSector->ceilingstat & 1) ? pSector->ceilingshade : pSector->floorshade; + } + } + } + break; + + case 48: + if (!RRRA) + break; + if (pData[0] == 3 || pData[3] == 1) //Lights going off + { + pSector->floorpal = 0; + pSector->ceilingpal = 0; + + walltype *pWall = &wall[pSector->wallptr]; + + for (j = pSector->wallnum; j > 0; j--, pWall++) + { + if (pWall->hitag != 1) + { + pWall->shade = pData[1]; + pWall->pal = 0; + } + } + + pSector->floorshade = pData[1]; + pSector->ceilingshade = pData[2]; + pData[0] = 0; + + for (SPRITES_OF_SECT(SECT(spriteNum), j)) + { + if (sprite[j].cstat & 16) + sprite[j].shade = (pSector->ceilingstat & 1) ? pSector->ceilingshade : pSector->floorshade; + } + + if (pData[3] == 1) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + + if (pData[0] == 1) //Lights flickering on + { + if (pSector->ceilingshade > pSprite->shade) + { + pSector->ceilingpal = pSprite->pal; + + pSector->ceilingshade -= 2; + + walltype *pWall = &wall[pSector->wallptr]; + for (j = pSector->wallnum; j > 0; j--, pWall++) + { + if (pWall->hitag != 1) + { + pWall->pal = pSprite->pal; + pWall->shade -= 2; + } + } + } + else pData[0] = 2; + + for (SPRITES_OF_SECT(SECT(spriteNum), j)) + { + if (sprite[j].cstat&16) + sprite[j].shade = (pSector->ceilingstat & 1) ? pSector->ceilingshade : pSector->floorshade; + } + } + break; + + + case SE_13_EXPLOSIVE: + if (pData[2]) + { + // t[0]: ceiling z + // t[1]: floor z + // s->owner: 1 if affect ceiling, 0 if affect floor + // t[3]: 1 if ceiling was parallaxed at premap, 0 else + + j = (SP(spriteNum)<<5)|1; + + if (pSprite->ang == 512) + { + if (pSprite->owner) + { + pSector->ceilingz = (klabs(pData[0] - pSector->ceilingz) >= j) + ? pSector->ceilingz + ksgn(pData[0] - pSector->ceilingz) * j + : pData[0]; + } + else + { + pSector->floorz = (klabs(pData[1] - pSector->floorz) >= j) + ? pSector->floorz + ksgn(pData[1] - pSector->floorz) * j + : pData[1]; + } + } + else + { + pSector->floorz = (klabs(pData[1] - pSector->floorz) >= j) + ? pSector->floorz + ksgn(pData[1] - pSector->floorz) * j + : pData[1]; + + pSector->ceilingz = /*(klabs(pData[0] - pSector->ceilingz) >= j) + ? pSector->ceilingz + ksgn(pData[0] - pSector->ceilingz) * j + : */pData[0]; + } +#ifdef YAX_ENABLE + if (pSprite->ang == 512) + { + int16_t cf=!pSprite->owner, bn=yax_getbunch(pSector-sector, cf); + int32_t jj, daz=SECTORFLD(pSector-sector,z, cf); + + if (bn >= 0) + { + for (SECTORS_OF_BUNCH(bn, cf, jj)) + { + SECTORFLD(jj,z, cf) = daz; + SECTORFLD(jj,stat, cf) &= ~(128+256 + 512+2048); + } + for (SECTORS_OF_BUNCH(bn, !cf, jj)) + { + SECTORFLD(jj,z, !cf) = daz; + SECTORFLD(jj,stat, !cf) &= ~(128+256 + 512+2048); + } + } + } +#endif + if (pData[3] == 1) + { + //Change the shades + + pData[3]++; + pSector->ceilingstat ^= 1; + + if (pSprite->ang == 512) + { + walltype *pWall = &wall[pSector->wallptr]; + + for (j = pSector->wallnum; j > 0; j--, pWall++) + pWall->shade = pSprite->shade; + + pSector->floorshade = pSprite->shade; + + if (g_player[0].ps->one_parallax_sectnum >= 0) + { + pSector->ceilingpicnum = sector[g_player[0].ps->one_parallax_sectnum].ceilingpicnum; + pSector->ceilingshade = sector[g_player[0].ps->one_parallax_sectnum].ceilingshade; + } + } + } + + if (++pData[2] > 256) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + + if (pData[2] == 4 && pSprite->ang != 512) + for (x=0; x<7; x++) RANDOMSCRAP(pSprite, spriteNum); + break; + + + case SE_15_SLIDING_DOOR: + + if (pData[4]) + { + pSprite->xvel = 16; + + if (pData[4] == 1) //Opening + { + if (pData[3] >= (SP(spriteNum)>>3)) + { + pData[4] = 0; //Turn off the sliders + A_CallSound(pSprite->sectnum,spriteNum); + break; + } + pData[3]++; + } + else if (pData[4] == 2) + { + if (pData[3]<1) + { + pData[4] = 0; + A_CallSound(pSprite->sectnum,spriteNum); + break; + } + pData[3]--; + } + + A_MoveSector(spriteNum); + setsprite(spriteNum,(vec3_t *)pSprite); + } + break; + + case SE_16_REACTOR: //Reactor + + pData[2]+=32; + + if (pSector->floorz < pSector->ceilingz) + pSprite->shade = 0; + else if (pSector->ceilingz < pData[3]) + { + //The following code check to see if + //there is any other sprites in the sector. + //If there isn't, then kill this sectoreffector + //itself..... + + for (SPRITES_OF_SECT(pSprite->sectnum, j)) + { + if (sprite[j].picnum == REACTOR || sprite[j].picnum == REACTOR2) + break; + } + + if (j == -1) + DELETE_SPRITE_AND_CONTINUE(spriteNum); + + pSprite->shade = 1; + } + + pSector->ceilingz = (pSprite->shade) + ? pSector->ceilingz + 1024 + : pSector->ceilingz - 512; + + A_MoveSector(spriteNum); + setsprite(spriteNum,(vec3_t *)pSprite); + + break; + + case SE_17_WARP_ELEVATOR: + { + int32_t nextk; + + q = pData[0]*(SP(spriteNum)<<2); + + pSector->ceilingz += q; + pSector->floorz += q; + + for (SPRITES_OF_SECT(pSprite->sectnum, j)) + { + if (sprite[j].statnum == STAT_PLAYER && sprite[j].owner >= 0) + { + int const warpPlayer = P_Get(j); + DukePlayer_t *const pPlayer = g_player[warpPlayer].ps; + + if (numplayers < 2 && !g_netServer) + pPlayer->opos.z = pPlayer->pos.z; + + pPlayer->pos.z += q; + pPlayer->truefz += q; + pPlayer->truecz += q; + + if (g_netServer || numplayers > 1) + pPlayer->opos.z = pPlayer->pos.z; + } + + if (sprite[j].statnum != STAT_EFFECTOR) + { + actor[j].bpos.z = sprite[j].z; + sprite[j].z += q; + } + + actor[j].floorz = pSector->floorz; + actor[j].ceilingz = pSector->ceilingz; + } + + if (pData[0]) //If in motion + { + if (klabs(pSector->floorz-pData[2]) <= SP(spriteNum)) + { + G_ActivateWarpElevators(spriteNum,0); + break; + } + + // If we still see the opening, we can't yet teleport. + if (pData[0]==-1) + { + if (pSector->floorz > pData[3]) + break; + } + else if (pSector->ceilingz < pData[4]) break; + + if (pData[1] == 0) break; + pData[1] = 0; + + for (SPRITES_OF(STAT_EFFECTOR, j)) + { + if (spriteNum != j && sprite[j].lotag == SE_17_WARP_ELEVATOR) + if (pSector->hitag-pData[0] == sector[sprite[j].sectnum].hitag + && spriteHitag == sprite[j].hitag) + break; + } + + if (j == -1) break; + + for (SPRITES_OF_SECT_SAFE(pSprite->sectnum, k, nextk)) + { + if (sprite[k].statnum == STAT_PLAYER && sprite[k].owner >= 0) + { + int const warpPlayer = P_Get(k); + DukePlayer_t *const pPlayer = g_player[warpPlayer].ps; + + pPlayer->pos.x += sprite[j].x - pSprite->x; + pPlayer->pos.y += sprite[j].y - pSprite->y; + pPlayer->pos.z = sector[sprite[j].sectnum].floorz - (pSector->floorz - pPlayer->pos.z); + + actor[k].floorz = sector[sprite[j].sectnum].floorz; + actor[k].ceilingz = sector[sprite[j].sectnum].ceilingz; + *(vec2_t *)&pPlayer->opos = *(vec2_t *)pPlayer; + *(vec2_t *)&pPlayer->bobpos = *(vec2_t *)pPlayer; + pPlayer->opos.z = pPlayer->pos.z; + pPlayer->truefz = actor[k].floorz; + pPlayer->truecz = actor[k].ceilingz; + pPlayer->bobcounter = 0; + + changespritesect(k, sprite[j].sectnum); + pPlayer->cursectnum = sprite[j].sectnum; + } + else if (sprite[k].statnum != STAT_EFFECTOR) + { + sprite[k].x += sprite[j].x-pSprite->x; + sprite[k].y += sprite[j].y-pSprite->y; + sprite[k].z = sector[sprite[j].sectnum].floorz - (pSector->floorz - sprite[k].z); + + Bmemcpy(&actor[k].bpos, &sprite[k], sizeof(vec3_t)); + + changespritesect(k,sprite[j].sectnum); + setsprite(k,(vec3_t *)&sprite[k]); + + actor[k].floorz = sector[sprite[j].sectnum].floorz; + actor[k].ceilingz = sector[sprite[j].sectnum].ceilingz; + } + } + } + break; + } + + case SE_18_INCREMENTAL_SECTOR_RISE_FALL: + if (pData[0]) + { + if (pSprite->pal) + { + if (pSprite->ang == 512) + { + pSector->ceilingz -= pSector->extra; + if (pSector->ceilingz <= pData[1]) + { + pSector->ceilingz = pData[1]; + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + } + else + { + pSector->floorz += pSector->extra; + + if (!RR) + for (bssize_t SPRITES_OF_SECT(pSprite->sectnum, sectSprite)) + { + if (sprite[sectSprite].picnum == APLAYER && sprite[sectSprite].owner >= 0 && g_player[P_Get(sectSprite)].ps->on_ground == 1) + g_player[P_Get(sectSprite)].ps->pos.z += pSector->extra; + + if (sprite[sectSprite].zvel == 0 && sprite[sectSprite].statnum != STAT_EFFECTOR && sprite[sectSprite].statnum != STAT_PROJECTILE) + { + actor[sectSprite].bpos.z = sprite[sectSprite].z += pSector->extra; + actor[sectSprite].floorz = pSector->floorz; + } + } + + if (pSector->floorz >= pData[1]) + { + pSector->floorz = pData[1]; + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + } + } + else + { + if (pSprite->ang == 512) + { + pSector->ceilingz += pSector->extra; + if (pSector->ceilingz >= pSprite->z) + { + pSector->ceilingz = pSprite->z; + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + } + else + { + pSector->floorz -= pSector->extra; + + if (!RR) + for (bssize_t SPRITES_OF_SECT(pSprite->sectnum, sectSprite)) + { + if (sprite[sectSprite].picnum == APLAYER && sprite[sectSprite].owner >= 0 &&g_player[P_Get(sectSprite)].ps->on_ground == 1) + g_player[P_Get(sectSprite)].ps->pos.z -= pSector->extra; + + if (sprite[sectSprite].zvel == 0 && sprite[sectSprite].statnum != STAT_EFFECTOR && sprite[sectSprite].statnum != STAT_PROJECTILE) + { + actor[sectSprite].bpos.z = sprite[sectSprite].z -= pSector->extra; + actor[sectSprite].floorz = pSector->floorz; + } + } + + if (pSector->floorz <= pSprite->z) + { + pSector->floorz = pSprite->z; + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + } + } + + if (++pData[2] >= pSprite->hitag) + { + pData[2] = 0; + pData[0] = 0; + } + } + break; + + case SE_19_EXPLOSION_LOWERS_CEILING: //Battlestar galactia shields + + if (pData[0]) + { + if (pData[0] == 1) + { + pData[0]++; + x = pSector->wallptr; + q = x+pSector->wallnum; + + for (j=x; j= 0) + { + wall[wall[j].nextwall].overpicnum = 0; + wall[wall[j].nextwall].cstat &= (128+32+8+4+2); + } + } + } + } + + if (pSector->ceilingz < pSector->floorz) + pSector->ceilingz += SP(spriteNum); + else + { + pSector->ceilingz = pSector->floorz; + + for (SPRITES_OF(STAT_EFFECTOR, j)) + { + if (sprite[j].lotag == SE_0_ROTATING_SECTOR && sprite[j].hitag==spriteHitag) + { + sectortype *const pSector = §or[sprite[j].sectnum]; + int const ownerSector = sprite[sprite[j].owner].sectnum; + + pSector->ceilingpal = sector[ownerSector].floorpal; + pSector->floorpal = pSector->ceilingpal; + pSector->ceilingshade = sector[ownerSector].floorshade; + pSector->floorshade = pSector->ceilingshade; + + actor[sprite[j].owner].t_data[0] = 2; + } + } + + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + } + else //Not hit yet + { + if (G_FindExplosionInSector(pSprite->sectnum) >= 0) + { + P_DoQuote(QUOTE_UNLOCKED, g_player[myconnectindex].ps); + + for (SPRITES_OF(STAT_EFFECTOR, l)) + { + switch (sprite[l].lotag & 0x7fff) + { + case SE_0_ROTATING_SECTOR: + if (sprite[l].hitag == spriteHitag) + { + int const spriteOwner = sprite[l].owner; + int const sectNum = sprite[l].sectnum; + + sector[sectNum].ceilingshade = sprite[spriteOwner].shade; + sector[sectNum].floorshade = sector[sectNum].ceilingshade; + sector[sectNum].ceilingpal = sprite[spriteOwner].pal; + sector[sectNum].floorpal = sector[sectNum].ceilingpal; + } + break; + + case SE_1_PIVOT: + case SE_12_LIGHT_SWITCH: +// case SE_18_INCREMENTAL_SECTOR_RISE_FALL: + case SE_19_EXPLOSION_LOWERS_CEILING: + if (spriteHitag == sprite[l].hitag) + if (actor[l].t_data[0] == 0) + { + actor[l].t_data[0] = 1; // Shut them all on + sprite[l].owner = spriteNum; + } + + break; + } + } + } + } + + break; + + case SE_20_STRETCH_BRIDGE: //Extend-o-bridge + if (pData[0] == 0) break; + pSprite->xvel = (pData[0] == 1) ? 8 : -8; + + if (pSprite->xvel) //Moving + { + vec2_t const vect = { (pSprite->xvel * sintable[(pSprite->ang + 512) & 2047]) >> 14, + (pSprite->xvel * sintable[pSprite->ang & 2047]) >> 14 }; + + pData[3] += pSprite->xvel; + + pSprite->x += vect.x; + pSprite->y += vect.y; + + if (pData[3] <= 0 || (pData[3] >> 6) >= (SP(spriteNum) >> 6)) + { + pSprite->x -= vect.x; + pSprite->y -= vect.y; + pData[0] = 0; + A_CallSound(pSprite->sectnum, spriteNum); + break; + } + + for (bssize_t nextSprite, SPRITES_OF_SECT_SAFE(pSprite->sectnum, sectSprite, nextSprite)) + { + if (sprite[sectSprite].statnum != STAT_EFFECTOR && sprite[sectSprite].zvel == 0) + { + sprite[sectSprite].x += vect.x; + sprite[sectSprite].y += vect.y; + + setsprite(sectSprite, (vec3_t *)&sprite[sectSprite]); + + if (sector[sprite[sectSprite].sectnum].floorstat & 2 && sprite[sectSprite].statnum == STAT_ZOMBIEACTOR) + A_Fall(sectSprite); + } + } + + dragpoint((int16_t)pData[1], wall[pData[1]].x + vect.x, wall[pData[1]].y + vect.y, 0); + dragpoint((int16_t)pData[2], wall[pData[2]].x + vect.x, wall[pData[2]].y + vect.y, 0); + + for (bssize_t TRAVERSE_CONNECT(playerNum)) + { + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + if (pPlayer->cursectnum == pSprite->sectnum && pPlayer->on_ground) + { + pPlayer->pos.x += vect.x; + pPlayer->pos.y += vect.y; + + pPlayer->opos.x = pPlayer->pos.x; + pPlayer->opos.y = pPlayer->pos.y; + + pPlayer->pos.z += PHEIGHT; + setsprite(pPlayer->i, (vec3_t *)pPlayer); + pPlayer->pos.z -= PHEIGHT; + } + } + + pSector->floorxpanning -= vect.x >> 3; + pSector->floorypanning -= vect.y >> 3; + + pSector->ceilingxpanning -= vect.x >> 3; + pSector->ceilingypanning -= vect.y >> 3; + } + + break; + + case SE_21_DROP_FLOOR: // Cascading effect + { + if (pData[0] == 0) break; + + int32_t *zptr = (pSprite->ang == 1536) ? &pSector->ceilingz : &pSector->floorz; + + if (pData[0] == 1) //Decide if the s->sectnum should go up or down + { + pSprite->zvel = ksgn(pSprite->z-*zptr) * (SP(spriteNum)<<4); + pData[0]++; + } + + if (pSector->extra == 0) + { + *zptr += pSprite->zvel; + + if (klabs(*zptr-pSprite->z) < 1024) + { + *zptr = pSprite->z; + DELETE_SPRITE_AND_CONTINUE(spriteNum); //All done // SE_21_KILLIT, see sector.c + } + } + else pSector->extra--; + break; + } + + case SE_22_TEETH_DOOR: + if (pData[1]) + { + if (GetAnimationGoal(§or[pData[0]].ceilingz) >= 0) + pSector->ceilingz += pSector->extra*9; + else pData[1] = 0; + } + break; + + case 156: + if (!RRRA) break; + fallthrough__; + case SE_24_CONVEYOR: + case SE_34: + { + if (pData[4]) + break; + + vec2_t const vect = { (SP(spriteNum) * sintable[(pSprite->ang + 512) & 2047]) >> 18, + (SP(spriteNum) * sintable[pSprite->ang & 2047]) >> 18 }; + + k = 0; + + for (bssize_t nextSprite, SPRITES_OF_SECT_SAFE(pSprite->sectnum, sectSprite, nextSprite)) + { + if (sprite[sectSprite].zvel < 0) + continue; + + switch (sprite[sectSprite].statnum) + { + case STAT_MISC: + switch (DYNAMICTILEMAP(sprite[sectSprite].picnum)) + { + case PUKE__STATIC: + case FOOTPRINTS4__STATIC: + case BLOODSPLAT1__STATIC: + case BLOODSPLAT2__STATIC: + case BLOODSPLAT3__STATIC: + case BLOODSPLAT4__STATIC: + if (RR) break; + fallthrough__; + case BULLETHOLE__STATIC: + if (RR && sprite[sectSprite].picnum == BULLETHOLE) continue; + fallthrough__; + case BLOODPOOL__STATIC: + case FOOTPRINTS__STATIC: + case FOOTPRINTS2__STATIC: + case FOOTPRINTS3__STATIC: sprite[sectSprite].xrepeat = sprite[sectSprite].yrepeat = 0; continue; + + case LASERLINE__STATIC: if (RR) break; continue; + } + fallthrough__; + case STAT_STANDABLE: + if (!RR && sprite[sectSprite].picnum == TRIPBOMB) + break; + fallthrough__; + case STAT_ACTOR: + case STAT_DEFAULT: + if (sprite[sectSprite].picnum == BOLT1 + || sprite[sectSprite].picnum == BOLT1 + 1 + || sprite[sectSprite].picnum == BOLT1 + 2 + || sprite[sectSprite].picnum == BOLT1 + 3 + || (!RR && (sprite[sectSprite].picnum == SIDEBOLT1 + || sprite[sectSprite].picnum == SIDEBOLT1 + 1 + || sprite[sectSprite].picnum == SIDEBOLT1 + 2 + || sprite[sectSprite].picnum == SIDEBOLT1 + 3)) + || A_CheckSwitchTile(sectSprite)) + break; + + if (!(sprite[sectSprite].picnum >= CRANE && sprite[sectSprite].picnum <= CRANE + 3)) + { + if (sprite[sectSprite].z > actor[sectSprite].floorz - ZOFFSET2) + { + actor[sectSprite].bpos.x = sprite[sectSprite].x; + actor[sectSprite].bpos.y = sprite[sectSprite].y; + + sprite[sectSprite].x += vect.x >> (RR ? 1 : 2); + sprite[sectSprite].y += vect.y >> (RR ? 1 : 2); + + setsprite(sectSprite, (vec3_t *)&sprite[sectSprite]); + + if (sector[sprite[sectSprite].sectnum].floorstat & 2) + if (sprite[sectSprite].statnum == STAT_ZOMBIEACTOR) + A_Fall(sectSprite); + } + } + break; + } + } + + for (bssize_t TRAVERSE_CONNECT(playerNum)) + { + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + if (pPlayer->cursectnum == pSprite->sectnum && pPlayer->on_ground) + { + if (klabs(pPlayer->pos.z - pPlayer->truefz) < PHEIGHT + (9 << 8)) + { + pPlayer->fric.x += vect.x << 3; + pPlayer->fric.y += vect.y << 3; + } + } + } + if (!RRRA || spriteLotag != 156) + pSector->floorxpanning += SP(spriteNum)>>7; + + break; + } + + case SE_35: + if (pSector->ceilingz > pSprite->z) + { + for (j = 0; j < 8; j++) + { + pSprite->ang += krand2()&511; + k = A_Spawn(spriteNum, SMALLSMOKE); + sprite[k].xvel = 96+(krand2()&127); + A_SetSprite(k, CLIPMASK0); + setsprite(k, (vec3_t *) &sprite[k]); + if (rnd(16)) + A_Spawn(spriteNum, EXPLOSION2); + } + + } + switch (pData[0]) + { + case 0: + pSector->ceilingz += pSprite->yvel; + if (pSector->ceilingz > pSector->floorz) + pSector->floorz = pSector->ceilingz; + if (pSector->ceilingz > pSprite->z+ZOFFSET5) + pData[0]++; + break; + case 1: + pSector->ceilingz-=(pSprite->yvel<<2); + if (pSector->ceilingz < pData[4]) + { + pSector->ceilingz = pData[4]; + pData[0] = 0; + } + break; + } + break; + + case SE_25_PISTON: //PISTONS + if (pData[4] == 0) break; + + if (pSector->floorz <= pSector->ceilingz) + pSprite->shade = 0; + else if (pSector->ceilingz <= pData[RR?4:3]) + pSprite->shade = 1; + + if (pSprite->shade) + { + pSector->ceilingz += SP(spriteNum)<<4; + if (pSector->ceilingz > pSector->floorz) + { + pSector->ceilingz = pSector->floorz; + if (RRRA && g_pistonSound) + A_PlaySound(371, spriteNum); + } + } + else + { + pSector->ceilingz -= SP(spriteNum)<<4; + if (pSector->ceilingz < pData[RR?4:3]) + { + pSector->ceilingz = pData[RR?4:3]; + if (RRRA && g_pistonSound) + A_PlaySound(167, spriteNum); + } + } + + break; + + case SE_26: + { + int32_t p, nextj; + + pSprite->xvel = 32; + l = (pSprite->xvel*sintable[(pSprite->ang+512)&2047])>>14; + x = (pSprite->xvel*sintable[pSprite->ang&2047])>>14; + + pSprite->shade++; + if (pSprite->shade > 7) + { + pSprite->x = pData[3]; + pSprite->y = pData[4]; + pSector->floorz -= ((pSprite->zvel*pSprite->shade)-pSprite->zvel); + pSprite->shade = 0; + } + else + pSector->floorz += pSprite->zvel; + + for (SPRITES_OF_SECT_SAFE(pSprite->sectnum, j, nextj)) + { + if (sprite[j].statnum != STAT_EFFECTOR && sprite[j].statnum != STAT_PLAYER ) + { + actor[j].bpos.x = sprite[j].x; + actor[j].bpos.y = sprite[j].y; + + sprite[j].x += l; + sprite[j].y += x; + sprite[j].z += pSprite->zvel; + + setsprite(j, (vec3_t *)&sprite[j]); + } + } + + for (TRAVERSE_CONNECT(p)) + { + DukePlayer_t *const pPlayer = g_player[p].ps; + + if (pSprite->sectnum == sprite[pPlayer->i].sectnum && pPlayer->on_ground) + { + pPlayer->fric.x += l << 5; + pPlayer->fric.y += x << 5; + pPlayer->pos.z += pSprite->zvel; + } + } + + A_MoveSector(spriteNum); + setsprite(spriteNum,(vec3_t *)pSprite); + + break; + } + + case SE_27_DEMO_CAM: + { + if (ud.recstat == 0 || !cl_democams) break; + + actor[spriteNum].tempang = pSprite->ang; + + int const p = A_FindPlayer(pSprite,&x); + DukePlayer_t * const ps = g_player[p].ps; + + if (sprite[ps->i].extra > 0 && myconnectindex == screenpeek) + { + if (pData[0] < 0) + { + ud.camerasprite = spriteNum; + pData[0]++; + } + else if (ud.recstat == 2 && ps->newowner == -1) + { + if (cansee(pSprite->x,pSprite->y,pSprite->z,SECT(spriteNum),ps->pos.x,ps->pos.y,ps->pos.z,ps->cursectnum)) + { + if (x < (int32_t)((unsigned)spriteHitag)) + { + ud.camerasprite = spriteNum; + pData[0] = 999; + pSprite->ang += G_GetAngleDelta(pSprite->ang,getangle(ps->pos.x-pSprite->x,ps->pos.y-pSprite->y))>>3; + SP(spriteNum) = 100+((pSprite->z-ps->pos.z)/257); + + } + else if (pData[0] == 999) + { + if (ud.camerasprite == spriteNum) + pData[0] = 0; + else pData[0] = -10; + ud.camerasprite = spriteNum; + + } + } + else + { + pSprite->ang = getangle(ps->pos.x-pSprite->x,ps->pos.y-pSprite->y); + + if (pData[0] == 999) + { + if (ud.camerasprite == spriteNum) + pData[0] = 0; + else pData[0] = -20; + ud.camerasprite = spriteNum; + } + } + } + } + break; + } + + case SE_28_LIGHTNING: + { + if (RR) + break; + if (pData[5] > 0) + { + pData[5]--; + break; + } + + if (T1(spriteNum) == 0) + { + A_FindPlayer(pSprite,&x); + if (x > 15500) + break; + T1(spriteNum) = 1; + T2(spriteNum) = 64 + (krand2()&511); + T3(spriteNum) = 0; + } + else + { + T3(spriteNum)++; + if (T3(spriteNum) > T2(spriteNum)) + { + T1(spriteNum) = 0; + g_player[screenpeek].ps->visibility = ud.const_visibility; + break; + } + else if (T3(spriteNum) == (T2(spriteNum)>>1)) + A_PlaySound(THUNDER,spriteNum); + else if (T3(spriteNum) == (T2(spriteNum)>>3)) + A_PlaySound(LIGHTNING_SLAP,spriteNum); + else if (T3(spriteNum) == (T2(spriteNum)>>2)) + { + for (SPRITES_OF(STAT_DEFAULT, j)) + if (sprite[j].picnum == NATURALLIGHTNING && sprite[j].hitag == pSprite->hitag) + sprite[j].cstat |= 32768; + } + else if (T3(spriteNum) > (T2(spriteNum)>>3) && T3(spriteNum) < (T2(spriteNum)>>2)) + { + if (cansee(pSprite->x,pSprite->y,pSprite->z,pSprite->sectnum,g_player[screenpeek].ps->pos.x,g_player[screenpeek].ps->pos.y,g_player[screenpeek].ps->pos.z,g_player[screenpeek].ps->cursectnum)) + j = 1; + else j = 0; + + if (rnd(192) && (T3(spriteNum)&1)) + { + if (j) + g_player[screenpeek].ps->visibility = 0; + } + else if (j) + g_player[screenpeek].ps->visibility = ud.const_visibility; + + for (SPRITES_OF(STAT_DEFAULT, j)) + { + if (sprite[j].picnum == NATURALLIGHTNING && sprite[j].hitag == pSprite->hitag) + { + if (rnd(32) && (T3(spriteNum)&1)) + { + int32_t p; + DukePlayer_t *ps; + + sprite[j].cstat &= 32767; + A_Spawn(j,SMALLSMOKE); + + p = A_FindPlayer(pSprite, NULL); + ps = g_player[p].ps; + + x = ldist(&sprite[ps->i], &sprite[j]); + if (x < 768) + { + if (!A_CheckSoundPlaying(ps->i,DUKE_LONGTERM_PAIN)) + A_PlaySound(DUKE_LONGTERM_PAIN,ps->i); + A_PlaySound(SHORT_CIRCUIT,ps->i); + sprite[ps->i].extra -= 8+(krand2()&7); + + P_PalFrom(ps, 32, 16,0,0); + } + break; + } + else sprite[j].cstat |= 32768; + } + } + } + } + break; + } + + case SE_29_WAVES: + pSprite->hitag += 64; + l = mulscale12((int32_t)pSprite->yvel,sintable[pSprite->hitag&2047]); + pSector->floorz = pSprite->z + l; + break; + + case SE_31_FLOOR_RISE_FALL: // True Drop Floor + if (pData[0] == 1) + { + // Choose dir + + if (!RR && pData[3] > 0) + { + pData[3]--; + break; + } + + if (pData[2] == 1) // Retract + { + if (SA(spriteNum) != 1536) + HandleSE31(spriteNum, 1, pSprite->z, 0, pSprite->z-pSector->floorz); + else + HandleSE31(spriteNum, 1, pData[1], 0, pData[1]-pSector->floorz); + + Yax_SetBunchZs(pSector-sector, YAX_FLOOR, pSector->floorz); + + break; + } + + if ((pSprite->ang&2047) == 1536) + HandleSE31(spriteNum, 0, pSprite->z, 1, pSprite->z-pSector->floorz); + else + HandleSE31(spriteNum, 0, pData[1], 1, pData[1]-pSprite->z); + + Yax_SetBunchZs(pSector-sector, YAX_FLOOR, pSector->floorz); + } + break; + + case SE_32_CEILING_RISE_FALL: // True Drop Ceiling + if (pData[0] == 1) + { + // Choose dir + + if (pData[2] == 1) // Retract + { + if (SA(spriteNum) != 1536) + { + if (klabs(pSector->ceilingz - pSprite->z) < (SP(spriteNum)<<1)) + { + pSector->ceilingz = pSprite->z; + A_CallSound(pSprite->sectnum,spriteNum); + pData[2] = 0; + pData[0] = 0; + } + else pSector->ceilingz += ksgn(pSprite->z-pSector->ceilingz)*SP(spriteNum); + } + else + { + if (klabs(pSector->ceilingz - pData[1]) < (SP(spriteNum)<<1)) + { + pSector->ceilingz = pData[1]; + A_CallSound(pSprite->sectnum,spriteNum); + pData[2] = 0; + pData[0] = 0; + } + else pSector->ceilingz += ksgn(pData[1]-pSector->ceilingz)*SP(spriteNum); + } + + Yax_SetBunchZs(pSector-sector, YAX_CEILING, pSector->ceilingz); + + break; + } + + if ((pSprite->ang&2047) == 1536) + { + if (klabs(pSector->ceilingz-pSprite->z) < (SP(spriteNum)<<1)) + { + pData[0] = 0; + pData[2] = !pData[2]; + A_CallSound(pSprite->sectnum,spriteNum); + pSector->ceilingz = pSprite->z; + } + else pSector->ceilingz += ksgn(pSprite->z-pSector->ceilingz)*SP(spriteNum); + } + else + { + if (klabs(pSector->ceilingz-pData[1]) < (SP(spriteNum)<<1)) + { + pData[0] = 0; + pData[2] = !pData[2]; + A_CallSound(pSprite->sectnum,spriteNum); + } + else pSector->ceilingz -= ksgn(pSprite->z-pData[1])*SP(spriteNum); + } + + Yax_SetBunchZs(pSector-sector, YAX_CEILING, pSector->ceilingz); + } + break; + + case SE_33_QUAKE_DEBRIS: + if (g_earthquakeTime > 0 && (krand2()&7) == 0) + RANDOMSCRAP(pSprite, spriteNum); + break; + + case SE_36_PROJ_SHOOTER: + if (pData[0]) + { + if (pData[0] == 1) + A_Shoot(spriteNum,pSector->extra); + else if (pData[0] == GAMETICSPERSEC*5) + pData[0] = 0; + pData[0]++; + } + break; + + case 128: //SE to control glass breakage + { + walltype *pWall = &wall[pData[2]]; + + if (pWall->cstat|32) + { + pWall->cstat &= (255-32); + pWall->cstat |= 16; + if (pWall->nextwall >= 0) + { + wall[pWall->nextwall].cstat &= (255-32); + wall[pWall->nextwall].cstat |= 16; + } + } + else break; + + pWall->overpicnum++; + if (pWall->nextwall >= 0) + wall[pWall->nextwall].overpicnum++; + + if (pData[0] < pData[1]) pData[0]++; + else + { + pWall->cstat &= (128+32+8+4+2); + if (pWall->nextwall >= 0) + wall[pWall->nextwall].cstat &= (128+32+8+4+2); + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + } + break; + + case SE_130: + if (pData[0] > 80) + { + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else pData[0]++; + + x = pSector->floorz-pSector->ceilingz; + + if (rnd(64)) + { + k = A_Spawn(spriteNum,EXPLOSION2); + sprite[k].xrepeat = sprite[k].yrepeat = 2+(krand2()&7); + sprite[k].z = pSector->floorz-(krand2()%x); + sprite[k].ang += 256-(krand2()%511); + sprite[k].xvel = krand2()&127; + A_SetSprite(k,CLIPMASK0); + } + break; + + case SE_131: + if (pData[0] > 40) + { + DELETE_SPRITE_AND_CONTINUE(spriteNum); + } + else pData[0]++; + + x = pSector->floorz-pSector->ceilingz; + + if (rnd(32)) + { + k = A_Spawn(spriteNum,EXPLOSION2); + sprite[k].xrepeat = sprite[k].yrepeat = 2+(krand2()&3); + sprite[k].z = pSector->floorz-(krand2()%x); + sprite[k].ang += 256-(krand2()%511); + sprite[k].xvel = krand2()&127; + A_SetSprite(k,CLIPMASK0); + } + break; + + case SE_49_POINT_LIGHT: + case SE_50_SPOT_LIGHT: + changespritestat(spriteNum, STAT_LIGHT); + break; + } +next_sprite: + spriteNum = nextSprite; + } + + //Sloped sin-wave floors! + for (SPRITES_OF(STAT_EFFECTOR, spriteNum)) + { + const spritetype *s = &sprite[spriteNum]; + + if (s->lotag == SE_29_WAVES) + { + usectortype const *const sc = (usectortype *)§or[s->sectnum]; + + if (sc->wallnum == 4) + { + walltype *const pWall = &wall[sc->wallptr+2]; + if (pWall->nextsector >= 0) + alignflorslope(s->sectnum, pWall->x,pWall->y, sector[pWall->nextsector].floorz); + } + } + } +} + +static void G_DoEffectorLights(void) // STATNUM 14 +{ +#ifdef POLYMER + int32_t i; + + for (SPRITES_OF(STAT_LIGHT, i)) + { + switch (sprite[i].lotag) + { + case SE_49_POINT_LIGHT: + { + if (!A_CheckSpriteFlags(i, SFLAG_NOLIGHT) && videoGetRenderMode() == REND_POLYMER && + !(A_CheckSpriteFlags(i, SFLAG_USEACTIVATOR) && sector[sprite[i].sectnum].lotag & 16384)) + { + if (actor[i].lightptr == NULL) + { +#pragma pack(push,1) + _prlight mylight; +#pragma pack(pop) + mylight.sector = SECT(i); + Bmemcpy(&mylight, &sprite[i], sizeof(int32_t) * 3); + mylight.range = SHT(i); + mylight.color[0] = sprite[i].xvel; + mylight.color[1] = sprite[i].yvel; + mylight.color[2] = sprite[i].zvel; + mylight.radius = 0; + mylight.angle = SA(i); + mylight.horiz = SH(i); + mylight.minshade = sprite[i].xoffset; + mylight.maxshade = sprite[i].yoffset; + mylight.tilenum = 0; + mylight.publicflags.emitshadow = 0; + mylight.publicflags.negative = !!(CS(i) & 128); + + if (CS(i) & 2) + { + if (CS(i) & 512) + mylight.priority = PR_LIGHT_PRIO_LOW; + else + mylight.priority = PR_LIGHT_PRIO_HIGH; + } + else + mylight.priority = PR_LIGHT_PRIO_MAX; + + actor[i].lightId = polymer_addlight(&mylight); + if (actor[i].lightId >= 0) + actor[i].lightptr = &prlights[actor[i].lightId]; + break; + } + + if (Bmemcmp(&sprite[i], actor[i].lightptr, sizeof(int32_t) * 3)) + { + Bmemcpy(actor[i].lightptr, &sprite[i], sizeof(int32_t) * 3); + actor[i].lightptr->sector = sprite[i].sectnum; + actor[i].lightptr->flags.invalidate = 1; + } + if (SHT(i) != actor[i].lightptr->range) + { + actor[i].lightptr->range = SHT(i); + actor[i].lightptr->flags.invalidate = 1; + } + if ((sprite[i].xvel != actor[i].lightptr->color[0]) || + (sprite[i].yvel != actor[i].lightptr->color[1]) || + (sprite[i].zvel != actor[i].lightptr->color[2])) + { + actor[i].lightptr->color[0] = sprite[i].xvel; + actor[i].lightptr->color[1] = sprite[i].yvel; + actor[i].lightptr->color[2] = sprite[i].zvel; + } + if ((int)!!(CS(i) & 128) != actor[i].lightptr->publicflags.negative) { + actor[i].lightptr->publicflags.negative = !!(CS(i) & 128); + } + } + break; + } + case SE_50_SPOT_LIGHT: + { + if (!A_CheckSpriteFlags(i, SFLAG_NOLIGHT) && videoGetRenderMode() == REND_POLYMER && + !(A_CheckSpriteFlags(i, SFLAG_USEACTIVATOR) && sector[sprite[i].sectnum].lotag & 16384)) + { + if (actor[i].lightptr == NULL) + { +#pragma pack(push,1) + _prlight mylight; +#pragma pack(pop) + + mylight.sector = SECT(i); + Bmemcpy(&mylight, &sprite[i], sizeof(int32_t) * 3); + mylight.range = SHT(i); + mylight.color[0] = sprite[i].xvel; + mylight.color[1] = sprite[i].yvel; + mylight.color[2] = sprite[i].zvel; + mylight.radius = (256-(SS(i)+128))<<1; + mylight.faderadius = (int16_t)(mylight.radius * 0.75f); + mylight.angle = SA(i); + mylight.horiz = SH(i); + mylight.minshade = sprite[i].xoffset; + mylight.maxshade = sprite[i].yoffset; + mylight.tilenum = actor[i].picnum; + mylight.publicflags.emitshadow = !(CS(i) & 64); + mylight.publicflags.negative = !!(CS(i) & 128); + + if (CS(i) & 2) + { + if (CS(i) & 512) + mylight.priority = PR_LIGHT_PRIO_LOW; + else + mylight.priority = PR_LIGHT_PRIO_HIGH; + } + else + mylight.priority = PR_LIGHT_PRIO_MAX; + + actor[i].lightId = polymer_addlight(&mylight); + if (actor[i].lightId >= 0) + { + actor[i].lightptr = &prlights[actor[i].lightId]; + + // Hack in case polymer_addlight tweaked the horiz value + if (actor[i].lightptr->horiz != SH(i)) + SH(i) = actor[i].lightptr->horiz; + } + break; + } + + if (Bmemcmp(&sprite[i], actor[i].lightptr, sizeof(int32_t) * 3)) + { + Bmemcpy(actor[i].lightptr, &sprite[i], sizeof(int32_t) * 3); + actor[i].lightptr->sector = sprite[i].sectnum; + actor[i].lightptr->flags.invalidate = 1; + } + if (SHT(i) != actor[i].lightptr->range) + { + actor[i].lightptr->range = SHT(i); + actor[i].lightptr->flags.invalidate = 1; + } + if ((sprite[i].xvel != actor[i].lightptr->color[0]) || + (sprite[i].yvel != actor[i].lightptr->color[1]) || + (sprite[i].zvel != actor[i].lightptr->color[2])) + { + actor[i].lightptr->color[0] = sprite[i].xvel; + actor[i].lightptr->color[1] = sprite[i].yvel; + actor[i].lightptr->color[2] = sprite[i].zvel; + } + if (((256-(SS(i)+128))<<1) != actor[i].lightptr->radius) + { + actor[i].lightptr->radius = (256-(SS(i)+128))<<1; + actor[i].lightptr->faderadius = (int16_t)(actor[i].lightptr->radius * 0.75f); + actor[i].lightptr->flags.invalidate = 1; + } + if (SA(i) != actor[i].lightptr->angle) + { + actor[i].lightptr->angle = SA(i); + actor[i].lightptr->flags.invalidate = 1; + } + if (SH(i) != actor[i].lightptr->horiz) + { + actor[i].lightptr->horiz = SH(i); + actor[i].lightptr->flags.invalidate = 1; + } + if ((int)!(CS(i) & 64) != actor[i].lightptr->publicflags.emitshadow) { + actor[i].lightptr->publicflags.emitshadow = !(CS(i) & 64); + } + if ((int)!!(CS(i) & 128) != actor[i].lightptr->publicflags.negative) { + actor[i].lightptr->publicflags.negative = !!(CS(i) & 128); + } + actor[i].lightptr->tilenum = actor[i].picnum; + } + + break; + } + } + } +#endif // POLYMER +} + +#ifdef POLYMER +static void A_DoLight(int spriteNum) +{ + spritetype *const pSprite = &sprite[spriteNum]; + int savedFires = 0; + + if (((sector[pSprite->sectnum].floorz - sector[pSprite->sectnum].ceilingz) < 16) || pSprite->z > sector[pSprite->sectnum].floorz || pSprite->z > actor[spriteNum].floorz || + (pSprite->picnum != SECTOREFFECTOR && ((pSprite->cstat & 32768) || pSprite->yrepeat < 4)) || + A_CheckSpriteFlags(spriteNum, SFLAG_NOLIGHT) || (A_CheckSpriteFlags(spriteNum, SFLAG_USEACTIVATOR) && sector[pSprite->sectnum].lotag & 16384)) + { + if (actor[spriteNum].lightptr != NULL) + A_DeleteLight(spriteNum); + } + else + { + if (actor[spriteNum].lightptr != NULL && actor[spriteNum].lightcount) + { + if (!(--actor[spriteNum].lightcount)) + A_DeleteLight(spriteNum); + } + + if (pr_lighting != 1) + return; + + for (bsize_t ii=0; ii<2; ii++) + { + if (pSprite->picnum <= 0) // oob safety + break; + + switch (DYNAMICTILEMAP(pSprite->picnum-1+ii)) + { + case DIPSWITCH__STATIC: + case DIPSWITCH2__STATIC: + case DIPSWITCH3__STATIC: + case PULLSWITCH__STATIC: + case SLOTDOOR__STATIC: + case LIGHTSWITCH__STATIC: + case SPACELIGHTSWITCH__STATIC: + case SPACEDOORSWITCH__STATIC: + case FRANKENSTINESWITCH__STATIC: + case POWERSWITCH1__STATIC: + case LOCKSWITCH1__STATIC: + case POWERSWITCH2__STATIC: + case TECHSWITCH__STATIC: + case ACCESSSWITCH__STATIC: + case ACCESSSWITCH2__STATIC: + { + if ((pSprite->cstat & 32768) || A_CheckSpriteFlags(spriteNum, SFLAG_NOLIGHT)) + { + if (actor[spriteNum].lightptr != NULL) + A_DeleteLight(spriteNum); + break; + } + + vec2_t const d = { sintable[(pSprite->ang+512)&2047]>>7, sintable[(pSprite->ang)&2047]>>7 }; + + pSprite->x += d.x; + pSprite->y += d.y; + + int16_t sectnum = pSprite->sectnum; + updatesector(pSprite->x, pSprite->y, §num); + + if ((unsigned) sectnum >= MAXSECTORS || pSprite->z > sector[sectnum].floorz || pSprite->z < sector[sectnum].ceilingz) + goto POOP; + + G_AddGameLight(0, spriteNum, (pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1, 512-ii*128, + ii==0 ? (172+(200<<8)+(104<<16)) : 216+(52<<8)+(20<<16), PR_LIGHT_PRIO_LOW); + + POOP: + pSprite->x -= d.x; + pSprite->y -= d.y; + } + break; + } + } + + switch (DYNAMICTILEMAP(pSprite->picnum)) + { + case ATOMICHEALTH__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD2(spriteNum, pSprite), 128+(128<<8)+(255<<16),PR_LIGHT_PRIO_HIGH_GAME); + break; + + case FIRE__STATIC: + case FIRE2__STATIC: + case BURNING__STATIC: + case BURNING2__STATIC: + { + uint32_t color; + int32_t jj; + + static int32_t savedfires[32][4]; // sectnum x y z + + /* + if (Actor[i].floorz - Actor[i].ceilingz < 128) break; + if (s->z > Actor[i].floorz+2048) break; + */ + + switch (pSprite->pal) + { + case 1: color = 128+(128<<8)+(255<<16); break; + case 2: color = 255+(48<<8)+(48<<16); break; + case 8: color = 48+(255<<8)+(48<<16); break; + default: color = 240+(160<<8)+(80<<16); break; + } + + for (jj=savedFires-1; jj>=0; jj--) + if (savedfires[jj][0]==pSprite->sectnum && savedfires[jj][1]==(pSprite->x>>3) && + savedfires[jj][2]==(pSprite->y>>3) && savedfires[jj][3]==(pSprite->z>>7)) + break; + + if (jj==-1 && savedFires<32) + { + jj = savedFires; + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD2(spriteNum, pSprite), color, PR_LIGHT_PRIO_HIGH_GAME); + savedfires[jj][0] = pSprite->sectnum; + savedfires[jj][1] = pSprite->x>>3; + savedfires[jj][2] = pSprite->y>>3; + savedfires[jj][3] = pSprite->z>>7; + savedFires++; + } + } + break; + + case OOZFILTER__STATIC: + if (pSprite->xrepeat > 4) + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 4096, 176+(252<<8)+(120<<16),PR_LIGHT_PRIO_HIGH_GAME); + break; + case FLOORFLAME__STATIC: + case FIREBARREL__STATIC: + case FIREVASE__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<2), LIGHTRAD2(spriteNum, pSprite)>>1, 255+(95<<8),PR_LIGHT_PRIO_HIGH_GAME); + break; + + case EXPLOSION2__STATIC: + if (!actor[spriteNum].lightcount) + { + // XXX: This block gets CODEDUP'd too much. + int32_t x = ((sintable[(pSprite->ang+512)&2047])>>6); + int32_t y = ((sintable[(pSprite->ang)&2047])>>6); + + pSprite->x -= x; + pSprite->y -= y; + + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite), 240+(160<<8)+(80<<16), + pSprite->yrepeat > 32 ? PR_LIGHT_PRIO_HIGH_GAME : PR_LIGHT_PRIO_LOW_GAME); + + pSprite->x += x; + pSprite->y += y; + } + break; + case FORCERIPPLE__STATIC: + case TRANSPORTERBEAM__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite), 80+(80<<8)+(255<<16),PR_LIGHT_PRIO_LOW_GAME); + break; + case GROWSPARK__STATIC: + { + int32_t x = ((sintable[(pSprite->ang+512)&2047])>>6); + int32_t y = ((sintable[(pSprite->ang)&2047])>>6); + + pSprite->x -= x; + pSprite->y -= y; + + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 1024, 216+(52<<8)+(20<<16),PR_LIGHT_PRIO_HIGH_GAME); + + pSprite->x += x; + pSprite->y += y; + } + break; + case SHRINKEREXPLOSION__STATIC: + { + int32_t x = ((sintable[(pSprite->ang+512)&2047])>>6); + int32_t y = ((sintable[(pSprite->ang)&2047])>>6); + + pSprite->x -= x; + pSprite->y -= y; + + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 2048, 176+(252<<8)+(120<<16),PR_LIGHT_PRIO_HIGH_GAME); + + pSprite->x += x; + pSprite->y += y; + } + break; + case FREEZEBLAST__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite)<<2, 72+(88<<8)+(140<<16),PR_LIGHT_PRIO_HIGH_GAME); + break; + case COOLEXPLOSION1__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite)<<2, 128+(0<<8)+(255<<16),PR_LIGHT_PRIO_HIGH_GAME); + break; + case SHRINKSPARK__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), LIGHTRAD(spriteNum, pSprite), 176+(252<<8)+(120<<16),PR_LIGHT_PRIO_HIGH_GAME); + break; + case FIRELASER__STATIC: + if (pSprite->statnum == STAT_PROJECTILE) + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 64 * pSprite->yrepeat, 255+(95<<8),PR_LIGHT_PRIO_LOW_GAME); + break; + case RPG__STATIC: + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 128 * pSprite->yrepeat, 255+(95<<8),PR_LIGHT_PRIO_LOW_GAME); + break; + case SHOTSPARK1__STATIC: + if (actor[spriteNum].t_data[2] == 0) // check for first frame of action + { + int32_t x = ((sintable[(pSprite->ang+512)&2047])>>7); + int32_t y = ((sintable[(pSprite->ang)&2047])>>7); + + pSprite->x -= x; + pSprite->y -= y; + + G_AddGameLight(0, spriteNum, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 8 * pSprite->yrepeat, 240+(160<<8)+(80<<16),PR_LIGHT_PRIO_LOW_GAME); + actor[spriteNum].lightcount = 1; + + pSprite->x += x; + pSprite->y += y; + } + break; + } + } +} +#endif // POLYMER + +void A_PlayAlertSound(int spriteNum) +{ + if (DEER) + return; + if (RR) + { + if (sprite[spriteNum].extra > 0) + { + switch (DYNAMICTILEMAP(PN(spriteNum))) + { + case COOT__STATICRR: if (!RRRA || (krand2()&3) == 2) A_PlaySound(PRED_RECOG, spriteNum); break; + case LTH__STATICRR: break; + case BILLYCOCK__STATICRR: + case BILLYRAY__STATICRR: + case BRAYSNIPER__STATICRR: A_PlaySound(PIG_RECOG, spriteNum); break; + case DOGRUN__STATICRR: + case HULK__STATICRR: + case HEN__STATICRR: + case DRONE__STATICRR: + case PIG__STATICRR: + case RECON__STATICRR: + case MINION__STATICRR: + case COW__STATICRR: + case VIXEN__STATICRR: + case RABBIT__STATICRR: break; + } + } + return; + } + if (sprite[spriteNum].extra > 0) + { + switch (DYNAMICTILEMAP(PN(spriteNum))) + { + case LIZTROOPONTOILET__STATIC: + case LIZTROOPJUSTSIT__STATIC: + case LIZTROOPSHOOT__STATIC: + case LIZTROOPJETPACK__STATIC: + case LIZTROOPDUCKING__STATIC: + case LIZTROOPRUNNING__STATIC: + case LIZTROOP__STATIC: A_PlaySound(PRED_RECOG, spriteNum); break; + case LIZMAN__STATIC: + case LIZMANSPITTING__STATIC: + case LIZMANFEEDING__STATIC: + case LIZMANJUMP__STATIC: A_PlaySound(CAPT_RECOG, spriteNum); break; + case PIGCOP__STATIC: + case PIGCOPDIVE__STATIC: A_PlaySound(PIG_RECOG, spriteNum); break; + case RECON__STATIC: A_PlaySound(RECO_RECOG, spriteNum); break; + case DRONE__STATIC: A_PlaySound(DRON_RECOG, spriteNum); break; + case COMMANDER__STATIC: + case COMMANDERSTAYPUT__STATIC: A_PlaySound(COMM_RECOG, spriteNum); break; + case ORGANTIC__STATIC: A_PlaySound(TURR_RECOG, spriteNum); break; + case OCTABRAIN__STATIC: + case OCTABRAINSTAYPUT__STATIC: A_PlaySound(OCTA_RECOG, spriteNum); break; + case BOSS1__STATIC: S_PlaySound(BOS1_RECOG); break; + case BOSS2__STATIC: S_PlaySound((sprite[spriteNum].pal == 1) ? BOS2_RECOG : WHIPYOURASS); break; + case BOSS3__STATIC: S_PlaySound((sprite[spriteNum].pal == 1) ? BOS3_RECOG : RIPHEADNECK); break; + case BOSS4__STATIC: + case BOSS4STAYPUT__STATIC: if (sprite[spriteNum].pal == 1) S_PlaySound(BOS4_RECOG); S_PlaySound(BOSS4_FIRSTSEE); break; + case GREENSLIME__STATIC: A_PlaySound(SLIM_RECOG, spriteNum); break; + } + } +} + +int A_CheckSwitchTile(int spriteNum) +{ + // picnum 0 would oob in the switch below, + + if (PN(spriteNum) <= 0) + return 0; + + // MULTISWITCH has 4 states so deal with it separately, + // ACCESSSWITCH and ACCESSSWITCH2 are only active in one state so deal with + // them separately. + + if ((PN(spriteNum) >= MULTISWITCH && PN(spriteNum) <= MULTISWITCH + 3) || (PN(spriteNum) == ACCESSSWITCH || PN(spriteNum) == ACCESSSWITCH2)) + return 1; + + if (RRRA && PN(spriteNum) >= MULTISWITCH2 && PN(spriteNum) <= MULTISWITCH2 + 3) + return 1; + + // Loop to catch both states of switches. + for (bssize_t j=1; j>=0; j--) + { + switch (DYNAMICTILEMAP(PN(spriteNum)-j)) + { + case RRTILE8464__STATICRR: + if (RRRA) return 1; + break; + case NUKEBUTTON__STATIC: + if (RR) return 1; + break; + case HANDPRINTSWITCH__STATIC: + case ALIENSWITCH__STATIC: + case MULTISWITCH__STATIC: + case PULLSWITCH__STATIC: + case HANDSWITCH__STATIC: + case SLOTDOOR__STATIC: + case LIGHTSWITCH__STATIC: + case SPACELIGHTSWITCH__STATIC: + case SPACEDOORSWITCH__STATIC: + case FRANKENSTINESWITCH__STATIC: + case LIGHTSWITCH2__STATIC: + case POWERSWITCH1__STATIC: + case LOCKSWITCH1__STATIC: + case POWERSWITCH2__STATIC: + case DIPSWITCH__STATIC: + case DIPSWITCH2__STATIC: + case TECHSWITCH__STATIC: + case DIPSWITCH3__STATIC: + return 1; + } + } + + return 0; +} + +void G_RefreshLights(void) +{ +#ifdef POLYMER + if (Numsprites && videoGetRenderMode() == REND_POLYMER) + { + int statNum = 0; + + do + { + int spriteNum = headspritestat[statNum++]; + + while (spriteNum >= 0) + { + A_DoLight(spriteNum); + spriteNum = nextspritestat[spriteNum]; + } + } + while (statNum < MAXSTATUS); + } +#endif +} + +void G_MoveWorld(void) +{ + extern double g_moveActorsTime, g_moveWorldTime; + const double worldTime = timerGetHiTicks(); + + if (!DEER) + { + G_MoveZombieActors(); //ST 2 + G_MoveWeapons(); //ST 4 + G_MoveTransports(); //ST 9 + } + + G_MovePlayers(); //ST 10 + G_MoveFallers(); //ST 12 + if (!DEER) + G_MoveMisc(); //ST 5 + + const double actorsTime = timerGetHiTicks(); + + G_MoveActors(); //ST 1 + + g_moveActorsTime = (1-0.033)*g_moveActorsTime + 0.033*(timerGetHiTicks()-actorsTime); + + if (DEER) + { + sub_56EA8(); + ghtarget_move(); + gharrow_move(); + ghdeploy_move(); + sub_519E8(ud.level_number); + sub_5524C(); + } + + // XXX: Has to be before effectors, in particular movers? + // TODO: lights in moving sectors ought to be interpolated + G_DoEffectorLights(); + if (!DEER) + { + G_MoveEffectors(); //ST 3 + G_MoveStandables(); //ST 6 + } + + G_RefreshLights(); + G_DoSectorAnimations(); + if (!DEER) + G_MoveFX(); //ST 11 + + if (RR && numplayers < 2 && g_thunderOn) + G_Thunder(); + + g_moveWorldTime = (1-0.033)*g_moveWorldTime + 0.033*(timerGetHiTicks()-worldTime); +} + +END_DUKE_NS diff --git a/source/duke/src/actors.h b/source/duke/src/actors.h new file mode 100644 index 000000000..f3e50906f --- /dev/null +++ b/source/duke/src/actors.h @@ -0,0 +1,340 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef actors_h_ +#define actors_h_ + +#include "player.h" +# include "namesdyn.h" + +BEGIN_DUKE_NS + +#define MAXSLEEPDIST 16384 +#define SLEEPTIME 1536 +#define ZOFFSET (1<<8) +#define ZOFFSET2 (16<<8) +#define ZOFFSET3 (8<<8) +#define ZOFFSET4 (12<<8) +#define ZOFFSET5 (32<<8) +#define ZOFFSET6 (4<<8) + +#define ACTOR_MAXFALLINGZVEL 6144 +#define ACTOR_ONWATER_ADDZ (24<<8) + +#define STAT_DEFAULT 0 +#define STAT_ACTOR 1 +#define STAT_ZOMBIEACTOR 2 +#define STAT_EFFECTOR 3 +#define STAT_PROJECTILE 4 +#define STAT_MISC 5 +#define STAT_STANDABLE 6 +#define STAT_LOCATOR 7 +#define STAT_ACTIVATOR 8 +#define STAT_TRANSPORT 9 +#define STAT_PLAYER 10 +#define STAT_FX 11 +#define STAT_FALLER 12 +#define STAT_DUMMYPLAYER 13 +#define STAT_LIGHT 14 +#define STAT_RAROR 15 +#define STAT_NETALLOC MAXSTATUS-1 + + +// Defines the motion characteristics of an actor +enum amoveflags_t +{ + face_player = 1, + geth = 2, + getv = 4, + random_angle = 8, + face_player_slow = 16, + spin = 32, + face_player_smart = 64, + fleeenemy = 128, + jumptoplayer_only = 256, + jumptoplayer_bits = 257, // NOTE: two bits set! + seekplayer = 512, + furthestdir = 1024, + dodgebullet = 4096, + justjump2 = 8192, + windang = 16384, + antifaceplayerslow = 32768 +}; + +// Defines for 'useractor' keyword +enum uactortypes_t +{ + notenemy, + enemy, + enemystayput +}; + +// These macros are there to give names to the t_data[]/T*/vm.g_t[] indices +// when used with actors. Greppability of source code is certainly a virtue. +#define AC_COUNT(t) ((t)[0]) /* the actor's count */ +/* The ID of the actor's current move. In C-CON, the bytecode offset to the + * move composite: */ +#define AC_MOVE_ID(t) ((t)[1]) +#define AC_ACTION_COUNT(t) ((t)[2]) /* the actor's action count */ +#define AC_CURFRAME(t) ((t)[3]) /* the actor's current frame offset */ +/* The ID of the actor's current action. In C-CON, the bytecode offset to the + * action composite: */ +#define AC_ACTION_ID(t) ((t)[4]) +#define AC_AI_ID(t) ((t)[5]) /* the ID of the actor's current ai */ + +enum actionparams +{ + ACTION_STARTFRAME = 0, + ACTION_NUMFRAMES, + ACTION_VIEWTYPE, + ACTION_INCVAL, + ACTION_DELAY, + ACTION_FLAGS, + ACTION_PARAM_COUNT, +}; + +enum actionflags +{ + AF_VIEWPOINT = 1u<<0u, +}; + +// : sprite pointer +// : actor_t pointer +# define AC_ACTIONTICS(spr, a) ((spr)->lotag) +# define AC_MOVFLAGS(spr, a) ((spr)->hitag) + +// (+ 40 16 16 4 8 6 8 6 4 20) +#pragma pack(push, 1) +typedef struct +{ + int32_t t_data[10]; // 40b sometimes used to hold offsets to con code + + int32_t flags; // 4b + vec3_t bpos; // 12b + int32_t floorz, ceilingz; // 8b + vec2_t lastv; // 8b + int16_t picnum, ang, extra, owner; // 8b + int16_t movflag, tempang, timetosleep; // 6b + int16_t actorstayput; // 2b + + uint8_t cgg, lasttransport; // 2b + // NOTE: 'dispicnum' is updated every frame, not in sync with game tics! + int16_t dispicnum; // 2b + +#ifdef POLYMER + int16_t lightId, lightmaxrange; // 4b + _prlight *lightptr; // 4b/8b aligned on 96 bytes + uint8_t lightcount, filler[3]; +#endif +} actor_t; + +// this struct needs to match the beginning of actor_t above +typedef struct +{ + int32_t t_data[10]; // 40b sometimes used to hold offsets to con code + + int32_t flags; // 4b + vec3_t bpos; // 12b + int32_t floorz, ceilingz; // 8b + vec2_t lastv; // 8b + int16_t picnum, ang, extra, owner; // 8b + int16_t movflag, tempang, timetosleep; // 6b + int16_t actorstayput; + + uint8_t cgg, lasttransport; + + spritetype sprite; + int16_t netIndex; +} netactor_t; +#pragma pack(pop) + +typedef struct +{ + intptr_t *execPtr; // pointer to CON script for this tile, formerly actorscrptr + intptr_t *loadPtr; // pointer to load time CON script, formerly actorLoadEventScrPtr or something + uint32_t flags; // formerly SpriteFlags, ActorType + int32_t cacherange; // formerly SpriteCache +} tiledata_t; + + +enum sflags_t +{ + SFLAG_SHADOW = 0x00000001, + SFLAG_NVG = 0x00000002, + SFLAG_NOSHADE = 0x00000004, + SFLAG_PROJECTILE = 0x00000008, + SFLAG_DECAL = 0x00000010, + SFLAG_BADGUY = 0x00000020, + SFLAG_NOPAL = 0x00000040, + SFLAG_NOEVENTCODE = 0x00000080, + SFLAG_NOLIGHT = 0x00000100, + SFLAG_USEACTIVATOR = 0x00000200, + SFLAG_NULL = 0x00000400, // null sprite in multiplayer + SFLAG_NOCLIP = 0x00000800, // clipmove it with cliptype 0 + SFLAG_NOFLOORSHADOW = 0x00001000, // for temp. internal use, per-tile flag not checked + SFLAG_SMOOTHMOVE = 0x00002000, + SFLAG_NOTELEPORT = 0x00004000, + SFLAG_BADGUYSTAYPUT = 0x00008000, + SFLAG_CACHE = 0x00010000, + // rotation-fixed wrt a pivot point to prevent position diverging due to + // roundoff error accumulation: + SFLAG_ROTFIXED = 0x00020000, + SFLAG_HARDCODED_BADGUY = 0x00040000, + SFLAG_DIDNOSE7WATER = 0x00080000, // used temporarily + SFLAG_NODAMAGEPUSH = 0x00100000, + SFLAG_NOWATERDIP = 0x00200000, + SFLAG_HURTSPAWNBLOOD = 0x00400000, + SFLAG_GREENSLIMEFOOD = 0x00800000, + SFLAG_REALCLIPDIST = 0x01000000, + SFLAG_WAKEUPBADGUYS = 0x02000000, + SFLAG_DAMAGEEVENT = 0x04000000, + SFLAG_BADGUY_TILE = 0x08000000, + SFLAG_KILLCOUNT = 0x10000000, + SFLAG_NOCANSEECHECK = 0x20000000, +}; + +// Custom projectiles "workslike" flags. +// XXX: Currently not predefined from CON. +enum pflags_t +{ + PROJECTILE_HITSCAN = 0x00000001, + PROJECTILE_RPG = 0x00000002, + PROJECTILE_BOUNCESOFFWALLS = 0x00000004, + PROJECTILE_BOUNCESOFFMIRRORS = 0x00000008, + PROJECTILE_KNEE = 0x00000010, + PROJECTILE_WATERBUBBLES = 0x00000020, + PROJECTILE_TIMED = 0x00000040, + PROJECTILE_BOUNCESOFFSPRITES = 0x00000080, + PROJECTILE_SPIT = 0x00000100, + PROJECTILE_COOLEXPLOSION1 = 0x00000200, + PROJECTILE_BLOOD = 0x00000400, + PROJECTILE_LOSESVELOCITY = 0x00000800, + PROJECTILE_NOAIM = 0x00001000, + PROJECTILE_RANDDECALSIZE = 0x00002000, + PROJECTILE_EXPLODEONTIMER = 0x00004000, + PROJECTILE_RPG_IMPACT = 0x00008000, + PROJECTILE_RADIUS_PICNUM = 0x00010000, + PROJECTILE_ACCURATE_AUTOAIM = 0x00020000, + PROJECTILE_FORCEIMPACT = 0x00040000, + PROJECTILE_REALCLIPDIST = 0x00080000, + PROJECTILE_ACCURATE = 0x00100000, + PROJECTILE_NOSETOWNERSHADE = 0x00200000, + PROJECTILE_RPG_IMPACT_DAMAGE = 0x00400000, + PROJECTILE_MOVED = 0x80000000, // internal flag, do not document + PROJECTILE_TYPE_MASK = PROJECTILE_HITSCAN | PROJECTILE_RPG | PROJECTILE_KNEE | PROJECTILE_BLOOD, +}; + +extern tiledata_t g_tile[MAXTILES]; +extern actor_t actor[MAXSPRITES]; +extern int32_t block_deletesprite; +extern int32_t g_noEnemies; +extern int32_t otherp; +extern int32_t ticrandomseed; +extern int g_canSeePlayer; + + +int A_CheckNoSE7Water(uspritetype const *pSprite, int sectNum, int sectLotag, int32_t *pOther); +int A_CheckSwitchTile(int spriteNum); +int A_IncurDamage(int spriteNum); +void A_AddToDeleteQueue(int spriteNum); +void A_DeleteSprite(int spriteNum); +void A_DoGuts(int spriteNum, int tileNum, int spawnCnt); +void A_DoGutsDir(int spriteNum, int tileNum, int spawnCnt); +void A_MoveCyclers(void); +void A_MoveDummyPlayers(void); +void A_MoveSector(int spriteNum); +void A_PlayAlertSound(int spriteNum); +void A_RadiusDamage(int spriteNum, int blastRadius, int dmg1, int dmg2, int dmg3, int dmg4); +void A_SpawnMultiple(int spriteNum, int tileNum, int spawnCnt); +void A_ResetLanePics(void); + +int G_SetInterpolation(int32_t *posptr); +void G_AddGameLight(int lightRadius, int spriteNum, int zOffset, int lightRange, int lightColor, int lightPrio); +void G_ClearCameraView(DukePlayer_t *ps); +void G_DoInterpolations(int smoothRatio); +void G_MoveWorld(void); +void G_RefreshLights(void); +void G_StopInterpolation(const int32_t *posptr); + +// PK 20110701: changed input argument: int32_t i (== sprite, whose sectnum...) --> sectnum directly +void Sect_ToggleInterpolation(int sectnum, int setInterpolation); +static FORCE_INLINE void Sect_ClearInterpolation(int sectnum) { Sect_ToggleInterpolation(sectnum, 0); } +static FORCE_INLINE void Sect_SetInterpolation(int sectnum) { Sect_ToggleInterpolation(sectnum, 1); } + +#if KRANDDEBUG +# define ACTOR_INLINE __fastcall +# define ACTOR_INLINE_HEADER extern __fastcall +#else +# define ACTOR_INLINE EXTERN_INLINE +# define ACTOR_INLINE_HEADER EXTERN_INLINE_HEADER +#endif + +extern int32_t A_MoveSprite(int32_t spritenum, vec3_t const * change, uint32_t cliptype); +ACTOR_INLINE_HEADER int A_CheckEnemyTile(int tileNum); +ACTOR_INLINE_HEADER int A_SetSprite(int spriteNum, uint32_t cliptype); + +EXTERN_INLINE_HEADER int G_CheckForSpaceCeiling(int sectnum); +EXTERN_INLINE_HEADER int G_CheckForSpaceFloor(int sectnum); + +EXTERN_INLINE_HEADER int A_CheckEnemySprite(void const * s); + +#if defined actors_c_ || !defined DISABLE_INLINING + +# if !KRANDDEBUG || (KRANDDEBUG && defined actors_c_) + +ACTOR_INLINE int A_CheckEnemyTile(int const tileNum) +{ + return ((g_tile[tileNum].flags & (SFLAG_BADGUY_TILE | SFLAG_BADGUY)) != 0); +} + +ACTOR_INLINE int A_SetSprite(int const spriteNum, uint32_t cliptype) +{ + vec3_t davect = { (sprite[spriteNum].xvel * (sintable[(sprite[spriteNum].ang + 512) & 2047])) >> 14, + (sprite[spriteNum].xvel * (sintable[sprite[spriteNum].ang & 2047])) >> 14, sprite[spriteNum].zvel }; + return (A_MoveSprite(spriteNum, &davect, cliptype) == 0); +} + +# endif + + +EXTERN_INLINE int G_CheckForSpaceCeiling(int const sectnum) +{ + return ((sector[sectnum].ceilingstat&1) && sector[sectnum].ceilingpal == 0 && + (sector[sectnum].ceilingpicnum==MOONSKY1 || sector[sectnum].ceilingpicnum==BIGORBIT1)); +} + +EXTERN_INLINE int G_CheckForSpaceFloor(int const sectnum) +{ + return ((sector[sectnum].floorstat&1) && sector[sectnum].ceilingpal == 0 && + (sector[sectnum].floorpicnum==MOONSKY1 || sector[sectnum].floorpicnum==BIGORBIT1)); +} + +EXTERN_INLINE int A_CheckEnemySprite(void const * const pSprite) +{ + return A_CheckEnemyTile(((uspritetype const *) pSprite)->picnum); +} + +#endif + +END_DUKE_NS + +#endif diff --git a/source/duke/src/anim.cpp b/source/duke/src/anim.cpp new file mode 100644 index 000000000..6d8c398c4 --- /dev/null +++ b/source/duke/src/anim.cpp @@ -0,0 +1,574 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! + +#include "baselayer.h" +#include "baselayer.h" +#include "duke3d.h" +#include "animlib.h" +#include "compat.h" +#include "cmdlib.h" +#include "v_2ddrawer.h" +#include "animtexture.h" +#include "../glbackend/glbackend.h" + + +#include "anim.h" + +#ifdef USE_LIBVPX +# include "animvpx.h" +#endif + +BEGIN_DUKE_NS + +// animsound_t.sound + +TArray g_Animations; +dukeanim_t * g_animPtr; + +dukeanim_t* Anim_Find(const char* s) +{ + auto index = g_Animations.FindEx([=](dukeanim_t& anm) { return !anm.name.CompareNoCase(s); }); + if (index == g_Animations.Size()) + { + FString fname = s; + DefaultExtension(fname, ".anm"); + index = g_Animations.FindEx([=](dukeanim_t& anm) { return !anm.name.CompareNoCase(fname); }); + if (index == g_Animations.Size()) + { + fname = s; + DefaultExtension(fname, ".ivf"); + index = g_Animations.FindEx([=](dukeanim_t& anm) { return !anm.name.CompareNoCase(fname); }); + if (index == g_Animations.Size()) return nullptr; + } + } + return &g_Animations[index]; +} + +dukeanim_t * Anim_Create(char const * fn) +{ + g_Animations.Reserve(1); + auto p = &g_Animations.Last(); + p->name = fn; + return p; +} + +#ifdef DYNSOUNDREMAP_ENABLE +static int32_t const StopAllSounds = -1; +#else +# define StopAllSounds -1 +#endif + +void Anim_Init(void) +{ + struct defaultanmsound { +#ifdef DYNSOUNDREMAP_ENABLE + int32_t const & sound; +#else + int16_t sound; +#endif + uint8_t frame; + }; + + static defaultanmsound const logo[] = + { + { FLY_BY, 1 }, + { PIPEBOMB_EXPLODE, 19 }, + }; + + static defaultanmsound const cineov2[] = + { + { WIND_AMBIENCE, 1 }, + { ENDSEQVOL2SND1, 26 }, + { ENDSEQVOL2SND2, 36 }, + { THUD, 54 }, + { ENDSEQVOL2SND3, 62 }, + { ENDSEQVOL2SND4, 75 }, + { ENDSEQVOL2SND5, 81 }, + { ENDSEQVOL2SND6, 115 }, + { ENDSEQVOL2SND7, 124 }, + }; + + static defaultanmsound const cineov3[] = + { + { WIND_REPEAT, 1 }, + { DUKE_GRUNT, 98 }, + { THUD, 82+20 }, + { SQUISHED, 82+20 }, + { ENDSEQVOL3SND3, 104+20 }, + { ENDSEQVOL3SND2, 114+20 }, + { PIPEBOMB_EXPLODE, 158 }, + }; + + static defaultanmsound const vol42a[] = + { + { INTRO4_B, 1 }, + { SHORT_CIRCUIT, 12 }, + { INTRO4_5, 18 }, + { SHORT_CIRCUIT, 34 }, + }; + + static defaultanmsound const vol41a[] = + { + { INTRO4_1, 1 }, + { INTRO4_3, 7 }, + { INTRO4_2, 12 }, + { INTRO4_4, 26 }, + }; + + static defaultanmsound const vol43a[] = + { + { INTRO4_6, 10 }, + }; + + static defaultanmsound const vol4e1[] = + { + { DUKE_UNDERWATER, 3 }, + { VOL4ENDSND1, 35 }, + }; + + static defaultanmsound const vol4e2[] = + { + { DUKE_UNDERWATER, 11 }, + { VOL4ENDSND1, 20 }, + { VOL4ENDSND2, 39 }, + { StopAllSounds, 50 }, + }; + + static defaultanmsound const vol4e3[] = + { + { BOSS4_DEADSPEECH, 1 }, + { VOL4ENDSND1, 40 }, + { DUKE_UNDERWATER, 40 }, + { BIGBANG, 50 }, + }; + + static defaultanmsound const rr_intro[] = + { + { 29, 1 }, + }; + + static defaultanmsound const redneck[] = + { + { 478, 1 }, + }; + + static defaultanmsound const xatlogo[] = + { + { 479, 1 }, + }; + + static defaultanmsound const turdmov[] = + { + { 82, 1 }, + }; + + static defaultanmsound const rr_outro[] = + { + { 35, 1 }, + }; + + struct defaultanm { + char const *fn; + defaultanmsound const *sounds; + uint8_t numsounds; + uint8_t fdelay; + }; + +#define anmsnd(x) (x), ARRAY_SIZE(x) + static defaultanm const anms[] = + { + { "logo.anm", anmsnd(logo), 9 }, + { "3dr.anm", NULL, 0, 10 }, + { "vol4e1.anm", anmsnd(vol4e1), 10 }, + { "vol4e2.anm", anmsnd(vol4e2), 14 }, + { "vol4e3.anm", anmsnd(vol4e3), 10 }, + { "vol41a.anm", anmsnd(vol41a), 14 }, + { "vol42a.anm", anmsnd(vol42a), 18 }, + { "vol43a.anm", anmsnd(vol43a), 10 }, + { "duketeam.anm", NULL, 0, 10 }, + { "radlogo.anm", NULL, 0, 10 }, + { "cineov2.anm", anmsnd(cineov2), 18 }, + { "cineov3.anm", anmsnd(cineov3), 10 }, + { "rr_intro.anm", anmsnd(rr_intro), 9 }, + { "redneck.anm", anmsnd(redneck), 9 }, + { "xatlogo.anm", anmsnd(xatlogo), 9 }, + { "turdmov.anm", anmsnd(turdmov), 9 }, + { "rr_outro.anm", anmsnd(rr_outro), 9 }, + { "lvl1.anm", NULL, 0, 20 }, + { "lvl2.anm", NULL, 0, 20 }, + { "lvl3.anm", NULL, 0, 20 }, + { "lvl4.anm", NULL, 0, 20 }, + { "lvl5.anm", NULL, 0, 20 }, + { "lvl6.anm", NULL, 0, 20 }, + { "lvl7.anm", NULL, 0, 20 }, + { "lvl8.anm", NULL, 0, 20 }, + { "lvl9.anm", NULL, 0, 20 }, + { "lvl10.anm", NULL, 0, 20 }, + { "lvl11.anm", NULL, 0, 20 }, + { "lvl12.anm", NULL, 0, 20 }, + { "lvl13.anm", NULL, 0, 20 }, + }; +#undef anmsnd + + for (defaultanm const& anm : anms) + { + dukeanim_t* anim = Anim_Create(anm.fn); + anim->framedelay = anm.fdelay; + + if (anm.numsounds) + { + anim->Sounds.Resize(anm.numsounds); + int const numsounds = anm.numsounds; + for (int i = 0; i < numsounds; ++i) + { + defaultanmsound const& src = anm.sounds[i]; + animsound_t& dst = anim->Sounds[i]; + + dst.sound = src.sound; + dst.frame = src.frame; + } + } + + anim->frameflags = 0; + } +} + +int32_t Anim_Play(const char *fn) +{ + dukeanim_t *anim = Anim_Find(fn); + + if (!anim) + { + Printf("Animation %s is undefined!\n", fn); + return 0; + } + + uint16_t soundidx = 0; // custom anim sounds + int32_t running = 1, i; + + inputState.ClearAllInput(); + +#ifdef USE_LIBVPX + uint16_t framenum = 0; + while (videoGetRenderMode() >= REND_POLYMOST) // if, really + { + char const * dot = Bstrrchr(fn, '.'); + if (!dot) + break; + + dukeanim_t const * origanim = anim; + FileReader handle; + if (!Bstrcmp(dot, ".ivf")) + { + handle = fileSystem.OpenFileReader(fn); + if (!handle.isOpen()) + break; + } + else + { + char vpxfn[BMAX_PATH]; + Bstrncpyz(vpxfn, fn, BMAX_PATH); + + ptrdiff_t dotpos = dot - fn; + if (dotpos + 4 >= BMAX_PATH) + break; + + char *vpxfndot = vpxfn + dotpos; + vpxfndot[1] = 'i'; + vpxfndot[2] = 'v'; + vpxfndot[3] = 'f'; + vpxfndot[4] = '\0'; + + handle = fileSystem.OpenFileReader(vpxfn); + if (!handle.isOpen()) + break; + + anim = Anim_Find(vpxfn); + } + + animvpx_ivf_header_t info; + i = animvpx_read_ivf_header(handle, &info); + + if (i) + { + Printf("Failed reading IVF file: %s\n", animvpx_read_ivf_header_errmsg[i]); + return 0; + } + + if (anim) + animvpx_setup_glstate(anim->frameflags); + else + animvpx_setup_glstate(origanim->frameflags); + + animvpx_codec_ctx codec; + + if (animvpx_init_codec(&info, handle, &codec)) + { + Printf("Error initializing VPX codec.\n"); + animvpx_restore_glstate(); + return 0; + } + + + uint32_t const convnumer = 120 * info.fpsdenom; + uint32_t const convdenom = info.fpsnumer * origanim->framedelay; + + uint32_t const msecsperframe = scale(info.fpsdenom, 1000, info.fpsnumer); + uint32_t nextframetime = timerGetTicks(); + uint8_t *pic; + + // Printf("msecs per frame: %d\n", msecsperframe); + + do + { + nextframetime += msecsperframe; + + i = animvpx_nextpic(&codec, &pic); + if (i) + { + Printf("Failed getting next pic: %s\n", animvpx_nextpic_errmsg[i]); + if (codec.errmsg) + { + Printf(" %s\n", codec.errmsg); + if (codec.errmsg_detail) + Printf(" detail: %s\n", codec.errmsg_detail); + } + break; + } + + if (!pic) + break; // no more pics! + + twod->ClearScreen(); + + ototalclock = totalclock + 1; // pause game like ANMs + + if (anim) + { + if (anim->frameaspect1 == 0 || anim->frameaspect2 == 0) + animvpx_render_frame(&codec, 0); + else + animvpx_render_frame(&codec, anim->frameaspect1 / anim->frameaspect2); + } + else + { + if (origanim->frameaspect1 == 0 || origanim->frameaspect2 == 0) + animvpx_render_frame(&codec, 0); + else + animvpx_render_frame(&codec, origanim->frameaspect1 / origanim->frameaspect2); + } + + // after rendering the frame but before displaying: maybe play sound... + framenum++; + if (anim) + { + while (soundidx < anim->Sounds.Size() && anim->Sounds[soundidx].frame <= framenum) + { + int16_t sound = anim->Sounds[soundidx].sound; + if (sound == -1) + FX_StopAllSounds(); + else + S_PlaySound(sound, CHAN_AUTO, CHANF_UI); + + soundidx++; + } + } + else + { + uint16_t convframenum = scale(framenum, convnumer, convdenom); + while (soundidx < origanim->Sounds.Size() && origanim->Sounds[soundidx].frame <= convframenum) + { + int16_t sound = origanim->Sounds[soundidx].sound; + if (sound == -1) + FX_StopAllSounds(); + else + S_PlaySound(sound, CHAN_AUTO, CHANF_UI); + + soundidx++; + } + } + + videoNextPage(); + do + { + G_HandleAsync(); + + if (inputState.CheckAllInput()) + { + running = 0; + break; + } + } while (timerGetTicks() < nextframetime); + } while (running); + + #ifdef DEBUGGINGAIDS + animvpx_print_stats(&codec); + #endif + + // + animvpx_restore_glstate(); + animvpx_uninit_codec(&codec); + + inputState.ClearAllInput(); + return !running; // done with playing VP8! + } +#endif +// ANM playback --- v v v --- + + int32_t ogltexfiltermode = gl_texture_filter; + auto fr = fileSystem.OpenFileReader(fn); + + if (!fr.isOpen()) + return 0; + + auto buffer = fr.ReadPadded(1); + fr.Close(); + + if (buffer.Size() <= 5) + { + Printf("Warning: skipping playback of empty ANM file \"%s\".\n", fn); + goto end_anim; + } + + anim->animbuf = buffer.Data(); + + uint32_t firstfour; + Bmemcpy(&firstfour, anim->animbuf, 4); + + // "DKIF" (.ivf) + if (firstfour == B_LITTLE32(0x46494B44)) + goto end_anim; + + int32_t numframes; + + // "LPF " (.anm) + if (firstfour != B_LITTLE32(0x2046504C) || + ANIM_LoadAnim(anim->animbuf, buffer.Size()-1) < 0 || + (numframes = ANIM_NumFrames()) <= 0) + { + // XXX: ANM_LoadAnim() still checks less than the bare minimum, + // e.g. ANM file could still be too small and not contain any frames. + Printf("Error: malformed ANM file \"%s\".\n", fn); + goto end_anim; + } + + ototalclock = totalclock; + + i = 1; + int32_t frametime; frametime = 0; + + { + AnimTextures animtex; + animtex.SetSize(320, 200); + + do + { + if (i > 4 && totalclock > frametime + 60) + { + Printf("WARNING: slowdown in %s, skipping playback\n", fn); + goto end_anim_restore_gl; + } + + G_HandleAsync(); + + if (totalclock < ototalclock - 1) + continue; + + animtex.SetFrame(ANIM_GetPalette(), ANIM_DrawFrame(i)); + + if (inputState.CheckAllInput()) + { + running = 0; + goto end_anim_restore_gl; + } + + if (g_restorePalette == 1) + { + P_SetGamePalette(g_player[myconnectindex].ps, ANIMPAL, 0); + g_restorePalette = 0; + } + + frametime = (int32_t)totalclock; + + videoClearScreen(0); + + int32_t z; +#if 0 + if (anim->frameaspect1 > 0 && anim->frameaspect2 > 0 && ((anim->frameaspect1 / anim->frameaspect2) != (tilesiz[TILE_ANIM].y / (tilesiz[TILE_ANIM].x * 1.2)))) + { + int32_t const oyxaspect = yxaspect; + if ((anim->frameaspect1 / anim->frameaspect2) >= ((decltype(anim->frameaspect1))xdim / ydim)) + z = divscale16(320, tilesiz[TILE_ANIM].y); + else + z = divscale16(lrint(320 * ydim * anim->frameaspect1), lrint(tilesiz[TILE_ANIM].y * xdim * anim->frameaspect2)); + int32_t aspect = divscale16(lrint(tilesiz[TILE_ANIM].y * anim->frameaspect2), lrint(tilesiz[TILE_ANIM].x * anim->frameaspect1)); + renderSetAspect(viewingrange, aspect); + rotatesprite_fs(160 << 16, 100 << 16, z, 512, TILE_ANIM, 0, 0, 2 | 4 | 8 | 64 | 1024); + renderSetAspect(viewingrange, oyxaspect); + } + else +#endif + { + if ((320 / (200 * 1.2f)) > (1.f * xdim / ydim)) + z = divscale16(320 * xdim * 3, 320 * ydim * 4); + else + z = divscale16(200, 200); + rotatesprite_fs(160 << 16, 100 << 16, z, 0, -1, 0, 0, 2 | 8 | 64, animtex.GetFrame()); + } + + g_animPtr = NULL; + + videoNextPage(); + + inputState.ClearAllInput(); + + ototalclock += anim->framedelay; + + while (soundidx < anim->Sounds.Size() && anim->Sounds[soundidx].frame <= (uint16_t)i) + { + int16_t sound = anim->Sounds[soundidx].sound; + if (sound == -1) + FX_StopAllSounds(); + else + S_PlaySound(sound, CHAN_AUTO, CHANF_UI); + + soundidx++; + } + + ++i; + } while (i < numframes); + } + +end_anim_restore_gl: + gl_texture_filter = ogltexfiltermode; + gltexapplyprops(); +end_anim: + inputState.ClearAllInput(); + anim->animbuf = nullptr; + ANIM_FreeAnim(); + tileDelete(TILE_ANIM); + + return !running; +} +END_DUKE_NS diff --git a/source/duke/src/anim.h b/source/duke/src/anim.h new file mode 100644 index 000000000..49241f4b6 --- /dev/null +++ b/source/duke/src/anim.h @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef anim_h_ +#define anim_h_ + +BEGIN_DUKE_NS + +struct animsound_t { + uint16_t frame = 0; + int16_t sound = 0; +}; + +struct dukeanim_t +{ + FString name; + double frameaspect1 = 0, frameaspect2 = 0; + uint8_t* animbuf = nullptr; + TArray Sounds; + uint8_t framedelay = 0; + uint8_t frameflags = 0; +}; + +extern dukeanim_t* g_animPtr; +extern TArray g_Animations; +extern dukeanim_t * Anim_Find(const char *s); +extern dukeanim_t * Anim_Create(const char *fn); +int32_t Anim_Play(const char *fn); +void Anim_Init(void); + +END_DUKE_NS +#endif + diff --git a/source/duke/src/cheats.cpp b/source/duke/src/cheats.cpp new file mode 100644 index 000000000..1bb93edfb --- /dev/null +++ b/source/duke/src/cheats.cpp @@ -0,0 +1,939 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! + +#include "duke3d.h" +#include "osdcmds.h" +#include "cheats.h" +#include "mapinfo.h" +#include "c_dispatch.h" + +BEGIN_DUKE_NS + +// KEEPINSYNC game.h: enum cheatindex_t +char CheatStrings [NUMCHEATS][MAXCHEATLEN] = +{ + "cornholio", // 0 + "stuff", // 1 + "scotty###", // 2 + "coords", // 3 + "view", // 4 + "time", // 5 + "unlock", // 6 + "cashman", // 7 + "items", // 8 + "rate", // 9 + "skill#", // 10 + "beta", // 11 + "hyper", // 12 + "monsters", // 13 + "", // 14 + "", // 15 + "todd", // 16 + "showmap", // 17 + "kroz", // 18 + "allen", // 19 + "clip", // 20 + "weapons", // 21 + "inventory", // 22 + "keys", // 23 + "debug", // 24 + "", // 25 + "", // 26 + "", // 27 + "", // 28 + "", // 29 + "", // 30 + "", // 31 + "", // 32 + "", // 33 + "", // 34 + "", // 35 + "", // 36 + "", // 37 + "", // 38 + "", // 39 +}; + +const uint32_t CheatFunctionFlags [NUMCHEATS] = +{ + 1 << CHEATFUNC_GOD, + 1 << CHEATFUNC_GIVEEVERYTHING, + 1 << CHEATFUNC_WARP, + 1 << CHEATFUNC_COORDS, + 1 << CHEATFUNC_VIEW, + 0, + 1 << CHEATFUNC_UNLOCK, + 1 << CHEATFUNC_CASHMAN, + 1 << CHEATFUNC_GIVEALLITEMS, + 1 << CHEATFUNC_FRAMERATE, + 1 << CHEATFUNC_SKILL, + 1 << CHEATFUNC_QUOTEBETA, + 1 << CHEATFUNC_HYPER, + 1 << CHEATFUNC_MONSTERS, + 0, + 0, + 1 << CHEATFUNC_QUOTETODD, + 1 << CHEATFUNC_SHOWMAP, + 1 << CHEATFUNC_GOD, + 1 << CHEATFUNC_QUOTEALLEN, + 1 << CHEATFUNC_CLIP, + 1 << CHEATFUNC_GIVEWEAPONS, + 1 << CHEATFUNC_GIVEINVENTORY, + 1 << CHEATFUNC_GIVEKEYS, + 1 << CHEATFUNC_DEBUG, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, +}; + +// KEEPINSYNC game.h: enum CheatCodeFunctions +// KEEPINSYNC menus.c: MenuEntry_t ME_CheatCodes[] +const uint8_t CheatFunctionIDs[NUMCHEATS] = +{ + CHEAT_CASHMAN, + CHEAT_CORNHOLIO, + CHEAT_STUFF, + CHEAT_WEAPONS, + CHEAT_ITEMS, + CHEAT_INVENTORY, + CHEAT_KEYS, + CHEAT_HYPER, + CHEAT_VIEW, + CHEAT_SHOWMAP, + CHEAT_UNLOCK, + CHEAT_CLIP, + CHEAT_SCOTTY, + CHEAT_SKILL, + CHEAT_MONSTERS, + CHEAT_RATE, + CHEAT_BETA, + CHEAT_TODD, + CHEAT_ALLEN, + CHEAT_COORDS, + CHEAT_DEBUG, +}; + +char const * const g_NAMMattCheatQuote = "Matt Saettler. matts@seanet.com"; + +void G_SetupCheats(void) +{ + if (RR) + { + CheatKeys[0] = sc_R; + CheatKeys[1] = sc_D; + Bstrcpy(CheatStrings[0], "hounddog"); + Bstrcpy(CheatStrings[1], "all"); + Bstrcpy(CheatStrings[2], "meadow###"); + Bstrcpy(CheatStrings[3], "yerat"); + Bstrcpy(CheatStrings[7], "cluck"); + Bstrcpy(CheatStrings[11], "teachers"); + Bstrcpy(CheatStrings[12], "moonshine"); + Bstrcpy(CheatStrings[13], "critters"); + Bstrcpy(CheatStrings[16], "rafael"); + Bstrcpy(CheatStrings[18], "elvis"); + Bstrcpy(CheatStrings[19], ""); + Bstrcpy(CheatStrings[21], "guns"); + if (RRRA) + { + Bstrcpy(CheatStrings[25], "joseph"); + Bstrcpy(CheatStrings[26], "mrbill"); + Bstrcpy(CheatStrings[27], "tony"); + Bstrcpy(CheatStrings[28], "gary"); + Bstrcpy(CheatStrings[29], "rhett"); + Bstrcpy(CheatStrings[30], "aaron"); + Bstrcpy(CheatStrings[31], "nocheat"); + Bstrcpy(CheatStrings[32], "woleslagle"); + Bstrcpy(CheatStrings[33], "mikael"); + Bstrcpy(CheatStrings[34], "greg"); + Bstrcpy(CheatStrings[35], "noah"); + Bstrcpy(CheatStrings[36], "arijit"); + Bstrcpy(CheatStrings[37], "donut"); + Bstrcpy(CheatStrings[38], "kfc"); + Bstrcpy(CheatStrings[39], "van"); + } + } + if (WW2GI) + { +#if 0 + // WWII GI's original cheat prefix temporarily disabled because W conflicts with WSAD movement + CheatKeys[0] = CheatKeys[1] = sc_W; +#else + CheatKeys[0] = sc_G; + CheatKeys[1] = sc_I; +#endif + + Bstrcpy(CheatStrings[0], "2god"); + Bstrcpy(CheatStrings[1], "2blood"); + Bstrcpy(CheatStrings[2], "2level###"); + Bstrcpy(CheatStrings[3], "2coords"); + Bstrcpy(CheatStrings[4], "2view"); + Bstrcpy(CheatStrings[5], ""); + Bstrcpy(CheatStrings[7], ""); + Bstrcpy(CheatStrings[8], ""); + Bstrcpy(CheatStrings[9], "2rate"); + Bstrcpy(CheatStrings[10], "2skill"); + Bstrcpy(CheatStrings[11], ""); + Bstrcpy(CheatStrings[12], ""); + Bstrcpy(CheatStrings[13], ""); + Bstrcpy(CheatStrings[16], "2matt"); + Bstrcpy(CheatStrings[17], "2showmap"); + Bstrcpy(CheatStrings[18], "2ryan"); + Bstrcpy(CheatStrings[19], ""); + Bstrcpy(CheatStrings[20], "2clip"); + Bstrcpy(CheatStrings[21], "2weapons"); + Bstrcpy(CheatStrings[22], "2inventory"); + Bstrcpy(CheatStrings[23], ""); + Bstrcpy(CheatStrings[24], "2debug"); + Bstrcpy(CheatStrings[26], "2cgs"); + + Bstrcpy(g_gametypeNames[0], "GI Match (Spawn)"); + Bstrcpy(g_gametypeNames[2], "GI Match (No Spawn)"); + } + else if (NAM) + { + CheatKeys[0] = sc_N; + CheatKeys[1] = sc_V; + + Bstrcpy(CheatStrings[0], "acaleb"); + Bstrcpy(CheatStrings[1], "ablood"); + Bstrcpy(CheatStrings[2], "alevel###"); + Bstrcpy(CheatStrings[3], "acoords"); + Bstrcpy(CheatStrings[4], "aview"); + Bstrcpy(CheatStrings[5], ""); + Bstrcpy(CheatStrings[7], ""); + Bstrcpy(CheatStrings[8], ""); + Bstrcpy(CheatStrings[9], "arate"); + Bstrcpy(CheatStrings[10], "askill"); + Bstrcpy(CheatStrings[11], ""); + Bstrcpy(CheatStrings[12], "ahyper"); + Bstrcpy(CheatStrings[13], ""); + Bstrcpy(CheatStrings[16], "amatt"); + Bstrcpy(CheatStrings[17], "ashowmap"); + Bstrcpy(CheatStrings[18], "agod"); + Bstrcpy(CheatStrings[19], ""); + Bstrcpy(CheatStrings[20], "aclip"); + Bstrcpy(CheatStrings[21], "aweapons"); + Bstrcpy(CheatStrings[22], "ainventory"); + Bstrcpy(CheatStrings[23], ""); + Bstrcpy(CheatStrings[24], "adebug"); + Bstrcpy(CheatStrings[26], "acgs"); + } +} + +static void doinvcheat(DukePlayer_t * const pPlayer, int32_t invidx, int32_t defaultnum, int event) +{ + defaultnum = VM_OnEventWithReturn(event, pPlayer->i, myconnectindex, defaultnum); + if (defaultnum >= 0) + pPlayer->inv_amount[invidx] = defaultnum; +} + +static void G_CheatGetInv(DukePlayer_t *pPlayer) +{ + doinvcheat(pPlayer, GET_STEROIDS, 400, EVENT_CHEATGETSTEROIDS); + if (!RR) doinvcheat(pPlayer, GET_HEATS, 1200, EVENT_CHEATGETHEAT); + doinvcheat(pPlayer, GET_BOOTS, RR ? 2000 : 200, EVENT_CHEATGETBOOT); + doinvcheat(pPlayer, GET_SHIELD, 100, EVENT_CHEATGETSHIELD); + doinvcheat(pPlayer, GET_SCUBA, 6400, EVENT_CHEATGETSCUBA); + doinvcheat(pPlayer, GET_HOLODUKE, 2400, EVENT_CHEATGETHOLODUKE); + doinvcheat(pPlayer, GET_JETPACK, RR ? 600 : 1600, EVENT_CHEATGETJETPACK); + doinvcheat(pPlayer, GET_FIRSTAID, pPlayer->max_player_health, EVENT_CHEATGETFIRSTAID); +} + +static void end_cheat(DukePlayer_t * const pPlayer) +{ + pPlayer->cheat_phase = 0; + inputState.keyFlushChars(); +} + +static int32_t cheatbuflen; +static int8_t cheatbuf[MAXCHEATLEN]; + +void G_DoCheats(void) +{ + DukePlayer_t * const pPlayer = g_player[myconnectindex].ps; + int consoleCheat = 0; + int cheatNum; + + if (DEER) + return; + + if (osdcmd_cheatsinfo_stat.cheatnum != -1) + { + cheatNum = osdcmd_cheatsinfo_stat.cheatnum; + + if (ud.player_skill == 4 || (RR && ud.player_skill > 3) || (RRRA && pPlayer->nocheat)) + { + switch (cheatNum) + { + case CHEAT_DEBUG: + case CHEAT_COORDS: + case CHEAT_RATE: + case CHEAT_RESERVED: + case CHEAT_RESERVED2: + //case CHEAT_RESERVED3: + break; + default: + P_DoQuote(QUOTE_CHEATS_DISABLED, pPlayer); + osdcmd_cheatsinfo_stat.cheatnum = -1; + return; + } + } + + // JBF 20030914 + osdcmd_cheatsinfo_stat.cheatnum = -1; + consoleCheat = 1; + } + + static int volumeOne = 0; + + if (VOLUMEONE && !volumeOne) + { + // change "scotty###" to "scotty##" + uint32_t const warpend = Bstrlen(CheatStrings[2]); + if (strcmp(&CheatStrings[2][warpend-3], "###") == 0) + CheatStrings[2][warpend-1] = '\0'; + + Bstrcpy(CheatStrings[6], ""); + volumeOne = 1; + } + + if (consoleCheat && numplayers < 2 && ud.recstat == 0) + goto FOUNDCHEAT; + + if ((RR && ud.player_skill > 3) || (RRRA && pPlayer->nocheat)) + return; + + if (pPlayer->gm & (MODE_TYPE|MODE_MENU)) + return; + + if (pPlayer->cheat_phase == 1) + { + int ch; + + while (inputState.keyBufferWaiting()) + { + ch = Btolower(inputState.keyGetChar()); + + if (!((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9'))) + { + pPlayer->cheat_phase = 0; + // P_DoQuote(QUOTE_46,pPlayer); + return; + } + + cheatbuf[cheatbuflen++] = (int8_t) ch; + // This assertion is not obvious, but it should hold because of the + // cheat string matching logic below. + Bassert(cheatbuflen < (signed)sizeof(cheatbuf)); + cheatbuf[cheatbuflen] = 0; + // inputState.ClearAllInput(); + + for (cheatNum=0; cheatNum < NUMCHEATCODES; cheatNum++) + { + for (bssize_t j = 0; j= '0' && ch <= '9')) + { + if (CheatStrings[cheatNum][j+1] == 0) goto FOUNDCHEAT; + if (j == cheatbuflen-1) return; + } + else break; + } + } + + pPlayer->cheat_phase = 0; + return; + + FOUNDCHEAT:; + + if (cheatNum == CHEAT_SCOTTY) + { + size_t const i = Bstrlen(CheatStrings[cheatNum])-3+VOLUMEONE; + if (!consoleCheat) + { + // JBF 20030914 + int32_t volnume, levnume; + if (VOLUMEALL) + { + volnume = cheatbuf[i] - '0'; + levnume = (cheatbuf[i+1] - '0')*10+(cheatbuf[i+2]-'0'); + } + else + { + volnume = cheatbuf[i] - '0'; + levnume = cheatbuf[i+1] - '0'; + } + + volnume--; + levnume--; + + ud.m_volume_number = volnume; + m_level_number = levnume; + } + else + { + // JBF 20030914 + ud.m_volume_number = osdcmd_cheatsinfo_stat.volume; + m_level_number = osdcmd_cheatsinfo_stat.level; + } + } + else if (cheatNum == CHEAT_SKILL) + { + if (!consoleCheat) + { + size_t const i = Bstrlen(CheatStrings[cheatNum])-1; + ud.m_player_skill = cheatbuf[i] - '1'; + } + else + { + ud.m_player_skill = osdcmd_cheatsinfo_stat.volume; + } + } + + { + switch (cheatNum) + { + case CHEAT_WEAPONS: + { + int const weaponLimit = (VOLUMEONE) ? 6 : 0; + + for (bssize_t weaponNum = PISTOL_WEAPON; weaponNum < MAX_WEAPONS-weaponLimit; weaponNum++) + { + P_AddAmmo(pPlayer, weaponNum, pPlayer->max_ammo_amount[weaponNum]); + pPlayer->gotweapon |= (1<ammo_amount[SLINGBLADE_WEAPON] = 1; + + P_DoQuote(QUOTE_CHEAT_ALL_WEAPONS, pPlayer); + + end_cheat(pPlayer); + } + return; + + case CHEAT_INVENTORY: + G_CheatGetInv(pPlayer); + P_DoQuote(QUOTE_CHEAT_ALL_INV, pPlayer); + end_cheat(pPlayer); + return; + + case CHEAT_KEYS: + pPlayer->got_access = 7; + if (RR) + for (int key = 0; key < 5; key++) + pPlayer->keys[key] = 1; + inputState.keyFlushChars(); + P_DoQuote(QUOTE_CHEAT_ALL_KEYS, pPlayer); + end_cheat(pPlayer); + return; + + case CHEAT_DEBUG: + g_Debug = 1-g_Debug; + + G_DumpDebugInfo(); + Bsprintf(tempbuf, "Gamevars dumped to log"); + G_AddUserQuote(tempbuf); + Bsprintf(tempbuf, "Map dumped to debug.map"); + G_AddUserQuote(tempbuf); + end_cheat(pPlayer); + break; + + case CHEAT_CLIP: + ud.noclip = !ud.noclip; + P_DoQuote(QUOTE_CHEAT_NOCLIP-!ud.noclip, pPlayer); + end_cheat(pPlayer); + return; + + case CHEAT_RESERVED2: + if (RR) + { + P_DoQuote(QUOTE_JETPACK_ON, pPlayer); + inputState.keyFlushChars(); + } + else + { + pPlayer->player_par = 0; + pPlayer->gm = MODE_EOL; + } + end_cheat(pPlayer); + return; + + case CHEAT_ALLEN: + P_DoQuote(QUOTE_CHEAT_ALLEN, pPlayer); + pPlayer->cheat_phase = 0; + inputState.ClearKeyStatus(sc_N); + return; + + case CHEAT_CORNHOLIO: + case CHEAT_KROZ: + //case CHEAT_COMEGETSOME: + { + const int32_t pi = pPlayer->i; + + ud.god = 1-ud.god; + + if (ud.god) + { + if (RRRA) + S_PlaySound(218); + pus = 1; + pub = 1; + sprite[pi].cstat = 257; + + actor[pi].t_data[0] = 0; + actor[pi].t_data[1] = 0; + actor[pi].t_data[2] = 0; + actor[pi].t_data[3] = 0; + actor[pi].t_data[4] = 0; + actor[pi].t_data[5] = 0; + + sprite[pi].hitag = 0; + sprite[pi].lotag = 0; + sprite[pi].pal = pPlayer->palookup; + + //if (cheatNum != CHEAT_COMEGETSOME) + //{ + P_DoQuote(QUOTE_CHEAT_GODMODE_ON, pPlayer); + //} + //else + //{ + // Bstrcpy(pStrings[QUOTE_RESERVED4], "Come Get Some!"); + // + // S_PlaySound(DUKE_GETWEAPON2); + // P_DoQuote(QUOTE_RESERVED4, pPlayer); + // G_CheatGetInv(pPlayer); + // + // for (bssize_t weaponNum = PISTOL_WEAPON; weaponNum < MAX_WEAPONS; weaponNum++) + // pPlayer->gotweapon |= (1<max_ammo_amount[weaponNum]); + // + // pPlayer->got_access = 7; + //} + } + else + { + sprite[pi].extra = pPlayer->max_player_health; + actor[pi].extra = -1; + pPlayer->last_extra = pPlayer->max_player_health; + P_DoQuote(QUOTE_CHEAT_GODMODE_OFF, pPlayer); + } + + sprite[pi].extra = pPlayer->max_player_health; + actor[pi].extra = 0; + + //if (cheatNum != CHEAT_COMEGETSOME) + pPlayer->dead_flag = 0; + + end_cheat(pPlayer); + return; + } + + case CHEAT_STUFF: + { + int const weaponLimit = (VOLUMEONE) ? 6 : 0; + + for (bssize_t weaponNum = PISTOL_WEAPON; weaponNum < MAX_WEAPONS-weaponLimit; weaponNum++) + pPlayer->gotweapon |= (1<max_ammo_amount[weaponNum]); + + if (RRRA) + pPlayer->ammo_amount[SLINGBLADE_WEAPON] = 1; + + G_CheatGetInv(pPlayer); + pPlayer->got_access = 7; + if (RR) + for (int key = 0; key < 5; key++) + pPlayer->keys[key] = 1; + P_DoQuote(QUOTE_CHEAT_EVERYTHING, pPlayer); + + // P_DoQuote(QUOTE_21,pPlayer); + pPlayer->inven_icon = ICON_FIRSTAID; + + end_cheat(pPlayer); + return; + } + + case CHEAT_SCOTTY: + { + if (RR) + g_lastLevel = 0; + int32_t const volnume = ud.m_volume_number, levnume = m_level_number; + + if ((!VOLUMEONE || volnume == 0) && (unsigned)volnume < (unsigned)g_volumeCnt && + (unsigned)levnume < MAXLEVELS && mapList[volnume*MAXLEVELS + levnume].fileName.IsNotEmpty()) + { + ud.volume_number = volnume; + ud.level_number = levnume; + +#if 0 + if (numplayers > 1 && g_netServer) + Net_NewGame(volnume, levnume); + else +#endif + pPlayer->gm |= MODE_RESTART; + } + + end_cheat(pPlayer); + return; + } + + case CHEAT_SKILL: + if (RR) + g_lastLevel = 0; + ud.player_skill = ud.m_player_skill; + +#if 0 + if (numplayers > 1 && g_netServer) + Net_NewGame(ud.m_volume_number, m_level_number); + else +#endif + pPlayer->gm |= MODE_RESTART; + + end_cheat(pPlayer); + return; + + case CHEAT_COORDS: + C_DoCommand("stat coord"); + end_cheat(pPlayer); + return; + + case CHEAT_VIEW: + if (!RRRA || (!pPlayer->on_motorcycle && !pPlayer->on_boat)) + { + pPlayer->over_shoulder_on ^= 1; + CAMERADIST = 0; + CAMERACLOCK = (int32_t) totalclock; + // P_DoQuote(QUOTE_CHEATS_DISABLED,pPlayer); + } + end_cheat(pPlayer); + return; + + case CHEAT_TIME: + // P_DoQuote(QUOTE_21,pPlayer); + end_cheat(pPlayer); + return; + + case CHEAT_UNLOCK: + if (VOLUMEONE) return; + + for (bssize_t i=numsectors-1; i>=0; i--) //Unlock + { + int const lotag = sector[i].lotag; + if (lotag == -1 || lotag == 32767) continue; + if ((lotag & 0x7fff) > 2) + { + if (lotag & (uint16_t)~16384u) + sector[i].lotag &= (uint16_t)~16384u; + G_OperateSectors(i, pPlayer->i); + } + } + G_OperateForceFields(pPlayer->i, -1); + + P_DoQuote(QUOTE_CHEAT_UNLOCK, pPlayer); + end_cheat(pPlayer); + return; + + case CHEAT_CASHMAN: + ud.cashman = 1-ud.cashman; + inputState.ClearKeyStatus(sc_N); + pPlayer->cheat_phase = 0; + return; + + case CHEAT_ITEMS: + G_CheatGetInv(pPlayer); + pPlayer->got_access = 7; + if (RR) + for(int key = 0; key < 5; key++) + pPlayer->keys[key] = 1; + P_DoQuote(QUOTE_CHEAT_EVERYTHING, pPlayer); + end_cheat(pPlayer); + return; + + case CHEAT_SHOWMAP: // SHOW ALL OF THE MAP TOGGLE; + gFullMap = !gFullMap; + + P_DoQuote(gFullMap ? QUOTE_SHOW_MAP_ON : QUOTE_SHOW_MAP_OFF, + pPlayer); + + end_cheat(pPlayer); + return; + + case CHEAT_TODD: + if (NAM_WW2GI) + { + quoteMgr.InitializeQuote(QUOTE_RESERVED4, g_NAMMattCheatQuote); + P_DoQuote(QUOTE_RESERVED4, pPlayer); + } + else + { + P_DoQuote(QUOTE_CHEAT_TODD, pPlayer); + } + + end_cheat(pPlayer); + return; + + case CHEAT_RATE: + r_showfps = clamp(*r_showfps+1, 0, 3); + end_cheat(pPlayer); + return; + + case CHEAT_BETA: + P_DoQuote(QUOTE_CHEAT_BETA, pPlayer); + inputState.ClearKeyStatus(sc_H); + end_cheat(pPlayer); + return; + + case CHEAT_HYPER: + pPlayer->inv_amount[GET_STEROIDS] = 399; + if (!RR) + pPlayer->inv_amount[GET_HEATS] = 1200; + P_DoQuote(QUOTE_CHEAT_STEROIDS, pPlayer); + end_cheat(pPlayer); + return; + + case CHEAT_MONSTERS: + { + const char *s [] = { "OPTVAL_ON", "OPTVAL_OFF", "$TXT_ON2" }; + + if (++g_noEnemies == 3) + g_noEnemies = 0; + + quoteMgr.FormatQuote(QUOTE_RESERVED4, "%s: %s", GStrings("NETMNU_MONSTERS"), s[g_noEnemies]); + P_DoQuote(QUOTE_RESERVED4, pPlayer); + + end_cheat(pPlayer); + return; + } + + case CHEAT_RESERVED: + //case CHEAT_RESERVED3: + if (RR) + { + P_DoQuote(51, pPlayer); + end_cheat(pPlayer); + } + else + { + ud.eog = 1; + pPlayer->player_par = 0; + pPlayer->gm |= MODE_EOL; + } + inputState.keyFlushChars(); + return; + + case CHEAT_RAJOSEPH: + G_OnMotorcycle(pPlayer, 0); + pPlayer->ammo_amount[MOTORCYCLE_WEAPON] = pPlayer->max_ammo_amount[MOTORCYCLE_WEAPON]; + P_DoQuote(126, pPlayer); + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + case CHEAT_RAMRBILL: + P_QuickKill(pPlayer); + P_DoQuote(127, pPlayer); + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + case CHEAT_RAGARY: + S_PlayRRMusic(10); + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + case CHEAT_RANOAH: + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + case CHEAT_RARHETT: + ud.god = 0; + pPlayer->gotweapon = 1<curr_weapon = KNEE_WEAPON; + pPlayer->nocheat = 1; + sprite[pPlayer->i].extra = 1; + P_DoQuote(128, pPlayer); + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + case CHEAT_RAAARON: + pPlayer->drug_mode = pPlayer->drug_mode ? 0 : 5; + pPlayer->drug_timer = (int32_t) totalclock; + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + case CHEAT_RANOCHEAT: + pPlayer->nocheat = 1; + P_DoQuote(130, pPlayer); + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + case CHEAT_RATONY: + g_changeEnemySize = 2; + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + case CHEAT_RAVAN: + g_changeEnemySize = 3; + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + case CHEAT_RAKFC: + for (int i = 0; i < 7; i++) + { + int const newSprite = A_Spawn(pPlayer->i, HEN); + sprite[newSprite].pal = 1; + sprite[newSprite].xrepeat <<= 2; + sprite[newSprite].yrepeat <<= 2; + } + P_DoQuote(139, pPlayer); + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + case CHEAT_RAWOLESLAGLE: + if (pPlayer->drink_amt) + { + pPlayer->drink_amt = 0; + P_DoQuote(132, pPlayer); + } + else + { + pPlayer->drink_amt = 90; + P_DoQuote(131, pPlayer); + } + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + case CHEAT_RAMIKAEL: + for (bssize_t weaponNum = PISTOL_WEAPON; weaponNum < MAX_WEAPONS; weaponNum++) + { + pPlayer->gotweapon |= 1 << weaponNum; + pPlayer->ammo_amount[weaponNum] = 66; + } + + pPlayer->ammo_amount[SLINGBLADE_WEAPON] = 1; + + G_CheatGetInv(pPlayer); + pPlayer->got_access = 7; + for (int key = 0; key < 5; key++) + pPlayer->keys[key] = 1; + P_DoQuote(5, pPlayer); + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + case CHEAT_RAGREG: + if (pPlayer->sea_sick_stat) + { + pPlayer->sea_sick_stat = 0; + P_DoQuote(129, pPlayer); + } + else + { + pPlayer->sea_sick_stat = 1; + P_DoQuote(137, pPlayer); + } + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + case CHEAT_RAARIJIT: + case CHEAT_RADONUT: + G_OnBoat(pPlayer, 0); + pPlayer->ammo_amount[BOAT_WEAPON] = pPlayer->max_ammo_amount[BOAT_WEAPON]; + P_DoQuote(136, pPlayer); + end_cheat(pPlayer); + inputState.keyFlushChars(); + return; + + default: + end_cheat(pPlayer); + return; + } + } + } + } + else + { + if (inputState.GetKeyStatus((uint8_t) CheatKeys[0])) + { + if (pPlayer->cheat_phase >= 0 && numplayers < 2 && ud.recstat == 0) + { + if (CheatKeys[0] == CheatKeys[1]) + inputState.ClearKeyStatus((uint8_t) CheatKeys[0]); + pPlayer->cheat_phase = -1; + } + } + + if (inputState.GetKeyStatus((uint8_t) CheatKeys[1])) + { + if (pPlayer->cheat_phase == -1) + { + if (ud.player_skill == 4) + { + P_DoQuote(QUOTE_CHEATS_DISABLED, pPlayer); + pPlayer->cheat_phase = 0; + } + else + { + pPlayer->cheat_phase = 1; + // P_DoQuote(QUOTE_25,pPlayer); + cheatbuflen = 0; + } + inputState.keyFlushChars(); + } + else if (pPlayer->cheat_phase != 0) + { + pPlayer->cheat_phase = 0; + inputState.ClearKeyStatus((uint8_t) CheatKeys[0]); + inputState.ClearKeyStatus((uint8_t) CheatKeys[1]); + } + } + } +} +END_DUKE_NS diff --git a/source/duke/src/cheats.h b/source/duke/src/cheats.h new file mode 100644 index 000000000..fc60209eb --- /dev/null +++ b/source/duke/src/cheats.h @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#pragma once + +BEGIN_DUKE_NS + +#define MAXCHEATLEN 20 +#define NUMCHEATCODES (int32_t)ARRAY_SIZE(CheatStrings) + +extern void G_DoCheats(void); +extern void G_SetupCheats(void); + +// Cheats +// KEEPINSYNC game.c: char CheatStrings[][] +enum cheatindex_t +{ + CHEAT_CORNHOLIO, // 0 + CHEAT_STUFF, + CHEAT_SCOTTY, + CHEAT_COORDS, + CHEAT_VIEW, + CHEAT_TIME, // 5 + CHEAT_UNLOCK, + CHEAT_CASHMAN, + CHEAT_ITEMS, + CHEAT_RATE, + CHEAT_SKILL, // 10 + CHEAT_BETA, + CHEAT_HYPER, + CHEAT_MONSTERS, + CHEAT_RESERVED, + CHEAT_RESERVED2, // 15 + CHEAT_TODD, + CHEAT_SHOWMAP, + CHEAT_KROZ, + CHEAT_ALLEN, + CHEAT_CLIP, // 20 + CHEAT_WEAPONS, + CHEAT_INVENTORY, + CHEAT_KEYS, + CHEAT_DEBUG, + CHEAT_RAJOSEPH, // 25 + CHEAT_RAMRBILL, + CHEAT_RATONY, + CHEAT_RAGARY, + CHEAT_RARHETT, + CHEAT_RAAARON, // 30 + CHEAT_RANOCHEAT, + CHEAT_RAWOLESLAGLE, + CHEAT_RAMIKAEL, + CHEAT_RAGREG, + CHEAT_RANOAH, // 35 + CHEAT_RAARIJIT, + CHEAT_RADONUT, + CHEAT_RAKFC, + CHEAT_RAVAN, + NUMCHEATS, +}; + +extern char CheatStrings[NUMCHEATS][MAXCHEATLEN]; + +// KEEPINSYNC game.c: uint8_t CheatFunctionIDs[] +// KEEPINSYNC menus.c: MenuEntry_t ME_CheatCodes[] +enum CheatCodeFunctions +{ + CHEATFUNC_CASHMAN, + CHEATFUNC_GOD, + CHEATFUNC_GIVEEVERYTHING, + CHEATFUNC_GIVEWEAPONS, + CHEATFUNC_GIVEALLITEMS, + CHEATFUNC_GIVEINVENTORY, + CHEATFUNC_GIVEKEYS, + CHEATFUNC_HYPER, + CHEATFUNC_VIEW, + CHEATFUNC_SHOWMAP, + CHEATFUNC_UNLOCK, + CHEATFUNC_CLIP, + CHEATFUNC_WARP, + CHEATFUNC_SKILL, + CHEATFUNC_MONSTERS, + CHEATFUNC_FRAMERATE, + CHEATFUNC_QUOTEBETA, + CHEATFUNC_QUOTETODD, + CHEATFUNC_QUOTEALLEN, + CHEATFUNC_COORDS, + CHEATFUNC_DEBUG, + NUMCHEATFUNCS, +}; + +END_DUKE_NS diff --git a/source/duke/src/cmdline.cpp b/source/duke/src/cmdline.cpp new file mode 100644 index 000000000..bd09600fd --- /dev/null +++ b/source/duke/src/cmdline.cpp @@ -0,0 +1,97 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! + +#include "duke3d.h" +#include "demo.h" +#include "screens.h" +#include "baselayer.h" +#include "cmdline.h" +#include "m_argv.h" + +BEGIN_DUKE_NS + +int32_t g_fakeMultiMode = 0; + + +static void G_AddDemo(const char* param) +{ + Bstrncpy(tempbuf, param, sizeof(tempbuf)); + char * colon = (char *) Bstrchr(tempbuf, ':'); + int32_t framespertic=-1, numrepeats=1; + + if (colon && colon != tempbuf) + { + // -d:[,] + // profiling options + *(colon++) = 0; + sscanf(colon, "%d,%d", &framespertic, &numrepeats); + } + + Demo_SetFirst(tempbuf); + + if (framespertic < 0) + { + Printf("Play demo %s.\n", g_firstDemoFile); + } + else + { + framespertic = clamp(framespertic, 0, 8)+1; + // TODO: repeat count and gathering statistics. + Printf("Profile demo %s, %d frames/gametic, repeated 1x.\n", g_firstDemoFile, + framespertic-1); + Demo_PlayFirst(framespertic, 1); + g_noLogo = 1; + } +} + +void G_CheckCommandLine() +{ + if (Args->CheckParm("-condebug") || Args->CheckParm("-z")) g_scriptDebug = 1; + if (Args->CheckParm("-altai")) + { + ud.playerai = 1; + Printf("Other player AI.\n"); + } + auto val = Args->CheckValue("-skill"); + if (val) + { + ud.m_player_skill = ud.player_skill = clamp((int)strtol(val, nullptr, 0), 0, 5); + if (ud.m_player_skill == 4) ud.m_respawn_monsters = ud.respawn_monsters = 1; + } + val = Args->CheckValue("-respawn"); + if (val) + { + if (*val == '1') ud.m_respawn_monsters = 1; + else if (*val == '2') ud.m_respawn_items = 1; + else if (*val == '3') ud.m_respawn_inventory = 1; + else + { + ud.m_respawn_monsters = 1; + ud.m_respawn_items = 1; + ud.m_respawn_inventory = 1; + } + Printf("Respawn on.\n"); + } +} +END_DUKE_NS diff --git a/source/duke/src/cmdline.h b/source/duke/src/cmdline.h new file mode 100644 index 000000000..c983f2e12 --- /dev/null +++ b/source/duke/src/cmdline.h @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef cmdline_h__ +#define cmdline_h__ + +#include "compat.h" + +BEGIN_DUKE_NS + +extern void G_CheckCommandLine(); +extern void G_ShowParameterHelp(void); +extern void G_ShowDebugHelp(void); + +extern int32_t g_fakeMultiMode; + +END_DUKE_NS + +#endif // cmdline_h__ diff --git a/source/duke/src/common.cpp b/source/duke/src/common.cpp new file mode 100644 index 000000000..7cbc57c7f --- /dev/null +++ b/source/duke/src/common.cpp @@ -0,0 +1,195 @@ +// +// Common non-engine code/data for EDuke32 and Mapster32 +// +#include "ns.h" // Must come before everything else! + +#include "compat.h" +#include "build.h" +#include "baselayer.h" +#include "palette.h" +#include "cmdlib.h" +#include "gamecvars.h" +#include "rts.h" +#include "gamecontrol.h" +#include "palettecontainer.h" + +#include "common.h" +#include "common_game.h" + +BEGIN_DUKE_NS + +////////// + +// Set up new-style multi-psky handling. +void G_InitMultiPsky(int CLOUDYOCEAN__DYN, int MOONSKY1__DYN, int BIGORBIT1__DYN, int LA__DYN) +{ + // When adding other multi-skies, take care that the tileofs[] values are + // <= PSKYOFF_MAX. (It can be increased up to MAXPSKYTILES, but should be + // set as tight as possible.) + + // The default sky properties (all others are implicitly zero): + psky_t *sky = tileSetupSky(DEFAULTPSKY); + sky->lognumtiles = 3; + sky->horizfrac = 32768; + + // CLOUDYOCEAN + // Aligns with the drawn scene horizon because it has one itself. + sky = tileSetupSky(CLOUDYOCEAN__DYN); + sky->lognumtiles = 3; + sky->horizfrac = 65536; + + // MOONSKY1 + // earth mountain mountain sun + sky = tileSetupSky(MOONSKY1__DYN); + sky->lognumtiles = 3; + sky->horizfrac = 32768; + sky->tileofs[6] = 1; + sky->tileofs[1] = 2; + sky->tileofs[4] = 2; + sky->tileofs[2] = 3; + + // BIGORBIT1 // orbit + // earth1 2 3 moon/sun + sky = tileSetupSky(BIGORBIT1__DYN); + sky->lognumtiles = 3; + sky->horizfrac = 32768; + sky->tileofs[5] = 1; + sky->tileofs[6] = 2; + sky->tileofs[7] = 3; + sky->tileofs[2] = 4; + + // LA // la city + // earth1 2 3 moon/sun + sky = tileSetupSky(LA__DYN); + sky->lognumtiles = 3; + sky->horizfrac = 16384 + 1024; + sky->tileofs[0] = 1; + sky->tileofs[1] = 2; + sky->tileofs[2] = 1; + sky->tileofs[3] = 3; + sky->tileofs[4] = 4; + sky->tileofs[5] = 0; + sky->tileofs[6] = 2; + sky->tileofs[7] = 3; + +#if 0 + // This assertion should hold. See note above. + for (bssize_t i=0; i= 0; i--) + { + if (sector[i].ceilingstat & 1) + { + skyIdx = getpskyidx(sector[i].ceilingpicnum); + if (skyIdx > 0) + break; + } + } + + g_pskyidx = skyIdx; +} + +////////// + +void G_LoadLookups(void) +{ + int32_t j; + + auto fr = fileSystem.OpenFileReader("lookup.dat"); + if (!fr.isOpen()) + return; + + j = lookups.loadTable(fr); + + if (j < 0) + { + if (j == -1) + Printf("ERROR loading \"lookup.dat\": failed reading enough data.\n"); + + return; + } + + uint8_t paldata[768]; + + for (j=1; j<=5; j++) + { + // Account for TITLE and REALMS swap between basepal number and on-disk order. + int32_t basepalnum = (j == 3 || j == 4) ? 4+3-j : j; + + if (fr.Read(paldata, 768) != 768) + return; + + for (bssize_t k = 0; k < 768; k++) + paldata[k] <<= 2; + + paletteSetColorTable(basepalnum, paldata, basepalnum == DREALMSPAL || basepalnum == ENDINGPAL, basepalnum < DREALMSPAL); + } + + for (int i = 0; i < 256; i++) + { + // swap red and blue channels. + paldata[i * 3] = GPalette.BaseColors[i].b; + paldata[i * 3+1] = GPalette.BaseColors[i].g; + paldata[i * 3+2] = GPalette.BaseColors[i].r; + } + paletteSetColorTable(DRUGPAL, paldata, false, false); // todo: implement this as a shader effect (swap R and B in postprocessing.) + + if (RR) + { + uint8_t table[256]; + for (bssize_t i = 0; i < 256; i++) + table[i] = i; + for (bssize_t i = 0; i < 32; i++) + table[i] = i+32; + + lookups.makeTable(7, table, 0, 0, 0, 0); + + for (bssize_t i = 0; i < 256; i++) + table[i] = i; + lookups.makeTable(30, table, 0, 0, 0, 0); + lookups.makeTable(31, table, 0, 0, 0, 0); + lookups.makeTable(32, table, 0, 0, 0, 0); + lookups.makeTable(33, table, 0, 0, 0, 0); + if (RRRA) + lookups.makeTable(105, table, 0, 0, 0, 0); + + j = 63; + for (bssize_t i = 64; i < 80; i++) + { + j--; + table[i] = j; + table[i+16] = i-24; + } + table[80] = 80; + table[81] = 81; + for (bssize_t i = 0; i < 32; i++) + table[i] = i+32; + lookups.makeTable(34, table, 0, 0, 0, 0); + for (bssize_t i = 0; i < 256; i++) + table[i] = i; + for (bssize_t i = 0; i < 16; i++) + table[i] = i+129; + for (bssize_t i = 16; i < 32; i++) + table[i] = i+192; + lookups.makeTable(35, table, 0, 0, 0, 0); + if (RRRA) + { + lookups.makeTable(50, NULL, 12 * 4, 12 * 4, 12 * 4, 0); + lookups.makeTable(51, NULL, 12 * 4, 12 * 4, 12 * 4, 0); + lookups.makeTable(54, lookups.getTable(8), 32 * 4, 32 * 4, 32 * 4, 0); + } + } +} + + +END_DUKE_NS diff --git a/source/duke/src/common_game.h b/source/duke/src/common_game.h new file mode 100644 index 000000000..11d723e76 --- /dev/null +++ b/source/duke/src/common_game.h @@ -0,0 +1,67 @@ +// +// Definitions of common game-only data structures/functions +// (and declarations of data appearing in both) +// for EDuke32 and Mapster32 +// + +#ifndef EDUKE32_COMMON_GAME_H_ +#define EDUKE32_COMMON_GAME_H_ + +#include "gamecontrol.h" + +BEGIN_DUKE_NS + + +#define DUKE (g_gameType & GAMEFLAG_DUKE) +#define RR (g_gameType & GAMEFLAG_RRALL) +#define RRRA (g_gameType & GAMEFLAG_RRRA) +#define NAM (g_gameType & GAMEFLAG_NAM) +#define NAPALM (g_gameType & GAMEFLAG_NAPALM) +#define WW2GI (g_gameType & GAMEFLAG_WW2GI) +#define NAM_WW2GI (g_gameType & (GAMEFLAG_NAM|GAMEFLAG_WW2GI)) +#define SHAREWARE (g_gameType & GAMEFLAG_SHAREWARE) +#define DEER (g_gameType & GAMEFLAG_DEER) +//#define DUKEBETA ((g_gameType & GAMEFLAG_DUKEBETA) == GAMEFLAG_DUKEBETA) +//#define IONMAIDEN (g_gameType & GAMEFLAG_IONMAIDEN) + +enum Games_t { + GAME_DUKE = 0, + GAME_RR, + GAME_RRRA, + GAME_NAM, + GAME_NAPALM, + //GAME_WW2GI, + GAMECOUNT +}; + +typedef enum basepal_ { + BASEPAL = 0, + WATERPAL, + SLIMEPAL, + DREALMSPAL, + TITLEPAL, + ENDINGPAL, // 5 + ANIMPAL, + DRUGPAL, + BASEPALCOUNT +} basepal_t; + +#include "v_text.h" + + +extern int loaddefinitions_game(const char *fn, int32_t preload); + +////////// + +extern void G_InitMultiPsky(int CLOUDYOCEAN__DYN, int MOONSKY1__DYN, int BIGORBIT1__DYN, int LA__DYN); +extern void G_SetupGlobalPsky(void); + +////////// + +extern void G_LoadLookups(void); + +////////// + +END_DUKE_NS + +#endif diff --git a/source/duke/src/config.cpp b/source/duke/src/config.cpp new file mode 100644 index 000000000..9797ee0c0 --- /dev/null +++ b/source/duke/src/config.cpp @@ -0,0 +1,58 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! + +#include "duke3d.h" +#include "osdcmds.h" +#include "baselayer.h" +#include "cmdline.h" + +// we load this in to get default button and key assignments +// as well as setting up function mappings + +BEGIN_DUKE_NS + +int32_t CONFIG_ReadSetup(void) +{ + g_player[0].ps->aim_mode = 1; + ud.config.ShowOpponentWeapons = 0; + ud.automsg = 0; + ud.camerasprite = -1; + + ud.camera_time = 0;//4; + + ud.screen_tilting = 1; + ud.statusbarflags = STATUSBAR_NOSHRINK; + playerteam = 0; + ud.angleinterpolation = 0; + + ud.display_bonus_screen = 1; + ud.show_level_text = 1; + ud.screenfade = 1; + ud.menubackground = 1; + ud.slidebar_paldisabled = 1; + ud.shadow_pal = 4; + return 0; +} + +END_DUKE_NS diff --git a/source/duke/src/config.h b/source/duke/src/config.h new file mode 100644 index 000000000..c7f20de6c --- /dev/null +++ b/source/duke/src/config.h @@ -0,0 +1,37 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef config_public_h_ +#define config_public_h_ + +#include "gamecontrol.h" + +BEGIN_DUKE_NS + +#define SETUPNAMEPARM "SETUPFILE" + +int32_t CONFIG_ReadSetup( void ); +void CONFIG_GetSetupFilename( void ); + +END_DUKE_NS + +#endif diff --git a/source/duke/src/d_menu.cpp b/source/duke/src/d_menu.cpp new file mode 100644 index 000000000..d6a8ffd52 --- /dev/null +++ b/source/duke/src/d_menu.cpp @@ -0,0 +1,795 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors +Copyright (C) 2019 Christoph Oelckers + +This 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. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! + +#include "cheats.h" +#include "compat.h" +#include "demo.h" +#include "duke3d.h" + +#include "menus.h" +#include "osdcmds.h" +#include "savegame.h" +#include "game.h" +#include "superfasthash.h" +#include "gamecvars.h" +#include "gamecontrol.h" +#include "c_bind.h" +#include "menu/menu.h" +#include "gstrings.h" +#include "version.h" +#include "namesdyn.h" +#include "../../glbackend/glbackend.h" + + +BEGIN_DUKE_NS + +#define MENU_MARGIN_REGULAR 40 +#define MENU_MARGIN_WIDE 32 +#define MENU_MARGIN_CENTER 160 +#define MENU_HEIGHT_CENTER 100 + + +enum MenuTextFlags_t +{ + MT_Selected = 1 << 0, + MT_Disabled = 1 << 1, + MT_XCenter = 1 << 2, + MT_XRight = 1 << 3, + MT_YCenter = 1 << 4, + MT_Literal = 1 << 5, + MT_RightSide = 1 << 6, +}; + + +// common font types +// tilenums are set after namesdyn runs. +// These are also modifiable by scripts. +// emptychar x,y between x,y zoom cursorLeft cursorCenter cursorScale textflags +// tilenum shade_deselected shade_disabled pal pal_selected pal_deselected pal_disabled +MenuFont_t MF_Redfont = { { 5<<16, 15<<16 }, { 0, 0 }, 65536, 20<<16, 110<<16, 65536, 65536, 65536, TEXT_BIGALPHANUM | TEXT_UPPERCASE, + -1, 10, 0, 0, 0, 0, 1, + 0, 0, 1 }; +MenuFont_t MF_Bluefont = { { 5<<16, 7<<16 }, { 0, 0 }, 65536, 10<<16, 110<<16, 32768, 65536, 65536, 0, + -1, 10, 0, 0, 10, 10, 16, + 0, 0, 16 }; +MenuFont_t MF_Minifont = { { 4<<16, 5<<16 }, { 1<<16, 1<<16 }, 65536, 10<<16, 110<<16, 32768, 65536, 65536, 0, + -1, 10, 0, 0, 2, 2, 0, + 0, 0, 16 }; + + +/* +This function prepares data after ART and CON have been processed. +It also initializes some data in loops rather than statically at compile time. +*/ + +void Menu_Init(void) +{ + + // prepare menu fonts + // check if tilenum is -1 in case it was set in EVENT_SETDEFAULTS + if ((unsigned)MF_Redfont.tilenum >= MAXTILES) MF_Redfont.tilenum = BIGALPHANUM; + if ((unsigned)MF_Bluefont.tilenum >= MAXTILES) MF_Bluefont.tilenum = STARTALPHANUM; + if ((unsigned)MF_Minifont.tilenum >= MAXTILES) MF_Minifont.tilenum = MINIFONT; + MF_Redfont.emptychar.y = tilesiz[MF_Redfont.tilenum].y << 16; + MF_Bluefont.emptychar.y = tilesiz[MF_Bluefont.tilenum].y << 16; + MF_Minifont.emptychar.y = tilesiz[MF_Minifont.tilenum].y << 16; + if (!minitext_lowercase) + MF_Minifont.textflags |= TEXT_UPPERCASE; + + + + if (RR) + { + MF_Redfont.zoom = 32768; + MF_Redfont.emptychar.x <<= 1; + MF_Redfont.cursorScale = 13107; + MF_Redfont.cursorScale2 = 6553; + //MF_Redfont.emptychar.y <<= 1; + MF_Bluefont.zoom = 32768; + MF_Bluefont.emptychar.x <<= 1; + MF_Bluefont.cursorScale = 6553; + MF_Bluefont.cursorScale2 = 6553; + //MF_Bluefont.emptychar.y <<= 1; + MF_Minifont.zoom = 32768; + MF_Minifont.emptychar.x <<= 1; + MF_Minifont.cursorScale = 6553; + MF_Minifont.cursorScale2 = 6553; + //MF_Minifont.emptychar.y <<= 1; + } + +} + + +static void Menu_DrawBackground(const DVector2 &origin) +{ + rotatesprite_fs(int(origin.X * 65536) + (MENU_MARGIN_CENTER << 16), int(origin.Y * 65536) + (100 << 16), 65536L, 0, MENUSCREEN, 16, 0, 10 + 64); +} + +static void Menu_DrawTopBar(const DVector2 &origin) +{ + rotatesprite_fs(int(origin.X*65536) + (MENU_MARGIN_CENTER<<16), int(origin.Y*65536) + (19<<16), MF_Redfont.cursorScale3, 0,MENUBAR,16,0,10); +} + +static void Menu_DrawTopBarCaption(const char* caption, const DVector2& origin) +{ + static char t[64]; + size_t const srclen = strlen(caption); + size_t const dstlen = min(srclen, ARRAY_SIZE(t) - 1); + memcpy(t, caption, dstlen); + t[dstlen] = '\0'; + char* p = &t[dstlen - 1]; + if (*p == ':') + *p = '\0'; + captionmenutext(int(origin.X * 65536) + (MENU_MARGIN_CENTER << 16), int(origin.Y * 65536) + (24 << 16) + (15 << 15), t); +} + +static void Menu_GetFmt(const MenuFont_t* font, uint8_t const status, int32_t* s) +{ + if (status & MT_Selected) + *s = sintable[((int32_t)totalclock << 5) & 2047] >> 12; + else + *s = font->shade_deselected; + // sum shade values + if (status & MT_Disabled) + *s += font->shade_disabled; +} + +static vec2_t Menu_Text(int32_t x, int32_t y, const MenuFont_t* font, const char* t, uint8_t status, int32_t ydim_upper, int32_t ydim_lower) +{ + int32_t s, p, ybetween = font->between.y; + int32_t f = font->textflags; + if (RR) f |= TEXT_RRMENUTEXTHACK; + if (status & MT_XCenter) + f |= TEXT_XCENTER; + if (status & MT_XRight) + f |= TEXT_XRIGHT; + if (status & MT_YCenter) + { + f |= TEXT_YCENTER | TEXT_YOFFSETZERO; + ybetween = font->emptychar.y; // <^ the battle against 'Q' + } + if (status & MT_Literal) + f |= TEXT_LITERALESCAPE; + + int32_t z = font->zoom; + + if (status & MT_Disabled) + p = (status & MT_RightSide) ? font->pal_disabled_right : font->pal_disabled; + else if (status & MT_Selected) + p = (status & MT_RightSide) ? font->pal_selected_right : font->pal_selected; + else + p = (status & MT_RightSide) ? font->pal_deselected_right : font->pal_deselected; + + Menu_GetFmt(font, status, &s); + + return G_ScreenText(font->tilenum, x, y, z, 0, 0, t, s, p, 2 | 8 | 16 | ROTATESPRITE_FULL16, 0, font->emptychar.x, font->emptychar.y, font->between.x, ybetween, f, 0, ydim_upper, xdim - 1, ydim_lower); +} + +static int32_t Menu_CursorShade(void) +{ + return 4 - (sintable[((int32_t)totalclock << 4) & 2047] >> 11); +} + +static void Menu_DrawCursorCommon(int32_t x, int32_t y, int32_t z, int32_t picnum, int32_t ydim_upper = 0, int32_t ydim_lower = ydim - 1) +{ + rotatesprite_(x, y, z, 0, picnum, Menu_CursorShade(), 0, 2 | 8, 0, 0, 0, ydim_upper, xdim - 1, ydim_lower); +} + +static void Menu_DrawCursorLeft(int32_t x, int32_t y, int32_t z) +{ + const int frames = RR ? 16 : 7; + Menu_DrawCursorCommon(x, y, z, SPINNINGNUKEICON+(((int32_t) totalclock>>3)%frames)); +} + +static void Menu_DrawCursorRight(int32_t x, int32_t y, int32_t z) +{ + const int frames = RR ? 16 : 7; + Menu_DrawCursorCommon(x, y, z, SPINNINGNUKEICON+frames-1-((frames-1+((int32_t) totalclock>>3))%frames)); +} + +static int Menu_GetFontHeight(int fontnum) +{ + auto& font = fontnum == NIT_BigFont ? MF_Redfont : fontnum == NIT_SmallFont ? MF_Bluefont : MF_Minifont; + return font.get_yline(); +} + +int dword_A99A0, dword_A99A4, dword_A99A8, dword_A99AC; +short word_A99B0, word_A99B2; +int dword_A99B4, dword_A99B8, dword_A99BC, dword_A99C0, dword_A99C4, dword_A99C8; + +void Menu_DHLeaonardHeadReset(void) +{ + dword_A99A0 = 0; + dword_A99A4 = 0; + dword_A99A8 = 0; + dword_A99AC = 0; + word_A99B2 = 0; + dword_A99B4 = 0; + word_A99B0 = 0; +} + +void Menu_DHLeaonardHeadDisplay(vec2_t pos) +{ + if (sub_51B68() && !dword_A99C0) + { + dword_A99C0 = (int)totalclock; + } + if (dword_A99C0 && (int)totalclock - dword_A99C0 > 40) + { + dword_A99C0 = 0; + dword_A99C4 = 1; + } + switch (dword_A99A0) + { + case 0: + if ((int)totalclock - dword_A99B8 >= 240 && dword_A99C4 && (rrdh_random() & 63) < 32) + { + dword_A99A0 = 1; + dword_A99A4 = 160 - ((rrdh_random() & 255) - 128); + word_A99B0 = ((rrdh_random() & 127) + 1984) & 2047; + dword_A99AC = (rrdh_random() & 4095) - 4090; + word_A99B2 = SPINNINGNUKEICON + (rrdh_random() & 15); + } + break; + case 1: + if (dword_A99A8 < 54) + { + if ((int)totalclock - dword_A99B4 > 2) + { + dword_A99B4 = (int)totalclock; + dword_A99A8 += 2; + } + } + else + { + dword_A99A0 = 2; + dword_A99BC = (int)totalclock; + } + pos.x += dword_A99A4 << 16; + pos.y += (240 - dword_A99A8) << 16; + rotatesprite(pos.x, pos.y, 32768 - dword_A99AC, word_A99B0, word_A99B2, 0, 0, 10, 0, 0, xdim - 1, ydim - 1); + break; + case 2: + if (dword_A99C4 == 1) + { + if ((rrdh_random() & 63) > 32) + word_A99B2--; + else + word_A99B2++; + } + else + { + if ((rrdh_random() & 127) == 48) + { + if ((int)totalclock - dword_A99BC > 240) + dword_A99A0 = 3; + } + } + if (word_A99B2 < SPINNINGNUKEICON) + word_A99B2 = SPINNINGNUKEICON + 15; + if (word_A99B2 > SPINNINGNUKEICON + 15) + word_A99B2 = SPINNINGNUKEICON; + pos.x += dword_A99A4 << 16; + pos.y += (240 - dword_A99A8) << 16; + rotatesprite(pos.x, pos.y, 32768 - dword_A99AC, word_A99B0, word_A99B2, 0, 0, 10, 0, 0, xdim - 1, ydim - 1); + if ((int)totalclock - dword_A99BC > 960) + dword_A99A0 = 3; + break; + case 3: + if (dword_A99A8 > 0) + { + if ((int)totalclock - dword_A99B4 > 2) + { + dword_A99B4 = (int)totalclock; + dword_A99A8 -= 2; + } + pos.x += dword_A99A4 << 16; + pos.y += (240 - dword_A99A8) << 16; + rotatesprite(pos.x, pos.y, 32768 - dword_A99AC, word_A99B0, word_A99B2, 0, 0, 10, 0, 0, xdim - 1, ydim - 1); + } + else + { + dword_A99B8 = (int)totalclock; + dword_A99A0 = 0; + } + break; + } + dword_A99C4 = 0; +} + + +//---------------------------------------------------------------------------- +// +// Implements the native looking menu used for the main menu +// and the episode/skill selection screens, i.e. the parts +// that need to look authentic +// +//---------------------------------------------------------------------------- + +class Duke3dListMenu : public DListMenu +{ + using Super = DListMenu; +protected: + + void Ticker() override + { + // Lay out the menu. + int32_t y_upper = mDesc->mYpos; + int32_t y_lower = y_upper + mDesc->mYbotton; + int32_t y = 0; + int32_t calculatedentryspacing = 0; + int32_t const height = Menu_GetFontHeight(mDesc->mNativeFontNum) >> 16; + + int32_t totalheight = 0, numvalidentries = mDesc->mItems.Size(); + + for (unsigned e = 0; e < mDesc->mItems.Size(); ++e) + { + auto entry = mDesc->mItems[e]; + entry->mHidden = false; + entry->SetHeight(height); + totalheight += height; + } + if (mDesc->mSpacing <= 0) calculatedentryspacing = std::max(0, (y_lower - y_upper - totalheight) / (numvalidentries > 1 ? numvalidentries - 1 : 1)); + if (calculatedentryspacing <= 0) calculatedentryspacing = mDesc->mSpacing; + + + // totalHeight calculating pass + int totalHeight; + for (unsigned e = 0; e < mDesc->mItems.Size(); ++e) + { + auto entry = mDesc->mItems[e]; + if (!entry->mHidden) + { + entry->SetY(y_upper + y); + y += height; + totalHeight = y; + y += calculatedentryspacing; + } + } + } +}; + +class Duke3dMainMenu : public Duke3dListMenu +{ + virtual void Init(DMenu* parent = NULL, FListMenuDescriptor* desc = NULL) override + { + Duke3dListMenu::Init(parent, desc); + Menu_DHLeaonardHeadReset(); + } + + void PreDraw() override + { + Duke3dListMenu::PreDraw(); + if (DEER) + { + vec2_t forigin = { int(origin.X * 65536), int(origin.Y * 65536) }; + Menu_DHLeaonardHeadDisplay(forigin); + rotatesprite_fs(forigin.x + (MENU_MARGIN_CENTER << 16), forigin.y + ((32) << 16), 20480L, 0, DUKENUKEM, 0, 0, 10); + } + else if (RRRA) + { + rotatesprite_fs(int(origin.X * 65536) + ((MENU_MARGIN_CENTER - 5) << 16), int(origin.Y * 65536) + ((57) << 16), 16592L, 0, THREEDEE, 0, 0, 10); + } + else if (RR) + { + rotatesprite_fs(int(origin.X * 65536) + ((MENU_MARGIN_CENTER + 5) << 16), int(origin.Y * 65536) + ((24) << 16), 23592L, 0, INGAMEDUKETHREEDEE, 0, 0, 10); + } + else + { + rotatesprite_fs(int(origin.X * 65536) + (MENU_MARGIN_CENTER<<16), int(origin.Y * 65536) + ((28)<<16), 65536L,0,INGAMEDUKETHREEDEE,0,0,10); + if (PLUTOPAK) // JBF 20030804 + rotatesprite_fs(int(origin.X * 65536) + ((MENU_MARGIN_CENTER+100)<<16), int(origin.Y * 65536) + (36<<16), 65536L,0,PLUTOPAKSPRITE+2,(sintable[((int32_t) totalclock<<4)&2047]>>11),0,2+8); + } + + } +}; + + +class Duke3dHuntMenu : public Duke3dListMenu +{ + void PreDraw() override + { + Duke3dListMenu::PreDraw(); + vec2_t forigin = { int(origin.X * 65536), int(origin.Y * 65536) }; + int t1, t2; + short ang; + switch (mDesc->mSelectedItem) + { + case 0: + default: + t1 = 7098; + t2 = 7041; + ang = 16; + break; + case 1: + t1 = 7099; + t2 = 7042; + ang = 2032; + break; + case 2: + t1 = 7100; + t2 = 7043; + ang = 16; + break; + case 3: + t1 = 7101; + t2 = 7044; + ang = 2032; + break; + } + rotatesprite_fs(forigin.x + (240 << 16), forigin.y + (56 << 16), 24576L, ang, t1, 2, 0, 64 + 10); + rotatesprite_fs(forigin.x + (240 << 16), forigin.y + (42 << 16), 24576L, ang, 7104, 2, 0, 10); + rotatesprite_fs(forigin.x + (20 << 16), forigin.y + (10 << 16), 32768L, 0, t2, -64, 0, 128 + 16 + 10); + } +}; + +class Duke3dTargetMenu : public Duke3dListMenu +{ + void PreDraw() override + { + Duke3dListMenu::PreDraw(); + vec2_t forigin = { int(origin.X * 65536), int(origin.Y * 65536) }; + int t1, t2; + short ang; + switch (mDesc->mSelectedItem) + { + case 0: + default: + t1 = 7102; + t2 = 7045; + ang = 16; + break; + case 1: + t1 = 7103; + t2 = 7046; + ang = 2032; + break; + break; + } + rotatesprite_fs(forigin.x + (240 << 16), forigin.y + (56 << 16), 24576L, ang, t1, 2, 0, 64 + 10); + rotatesprite_fs(forigin.x + (240 << 16), forigin.y + (42 << 16), 24576L, ang, 7104, 2, 0, 10); + rotatesprite_fs(forigin.x + (20 << 16), forigin.y + (10 << 16), 32768L, 0, t2, -64, 0, 128 + 16 + 10); + } +}; + +class Duke3dWeaponMenu : public Duke3dListMenu +{ + void PreDraw() override + { + Duke3dListMenu::PreDraw(); + vec2_t forigin = { int(origin.X * 65536), int(origin.Y * 65536) }; + int t1, t2; + switch (mDesc->mSelectedItem) + { + case 0: + default: + t1 = 7124; + t2 = 7066; + break; + case 1: + t1 = 7125; + t2 = 7067; + break; + case 2: + t1 = 7126; + t2 = 7068; + break; + case 3: + t1 = 7127; + t2 = 7069; + break; + case 4: + t1 = 7128; + t2 = 7070; + break; + } + rotatesprite_fs(forigin.x + (240 << 16), forigin.y + (56 << 16), 32768L, 0, t1, 2, 0, 64 + 10); + rotatesprite_fs(forigin.x + (8 << 16), forigin.y + (4 << 16), 32768L, 0, t2, -64, 0, 128 + 16 + 10); + } +}; + +class Duke3dTrophiesMenu : public Duke3dListMenu +{ + void PreDraw() override + { + Duke3dListMenu::PreDraw(); + vec2_t forigin = { int(origin.X * 65536), int(origin.Y * 65536) }; + if (g_player[myconnectindex].ps->gm & MODE_GAME) + { + if (ud.level_number < 4) + { + rotatesprite_fs(forigin.x + (160 << 16), forigin.y + (100 << 16), 65536, 0, 1730, 0, 0, 10); + sub_5469C(forigin, 0); + } + else + sub_5469C(forigin, 2); + } + else + { + rotatesprite_fs(forigin.x + (160 << 16), forigin.y + (100 << 16), 65536, 0, 1730, 0, 0, 10); + sub_5469C(forigin, 1); + } + } +}; + + +//---------------------------------------------------------------------------- +// +// Menu related game interface functions +// +//---------------------------------------------------------------------------- + +void GameInterface::DrawNativeMenuText(int fontnum, int state, double xpos, double ypos, float fontscale, const char* text, int flags) +{ + int ydim_upper = 0; + int ydim_lower = ydim - 1; + //int32_t const indent = 0; // not set for any relevant menu + int x = int(xpos * 65536); + + uint8_t status = 0; + if (state == NIT_SelectedState) + status |= MT_Selected; + if (state == NIT_InactiveState) + status |= MT_Disabled; + if (flags & LMF_Centered) + status |= MT_XCenter; + + bool const dodraw = true; + MenuFont_t& font = fontnum == NIT_BigFont ? MF_Redfont : fontnum == NIT_SmallFont ? MF_Bluefont : MF_Minifont; + + int32_t const height = font.get_yline(); + status |= MT_YCenter; + int32_t const y_internal = int(ypos * 65536) + ((height >> 17) << 16);// -menu->scrollPos; + + vec2_t textsize; + if (dodraw) + textsize = Menu_Text(x, y_internal, &font, text, status, ydim_upper, ydim_lower); + + if (dodraw && (status & MT_Selected) && state != 1) + { + if (status & MT_XCenter) + { + Menu_DrawCursorLeft(x + font.cursorCenterPosition, y_internal, font.cursorScale); + Menu_DrawCursorRight(x - font.cursorCenterPosition, y_internal, font.cursorScale); + } + else + Menu_DrawCursorLeft(x /*+ indent*/ - font.cursorLeftPosition, y_internal, font.cursorScale); + } + +} + +void GameInterface::MenuOpened() +{ + S_PauseSound(true, false); + if ((!g_netServer && ud.multimode < 2)) + { + ready2send = 0; + totalclock = ototalclock; + screenpeek = myconnectindex; + } + + auto& gm = g_player[myconnectindex].ps->gm; + if (gm & MODE_GAME) + { + gm |= MODE_MENU; + } +} + +void GameInterface::MenuSound(EMenuSounds snd) +{ + switch (snd) + { + case ActivateSound: + S_MenuSound(); + break; + + case CursorSound: + S_PlaySound(RR ? 335 : KICK_HIT, CHAN_AUTO, CHANF_UI); + break; + + case AdvanceSound: + S_PlaySound(RR ? 341 : PISTOL_BODYHIT, CHAN_AUTO, CHANF_UI); + break; + + case CloseSound: + S_PlaySound(EXITMENUSOUND, CHAN_AUTO, CHANF_UI); + break; + + default: + return; + } +} + +void GameInterface::MenuClosed() +{ + + auto& gm = g_player[myconnectindex].ps->gm; + if (gm & MODE_GAME) + { + if (gm & MODE_MENU) + inputState.ClearAllInput(); + + // The following lines are here so that you cannot close the menu when no game is running. + gm &= ~MODE_MENU; + + if ((!g_netServer && ud.multimode < 2) && ud.recstat != 2) + { + ready2send = 1; + totalclock = ototalclock; + CAMERACLOCK = (int32_t)totalclock; + CAMERADIST = 65536; + + // Reset next-viewscreen-redraw counter. + // XXX: are there any other cases like that in need of handling? + if (g_curViewscreen >= 0) + actor[g_curViewscreen].t_data[0] = (int32_t)totalclock; + } + + G_UpdateScreenArea(); + S_ResumeSound(false); + } +} + +bool GameInterface::CanSave() +{ + if (ud.recstat == 2 || DEER) return false; + auto &myplayer = *g_player[myconnectindex].ps; + if (sprite[myplayer.i].extra <= 0) + { + //P_DoQuote(QUOTE_SAVE_DEAD, &myplayer); // handled by the menu. + return false; + } + return true; +} + +void GameInterface::StartGame(FNewGameStartup& gs) +{ + int32_t skillsound = PISTOL_BODYHIT; + + soundEngine->StopAllChannels(); + + if (!DEER) + { + + switch (gs.Skill) + { + case 0: + skillsound = RR ? 427 : JIBBED_ACTOR6; + break; + case 1: + skillsound = RR ? 428 : BONUS_SPEECH1; + break; + case 2: + skillsound = RR ? 196 : DUKE_GETWEAPON2; + break; + case 3: + skillsound = RR ? 195 : JIBBED_ACTOR5; + break; + case 4: + skillsound = RR ? 197 : JIBBED_ACTOR5; // Does not exist in DN3D. + break; + } + ud.m_player_skill = gs.Skill + 1; + if (menu_sounds && skillsound >= 0 && SoundEnabled()) + { + S_PlaySound(skillsound, CHAN_AUTO, CHANF_UI); + + while (S_CheckSoundPlaying(skillsound)) + { + S_Update(); + G_HandleAsync(); + } + } + ud.m_respawn_monsters = (gs.Skill == 3); + ud.m_volume_number = gs.Episode; + m_level_number = gs.Level; + } + else + { + ud.m_player_skill = 1; + ud.m_respawn_monsters = 0; + ud.m_volume_number = 0; + m_level_number = gs.Episode; + g_player[myconnectindex].ps->dhat61f = gs.Skill; + } + + ud.m_monsters_off = ud.monsters_off = 0; + ud.m_respawn_items = 0; + ud.m_respawn_inventory = 0; + ud.multimode = 1; + G_NewGame_EnterLevel(); + +} + +FSavegameInfo GameInterface::GetSaveSig() +{ + return { SAVESIG_RR, MINSAVEVER_RR, SAVEVER_RR }; +} + +void GameInterface::DrawMenuCaption(const DVector2& origin, const char* text) +{ + Menu_DrawTopBar(origin); + Menu_DrawTopBarCaption(text, origin); +} + +void GameInterface::DrawCenteredTextScreen(const DVector2 &origin, const char *text, int position, bool bg) +{ + if (bg) Menu_DrawBackground(origin); + else + { + // Only used for the confirmation screen. + int lines = 1; + for (int i = 0; text[i]; i++) if (text[i] == '\n') lines++; + int height = lines * Menu_GetFontHeight(NIT_SmallFont); + position -= height >> 17; + if (!RR) Menu_DrawCursorLeft(160 << 16, 130 << 16, 65536); + } + G_ScreenText(MF_Bluefont.tilenum, int((origin.X + 160) * 65536), int((origin.Y + position) * 65536), MF_Bluefont.zoom, 0, 0, text, 0, MF_Bluefont.pal, + 2 | 8 | 16 | ROTATESPRITE_FULL16, 0, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, + MF_Bluefont.textflags | TEXT_XCENTER, 0, 0, xdim - 1, ydim - 1); +} + + +void GameInterface::DrawPlayerSprite(const DVector2& origin, bool onteam) +{ + if (RR) + rotatesprite_fs(int(origin.X * 65536) + (260<<16), int(origin.Y * 65536) + ((24+(tilesiz[APLAYER].y>>2))<<16), 24576L,0,3845+36-((((8-((int32_t) totalclock>>4)))&7)*5),0,onteam ? G_GetTeamPalette(playerteam) : G_CheckPlayerColor(playercolor),10); + else + rotatesprite_fs(int(origin.X * 65536) + (260<<16), int(origin.Y * 65536) + ((24+(tilesiz[APLAYER].y>>1))<<16), 49152L,0,1441-((((4-((int32_t) totalclock>>4)))&3)*5),0,onteam ? G_GetTeamPalette(playerteam) : G_CheckPlayerColor(playercolor),10); +} + +void GameInterface::QuitToTitle() +{ + g_player[myconnectindex].ps->gm = MODE_DEMO; + if (ud.recstat == 1) + G_CloseDemoWrite(); + artClearMapArt(); +} + +END_DUKE_NS + +//---------------------------------------------------------------------------- +// +// Class registration +// +//---------------------------------------------------------------------------- + + +static TMenuClassDescriptor _mm("Duke3d.MainMenu"); +static TMenuClassDescriptor _lm("Duke3d.ListMenu"); +static TMenuClassDescriptor _dhm("Duke3d.HuntMenu"); +static TMenuClassDescriptor _dtm("Duke3d.TargetMenu"); +static TMenuClassDescriptor _dwm("Duke3d.WeaponMenu"); +static TMenuClassDescriptor _dttm("Duke3d.TrophiesMenu"); +static TMenuClassDescriptor _ism("Duke3d.ImageScrollerMenu"); // does not implement a new class, we only need the descriptor. + +void RegisterDuke3dMenus() +{ + menuClasses.Push(&_mm); + menuClasses.Push(&_lm); + menuClasses.Push(&_ism); + menuClasses.Push(&_dhm); + menuClasses.Push(&_dtm); + menuClasses.Push(&_dwm); + menuClasses.Push(&_dttm); +} diff --git a/source/duke/src/demo.cpp b/source/duke/src/demo.cpp new file mode 100644 index 000000000..920ecb5fa --- /dev/null +++ b/source/duke/src/demo.cpp @@ -0,0 +1,944 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! + +#include "demo.h" +#include "duke3d.h" + +#include "menus.h" +#include "savegame.h" +#include "screens.h" + +BEGIN_DUKE_NS + +char g_firstDemoFile[BMAX_PATH]; + +FileWriter *g_demo_filePtr{}; // write +FileReader g_demo_recFilePtr; // read + +int32_t g_demo_cnt; +int32_t g_demo_goalCnt=0; +int32_t g_demo_totalCnt; +int32_t g_demo_paused=0; +int32_t g_demo_rewind=0; +int32_t g_demo_showStats=1; +static int32_t g_demo_soundToggle; + +static int32_t demo_hasdiffs, demorec_diffs=1, demorec_difftics = 2*REALGAMETICSPERSEC; +int32_t demoplay_diffs=1; +int32_t demorec_seeds_cvar=1; +int32_t demoplay_showsync=1; + +static int32_t demorec_seeds=1, demo_hasseeds; + +static void Demo_RestoreModes(int32_t menu) +{ + if (menu) + M_StartControlPanel(false); + else + M_ClearMenus(); + + g_player[myconnectindex].ps->gm &= ~MODE_GAME; + g_player[myconnectindex].ps->gm |= MODE_DEMO; +} + +void Demo_PrepareWarp(void) +{ + if (!g_demo_paused) + { + g_demo_soundToggle = nosound; + nosound = true; + } + + FX_StopAllSounds(); + S_ClearSoundLocks(); +} + + +static int32_t G_OpenDemoRead(int32_t g_whichDemo) // 0 = mine +{ + int32_t i; + savehead_t saveh; + + char demofn[14]; + const char *demofnptr; + + if (DEER) + return 0; + + if (g_whichDemo == 1 && g_firstDemoFile[0]) + { + demofnptr = g_firstDemoFile; + } + else + { + Bsprintf(demofn, DEMOFN_FMT, g_whichDemo); + demofnptr = demofn; + } + + if (!g_demo_recFilePtr.OpenFile(demofnptr)) + return 0; + + Bassert(g_whichDemo >= 1); + i = sv_loadsnapshot(g_demo_recFilePtr, -g_whichDemo, &saveh); + if (i) + { + Printf(TEXTCOLOR_RED "There were errors opening demo %d (code: %d).\n", g_whichDemo, i); + g_demo_recFilePtr.Close(); + return 0; + } + + demo_hasdiffs = saveh.recdiffsp; + g_demo_totalCnt = saveh.reccnt; + demo_hasseeds = 0; + + i = g_demo_totalCnt/REALGAMETICSPERSEC; + Printf("demo %d duration: %d min %d sec\n", g_whichDemo, i/60, i%60); + + g_demo_cnt = 1; + ud.reccnt = 0; + + gFullMap = false; + ud.god = ud.cashman = ud.eog = 0; + ud.noclip = ud.scrollmode = ud.overhead_on = 0; //= paused = 0; + + totalclock = ototalclock = lockclock = 0; + + return 1; +} + +#if KRANDDEBUG +extern void krd_enable(int32_t which); +extern int32_t krd_print(const char *filename); +#endif + +void G_OpenDemoWrite(void) +{ + char demofn[BMAX_PATH]; + int32_t i, demonum=1; + + if (ud.recstat == 2) + { + g_demo_recFilePtr.Close(); + } + + if ((g_player[myconnectindex].ps->gm&MODE_GAME) && g_player[myconnectindex].ps->dead_flag) + { + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "CANNOT START DEMO RECORDING WHEN DEAD!"); + P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); + ud.recstat = m_recstat = 0; + return; + } + do + { + if (demonum == MAXDEMOS) + return; + + if (snprintf(demofn, sizeof(demofn), "%s" DEMOFN_FMT, G_GetDemoPath().GetChars(), demonum)) + { + Printf("Couldn't start demo writing: INTERNAL ERROR: file name too long\n"); + goto error_wopen_demo; + } + + demonum++; + + g_demo_filePtr = FileWriter::Open(demofn); + if (g_demo_filePtr == NULL) + break; + + delete g_demo_filePtr; + } + while (1); + + g_demo_filePtr = FileWriter::Open(demofn); + if (g_demo_filePtr == NULL) + return; + + i=sv_saveandmakesnapshot(*g_demo_filePtr, -1, (demorec_seeds_cvar<<1)); + if (i) + { + delete g_demo_filePtr; + g_demo_filePtr = nullptr; +error_wopen_demo: + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "FAILED STARTING DEMO RECORDING. SEE CONSOLE FOR DETAILS."); + P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); + ud.recstat = m_recstat = 0; + return; + } + + demorec_seeds = demorec_seeds_cvar; + demorec_diffs = demorec_diffs_cvar; + demorec_difftics = demorec_difftics_cvar; + + quoteMgr.FormatQuote(QUOTE_RESERVED4, "DEMO %d RECORDING STARTED", demonum-1); + P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); + + ud.reccnt = 0; + ud.recstat = m_recstat = 1; // + +# if KRANDDEBUG + krd_enable(1); +# endif + g_demo_cnt = 1; +} + +// demo_profile: < 0: prepare +static int32_t g_demo_playFirstFlag, g_demo_profile, g_demo_stopProfile; +static int32_t g_demo_exitAfter; +void Demo_PlayFirst(int32_t prof, int32_t exitafter) +{ + g_demo_playFirstFlag = 1; + g_demo_exitAfter = exitafter; + Bassert(prof >= 0); + g_demo_profile = -prof; // prepare +} + +void Demo_SetFirst(const char *demostr) +{ + char *tailptr; + int32_t i = Bstrtol(demostr, &tailptr, 10); + + if (tailptr==demostr+Bstrlen(demostr) && (unsigned)i < MAXDEMOS) // demo number passed + Bsprintf(g_firstDemoFile, DEMOFN_FMT, i); + else // demo file name passed + maybe_append_ext(g_firstDemoFile, sizeof(g_firstDemoFile), demostr, ".edm"); +} + + +static uint8_t g_demo_seedbuf[RECSYNCBUFSIZ]; + +static void Demo_WriteSync() +{ + int16_t tmpreccnt; + + g_demo_filePtr->Write("sYnC", 4); + tmpreccnt = (int16_t)ud.reccnt; + g_demo_filePtr->Write(&tmpreccnt, sizeof(int16_t)); + if (demorec_seeds) + g_demo_filePtr->Write(g_demo_seedbuf, ud.reccnt); + + g_demo_filePtr->Write(recsync, sizeof(input_t)* ud.reccnt); + + ud.reccnt = 0; +} + +void G_DemoRecord(void) +{ + int16_t i; + + g_demo_cnt++; + + if (demorec_diffs && (g_demo_cnt%demorec_difftics == 1)) + { + sv_writediff(g_demo_filePtr); + demorec_difftics = demorec_difftics_cvar; + } + + if (demorec_seeds) + g_demo_seedbuf[ud.reccnt] = (uint8_t)(randomseed>>24); + + for (TRAVERSE_CONNECT(i)) + { + Bmemcpy(&recsync[ud.reccnt], g_player[i].input, sizeof(input_t)); + ud.reccnt++; + } + + if (ud.reccnt > RECSYNCBUFSIZ-MAXPLAYERS || (demorec_diffs && (g_demo_cnt%demorec_difftics == 0))) + Demo_WriteSync(); +} + +void G_CloseDemoWrite(void) +{ + if (ud.recstat == 1) + { + if (ud.reccnt > 0) + Demo_WriteSync(); + + g_demo_filePtr->Write("EnD!", 4); + + // lastly, we need to write the number of written recsyncs to the demo file + g_demo_filePtr->Write(&g_demo_cnt, sizeof(g_demo_cnt)); + + ud.recstat = m_recstat = 0; + delete g_demo_filePtr; + g_demo_filePtr = nullptr; + + sv_freemem(); + + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "DEMO RECORDING STOPPED"); + P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); + } +#if KRANDDEBUG + krd_print("krandrec.log"); +#endif +} + +static int32_t g_whichDemo = 1; + +static int32_t Demo_UpdateState(int32_t frominit) +{ + int32_t j = g_player[myconnectindex].ps->gm&MODE_MENU; + int32_t k = sv_updatestate(frominit); + // tmpdifftime = g_demo_cnt+12; + Demo_RestoreModes(j); + + if (k) + Printf("sv_updatestate() returned %d.\n", k); + return k; +} + +#define CORRUPT(code) do { corruptcode=code; goto corrupt; } while(0) + +static int32_t Demo_ReadSync(int32_t errcode) +{ + uint16_t si; + int32_t i; + + if (g_demo_recFilePtr.Read(&si, sizeof(uint16_t)) != sizeof(uint16_t)) + return errcode; + + i = si; + if (demo_hasseeds) + { + if (g_demo_recFilePtr.Read(g_demo_seedbuf, i) != i) + return errcode; + } + + + int32_t bytes = sizeof(input_t)*i; + + if (g_demo_recFilePtr.Read(recsync, bytes) != bytes) + return errcode+2; + + ud.reccnt = i; + return 0; +} + +////////// DEMO PROFILING (TIMEDEMO MODE) ////////// +static struct { + int32_t numtics, numframes; + double totalgamems; + double totalroomsdrawms, totalrestdrawms; + double starthiticks; +} g_prof; + +int32_t Demo_IsProfiling(void) +{ + return (g_demo_profile > 0); +} + +static void Demo_StopProfiling(void) +{ + g_demo_stopProfile = 1; +} + +static void Demo_GToc(double t) +{ + g_prof.numtics++; + g_prof.totalgamems += timerGetHiTicks()-t; +} + +static void Demo_RToc(double t1, double t2) +{ + g_prof.numframes++; + g_prof.totalroomsdrawms += t2-t1; + g_prof.totalrestdrawms += timerGetHiTicks()-t2; +} + +static void Demo_DisplayProfStatus(void) +{ + char buf[64]; + + static int32_t lastpercent=-1; + int32_t percent = (100*g_demo_cnt)/g_demo_totalCnt; + + if (lastpercent == percent) + return; + lastpercent = percent; + + videoClearScreen(0); + snprintf(buf, sizeof(buf), "timing... %d/%d game tics (%d %%)", + g_demo_cnt, g_demo_totalCnt, percent); + gametext_center(60, buf); + videoNextPage(); +} + +static void Demo_SetupProfile(void) +{ + g_demo_profile *= -1; // now >0: profile for real + + g_demo_soundToggle = nosound; + nosound = true; // restored by Demo_FinishProfile() + + Bmemset(&g_prof, 0, sizeof(g_prof)); + + g_prof.starthiticks = timerGetHiTicks(); +} + +static void Demo_FinishProfile(void) +{ + if (Demo_IsProfiling()) + { + int32_t dn=g_whichDemo-1; + int32_t nt=g_prof.numtics, nf=g_prof.numframes; + double gms=g_prof.totalgamems; + double dms1=g_prof.totalroomsdrawms, dms2=g_prof.totalrestdrawms; + + nosound = g_demo_soundToggle; + + if (nt > 0) + { + Printf("== demo %d: %d gametics\n", dn, nt); + Printf("== demo %d game times: %.03f ms (%.03f us/gametic)\n", + dn, gms, (gms*1000.0)/nt); + } + + if (nf > 0) + { + Printf("== demo %d: %d frames (%d frames/gametic)\n", dn, nf, g_demo_profile-1); + Printf("== demo %d drawrooms times: %.03f s (%.03f ms/frame)\n", + dn, dms1/1000.0, dms1/nf); + Printf("== demo %d drawrest times: %.03f s (%.03f ms/frame)\n", + dn, dms2/1000.0, dms2/nf); + } + + { + double totalprofms = gms+dms1+dms2; + double totalms = timerGetHiTicks()-g_prof.starthiticks; + if (totalprofms != 0) + Printf("== demo %d: non-profiled time overhead: %.02f %%\n", + dn, 100.0*totalms/totalprofms - 100.0); + } + } + + g_demo_profile = 0; + g_demo_stopProfile = 0; +} +//////////////////// + +int32_t G_PlaybackDemo(void) +{ + int32_t bigi, j, initsyncofs = 0, lastsyncofs = 0, lastsynctic = 0, lastsyncclock = 0; + int32_t foundemo = 0, corruptcode, outofsync=0; + static int32_t in_menu = 0; + // static int32_t tmpdifftime=0; + + totalclock = 0; + ototalclock = 0; + lockclock = 0; + + if (ready2send) + return 0; + + if (!g_demo_playFirstFlag) + g_demo_profile = 0; + +RECHECK: + if (g_demo_playFirstFlag) + g_demo_playFirstFlag = 0; + else if (g_demo_exitAfter) + G_GameExit(" "); + +#if KRANDDEBUG + if (foundemo) + krd_print("krandplay.log"); +#endif + + in_menu = g_player[myconnectindex].ps->gm&MODE_MENU; + + pub = NUMPAGES; + pus = NUMPAGES; + + renderFlushPerms(); + +#ifdef PLAYDEMOLOOP // Todo: Make a CVar. + if (!g_netServer && ud.multimode < 2) + foundemo = G_OpenDemoRead(g_whichDemo); +#endif + + if (foundemo == 0) + { + ud.recstat = 0; + + if (g_whichDemo > 1) + { + g_whichDemo = 1; + goto RECHECK; + } + + fadepal(0,0,0, 0,252,28); + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + G_DrawBackground(); + //M_DisplayMenus(); + videoNextPage(); + fadepal(0,0,0, 252,0,-28); + ud.reccnt = 0; + } + else + { + ud.recstat = 2; + + g_whichDemo++; + if (g_whichDemo == MAXDEMOS) + g_whichDemo = 1; + + g_player[myconnectindex].ps->gm &= ~MODE_GAME; + g_player[myconnectindex].ps->gm |= MODE_DEMO; + + lastsyncofs = g_demo_recFilePtr.Tell(); + initsyncofs = lastsyncofs; + lastsynctic = g_demo_cnt; + lastsyncclock = (int32_t) totalclock; + outofsync = 0; +#if KRANDDEBUG + krd_enable(2); +#endif + if (g_demo_profile < 0) + { + Demo_SetupProfile(); + } + } + + if (foundemo == 0 || in_menu || inputState.CheckAllInput() || numplayers > 1) + { + FX_StopAllSounds(); + S_ClearSoundLocks(); + M_StartControlPanel(false); + } + + ready2send = 0; + bigi = 0; + + inputState.ClearAllInput(); + + // Printf("ticcnt=%d, total=%d\n", g_demo_cnt, g_demo_totalCnt); + while (g_demo_cnt < g_demo_totalCnt || foundemo==0) + { + // Main loop here. It also runs when there's no demo to show, + // so maybe a better name for this function would be + // G_MainLoopWhenNotInGame()? + + // Demo requested from the OSD, its name is in g_firstDemoFile[] + if (g_demo_playFirstFlag) + { + g_demo_playFirstFlag = 0; + g_whichDemo = 1; // force g_firstDemoFile[] + g_demo_paused = 0; + goto nextdemo_nomenu; + } + + if (foundemo && (!g_demo_paused || g_demo_goalCnt)) + { + if (g_demo_goalCnt>0 && g_demo_goalCnt < g_demo_cnt) + { + // initialize rewind + + int32_t menu = g_player[myconnectindex].ps->gm&MODE_MENU; + + if (g_demo_goalCnt > lastsynctic) + { + // we can use a previous diff + if (Demo_UpdateState(0)==0) + { + g_demo_cnt = lastsynctic; + g_demo_recFilePtr.Seek(lastsyncofs, FileReader::SeekSet); + ud.reccnt = 0; + + totalclock = ototalclock = lockclock = lastsyncclock; + } + else CORRUPT(-1); + } + else + { + // update to initial state + if (Demo_UpdateState(1) == 0) + { + g_demo_recFilePtr.Seek(initsyncofs, FileReader::SeekSet); + g_levelTextTime = 0; + + g_demo_cnt = 1; + ud.reccnt = 0; + + totalclock = ototalclock = lockclock = 0; + } + else CORRUPT(0); + } + + Demo_RestoreModes(menu); + } + + if (g_demo_stopProfile) + Demo_FinishProfile(); + + while (totalclock >= (lockclock+TICSPERFRAME) + // || (ud.reccnt > REALGAMETICSPERSEC*2 && paused) + || (g_demo_goalCnt>0 && g_demo_cnt0 && ud.reccnt/ud.multimode >= g_demo_goalCnt-g_demo_cnt)) + { + Demo_UpdateState(0); + } + } + } + else if (Bmemcmp(tmpbuf, "EnD!", 4)==0) + goto nextdemo; + else CORRUPT(12); + + if (0) + { +corrupt: + Printf(TEXTCOLOR_RED "Demo %d is corrupt (code %d).\n", g_whichDemo-1, corruptcode); +nextdemo: + M_StartControlPanel(false); +nextdemo_nomenu: + foundemo = 0; + ud.reccnt = 0; + g_demo_recFilePtr.Close(); + + if (g_demo_goalCnt>0) + { + g_demo_goalCnt=0; + nosound = g_demo_soundToggle; + } + + if (Demo_IsProfiling()) // don't reset g_demo_profile if it's < 0 + Demo_FinishProfile(); + goto RECHECK; + } + } + + if (demo_hasseeds) + outofsync = ((uint8_t)(randomseed>>24) != g_demo_seedbuf[bigi]); + + for (TRAVERSE_CONNECT(j)) + { + Bmemcpy(&inputfifo[movefifoplc&(MOVEFIFOSIZ-1)][j], &recsync[bigi], sizeof(input_t)); + bigi++; + ud.reccnt--; + } + + g_demo_cnt++; + + S_Update(); + + if (Demo_IsProfiling()) + { + double t = timerGetHiTicks(); + G_DoMoveThings(); + Demo_GToc(t); + } + else if (!g_demo_paused) + { + // assumption that ud.multimode doesn't change in a demo may not be true + // sometime in the future v v v v v v v v v + if (g_demo_goalCnt==0 || !demo_hasdiffs || ud.reccnt/ud.multimode>=g_demo_goalCnt-g_demo_cnt) + { + G_DoMoveThings(); // increases lockclock by TICSPERFRAME + } + else + { + lockclock += TICSPERFRAME; + } + } + else + { + int32_t k = nosound; + nosound = true; + G_DoMoveThings(); + nosound = k; + } + + ototalclock += TICSPERFRAME; + + if (g_demo_goalCnt > 0) + { + // if fast-forwarding, we must update totalclock + totalclock += TICSPERFRAME; + +// Printf("t:%d, l+T:%d; cnt:%d, goal:%d%s", totalclock, (lockclock+TICSPERFRAME), +// g_demo_cnt, g_demo_goalCnt, g_demo_cnt>=g_demo_goalCnt?" ":"\n"); + if (g_demo_cnt>=g_demo_goalCnt) + { + g_demo_goalCnt = 0; + nosound = g_demo_soundToggle; + } + } + } + } + else if (foundemo && g_demo_paused) + { + totalclock = lockclock; + } + + if (Demo_IsProfiling()) + totalclock += TICSPERFRAME; + + if (G_FPSLimit()) + { + if (foundemo == 0) + { + G_DrawBackground(); + } + else + { + // NOTE: currently, no key/mouse events will be seen while + // demo-profiling because we need 'totalclock' for ourselves. + // And handleevents() -> sampletimer() would mess that up. + G_HandleLocalKeys(); + + // Render one frame (potentially many if profiling) + if (Demo_IsProfiling()) + { + int32_t i, num = g_demo_profile-1; + + Bassert(totalclock-ototalclock==4); + + for (i=0; i>16); + + G_DrawRooms(screenpeek, j); + + t2 = timerGetHiTicks(); + + G_DisplayRest(j); + + Demo_RToc(t1, t2); + } + + totalclock = ototalclock+4; + + // draw status + Demo_DisplayProfStatus(); + + if (inputState.CheckAllInput()) + Demo_StopProfiling(); + } + else + { + j = calc_smoothratio(totalclock, ototalclock); + if (g_demo_paused && g_demo_rewind) + j = 65536-j; + + G_DrawRooms(screenpeek, j); + G_DisplayRest(j); + + } +// totalclocklock = totalclock; + + if (!Demo_IsProfiling() && (g_player[myconnectindex].ps->gm&MODE_MENU) == 0) + { + if (demoplay_showsync && outofsync) + gametext_center(100, "OUT OF SYNC"); + + if (g_demo_showStats) + { + #if 0 + if (g_demo_cnt 1) && g_player[myconnectindex].ps->gm) + Net_GetPackets(); + + if (g_player[myconnectindex].gotvote == 0 && voting != -1 && voting != myconnectindex) + gametext_center(60, GStrings("TXT_PRESSF1_F2")); + } + + if ((g_player[myconnectindex].ps->gm&MODE_MENU) && (g_player[myconnectindex].ps->gm&MODE_EOL)) + { + Demo_FinishProfile(); + videoNextPage(); + goto RECHECK; + } + + if (Demo_IsProfiling()) + { + // Do nothing: sampletimer() is reached from M_DisplayMenus() -> + // Net_GetPackets() else. + } + else if (g_player[myconnectindex].ps->gm&MODE_TYPE) + { + Net_SendMessage(); + + if ((g_player[myconnectindex].ps->gm&MODE_TYPE) != MODE_TYPE) + { + g_player[myconnectindex].ps->gm = 0; + M_StartControlPanel(false); + } + } + else + { + //if (ud.recstat != 2) + //M_DisplayMenus(); + + if ((g_netServer || ud.multimode > 1))// && !Menu_IsTextInput(m_currentMenu)) + { + ControlInfo noshareinfo; + CONTROL_GetInput(&noshareinfo); + } + } + + if (!Demo_IsProfiling()) + G_PrintGameQuotes(screenpeek); + + if (ud.last_camsprite != ud.camerasprite) + ud.last_camsprite = ud.camerasprite; + + if (VOLUMEONE) + { + if ((g_player[myconnectindex].ps->gm&MODE_MENU) == 0) + rotatesprite_fs((320-50)<<16, 9<<16, 65536L, 0, BETAVERSION, 0, 0, 2+8+16+128); + } + + videoNextPage(); + } + + // NOTE: We must prevent handleevents() and Net_GetPackets() from + // updating totalclock when profiling (both via sampletimer()): + if (!Demo_IsProfiling()) + G_HandleAsync(); + + if (g_player[myconnectindex].ps->gm == MODE_GAME) + { + // user wants to play a game, quit showing demo! + + if (foundemo) + { +#if KRANDDEBUG + krd_print("krandplay.log"); +#endif + g_demo_recFilePtr.Close(); + } + + return 0; + } + } + + ud.multimode = numplayers; // fixes 2 infinite loops after watching demo + g_demo_recFilePtr.Close(); + + Demo_FinishProfile(); + + // if we're in the menu, try next demo immediately + if (g_player[myconnectindex].ps->gm&MODE_MENU) + goto RECHECK; + +#if KRANDDEBUG + if (foundemo) + krd_print("krandplay.log"); +#endif + + // finished playing a demo and not in menu: + // return so that e.g. the title can be shown + return 1; +} + +END_DUKE_NS diff --git a/source/duke/src/demo.h b/source/duke/src/demo.h new file mode 100644 index 000000000..077308bc5 --- /dev/null +++ b/source/duke/src/demo.h @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef demo_h_ +#define demo_h_ + +#include "compat.h" +#include "files.h" + +BEGIN_DUKE_NS + + +#define DEMOFN_FMT "edemo%03d.edm" +#define LDEMOFN_FMT "demo%d.dmo" +#define MAXDEMOS 1000 + +extern FileWriter * g_demo_filePtr; +extern char g_firstDemoFile[BMAX_PATH]; + +extern int32_t g_demo_cnt; +extern int32_t g_demo_goalCnt; +extern int32_t g_demo_paused; +extern FileReader g_demo_recFilePtr; +extern int32_t g_demo_rewind; +extern int32_t g_demo_showStats; +extern int32_t g_demo_totalCnt; + +int32_t G_PlaybackDemo(void); +void Demo_PrepareWarp(void); +void G_CloseDemoWrite(void); +void G_DemoRecord(void); +void G_OpenDemoWrite(void); + +void Demo_PlayFirst(int32_t prof, int32_t exitafter); +void Demo_SetFirst(const char *demostr); + +int32_t Demo_IsProfiling(void); + +#if KRANDDEBUG +int32_t krd_print(const char *filename); +void krd_enable(int32_t which); +#endif + +END_DUKE_NS + +#endif diff --git a/source/duke/src/duke3d.h b/source/duke/src/duke3d.h new file mode 100644 index 000000000..e3545af5d --- /dev/null +++ b/source/duke/src/duke3d.h @@ -0,0 +1,242 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef duke3d_h_ +#define duke3d_h_ + +// JBF +#include "baselayer.h" +#include "build.h" + +#include "compat.h" + +#include "pragmas.h" + +#include "polymost.h" +#include "gamecvars.h" +#include "menu/menu.h" + +BEGIN_DUKE_NS + +#define VOLUMEALL (g_Shareware == 0) +#define PLUTOPAK (g_scriptVersion >= 14) +#define VOLUMEONE (g_Shareware == 1) + +// increase by 3, because atomic GRP adds 1, and Shareware adds 2 +// Non-Lua build +# define BYTEVERSION_EDUKE32 336 + +//#define BYTEVERSION_13 27 +//#define BYTEVERSION_14 116 +//#define BYTEVERSION_15 117 +#define BYTEVERSION (BYTEVERSION_EDUKE32+(PLUTOPAK?1:(VOLUMEONE<<1))) + +#define NUMPAGES 1 + +#define RECSYNCBUFSIZ 2520 //2520 is the (LCM of 1-8)*3 +#define MOVEFIFOSIZ 256 + +#define MAXLEVELS 64 +#define MAXGAMETYPES 16 + +enum { + MUS_FIRST_SPECIAL = MAXVOLUMES*MAXLEVELS, + + MUS_INTRO = MUS_FIRST_SPECIAL, + MUS_BRIEFING = MUS_FIRST_SPECIAL + 1, + MUS_LOADING = MUS_FIRST_SPECIAL + 2, +}; + +////////// TIMING CONSTANTS ////////// +// The number of 'totalclock' increments per second: +#define TICRATE 120 +// The number of game state updates per second: +#define REALGAMETICSPERSEC 30 +// The number of 'totalclock' increments per game state update: +// NOTE: calling a game state update a 'frame' is really weird. +// (This used to be TICRATE/GAMETICSPERSEC, which was 120/26 = 4.615~ truncated +// to 4 by integer division.) +#define TICSPERFRAME (TICRATE/REALGAMETICSPERSEC) +// Used as a constant to satisfy all of the calculations written with ticrate = +// 26 in mind: +#define GAMETICSPERSEC 26 + + +#define PACKBUF_SIZE 32768 + +#define TILE_SAVESHOT (MAXTILES-1) +#define TILE_LOADSHOT (MAXTILES-3) +#define TILE_TILT (MAXTILES-2) +#define TILE_ANIM (MAXTILES-4) +#define TILE_VIEWSCR (MAXTILES-5) +// Reserved: TILE_VIEWSCR_1 (MAXTILES-6) +// Reserved: TILE_VIEWSCR_2 (MAXTILES-7) +EDUKE32_STATIC_ASSERT(7 <= MAXTILES-MAXUSERTILES); + +// sprites with these statnums should be considered for fixing +#define ROTFIXSPR_STATNUMP(k) ((k)==STAT_DEFAULT || (k)==STAT_STANDABLE || (k)==STAT_FX || \ + (k)==STAT_FALLER || (k)==STAT_LIGHT) +#define ROTFIXSPR_MAGIC 0x18190000 + +// JBF 20040604: sync is a function on some platforms +#define sync dsync + +// Uncomment the following to remove calls to a.nasm functions with the GL renderers +// so that debugging with valgrind --smc-check=none is possible: +//#define DEBUG_VALGRIND_NO_SMC + +END_DUKE_NS + +#include "actors.h" +#include "common_game.h" +#include "config.h" +#include "gamecontrol.h" +#include "game.h" +#include "gamedef.h" +#include "gamedefs.h" +#include "gameexec.h" +#include "gamevars.h" +#include "global.h" +#include "inv.h" +#include "macros.h" +#include "namesdyn.h" +#include "net.h" +#include "player.h" +#include "quotes.h" +#include "rts.h" +#include "text.h" +#include "sector.h" +#include "sounds.h" +#include "soundsdyn.h" +#include "rrdh.h" + +BEGIN_DUKE_NS + +// Order is that of EDuke32 by necessity because it exposes the key binds to scripting by index instead of by name. +enum GameFunction_t +{ + gamefunc_Move_Forward, + gamefunc_Move_Backward, + gamefunc_Turn_Left, + gamefunc_Turn_Right, + gamefunc_Strafe, + gamefunc_Fire, + gamefunc_Open, + gamefunc_Run, + gamefunc_Alt_Fire, // Duke3D, Blood + gamefunc_Jump, + gamefunc_Crouch, + gamefunc_Look_Up, + gamefunc_Look_Down, + gamefunc_Look_Left, + gamefunc_Look_Right, + gamefunc_Strafe_Left, + gamefunc_Strafe_Right, + gamefunc_Aim_Up, + gamefunc_Aim_Down, + gamefunc_Weapon_1, + gamefunc_Weapon_2, + gamefunc_Weapon_3, + gamefunc_Weapon_4, + gamefunc_Weapon_5, + gamefunc_Weapon_6, + gamefunc_Weapon_7, + gamefunc_Weapon_8, + gamefunc_Weapon_9, + gamefunc_Weapon_10, + gamefunc_Inventory, + gamefunc_Inventory_Left, + gamefunc_Inventory_Right, + gamefunc_Holo_Duke, // Duke3D, RR + gamefunc_Jetpack, + gamefunc_NightVision, + gamefunc_MedKit, + gamefunc_TurnAround, + gamefunc_SendMessage, + gamefunc_Map, + gamefunc_Shrink_Screen, + gamefunc_Enlarge_Screen, + gamefunc_Center_View, + gamefunc_Holster_Weapon, + gamefunc_Show_Opponents_Weapon, + gamefunc_Map_Follow_Mode, + gamefunc_See_Coop_View, + gamefunc_Mouse_Aiming, + gamefunc_Toggle_Crosshair, + gamefunc_Steroids, + gamefunc_Quick_Kick, + gamefunc_Next_Weapon, + gamefunc_Previous_Weapon, + gamefunc_Dpad_Select, + gamefunc_Dpad_Aiming, + gamefunc_Last_Weapon, + gamefunc_Alt_Weapon, + gamefunc_Third_Person_View, + gamefunc_Show_DukeMatch_Scores, + gamefunc_Toggle_Crouch, // This is the last one used by EDuke32. + NUM_ACTIONS +}; + +static inline int32_t G_HaveActor(int spriteNum) +{ + return g_tile[spriteNum].execPtr!=NULL; +} + +static inline int32_t G_DefaultActorHealth(int spriteNum) +{ + return G_HaveActor(spriteNum) ? g_tile[spriteNum].execPtr[0] : 0; +} + + +struct GameInterface : ::GameInterface +{ + const char* Name() override { return "Redneck"; } + int app_main() override; + void UpdateScreenSize() override; + void FreeGameData() override; + bool GenerateSavePic() override; + bool validate_hud(int) override; + void set_hud_layout(int size) override; + void set_hud_scale(int size) override; + FString statFPS() override; + GameStats getStats() override; + void DrawNativeMenuText(int fontnum, int state, double xpos, double ypos, float fontscale, const char* text, int flags) override; + void MenuOpened() override; + void MenuSound(EMenuSounds snd) override; + void MenuClosed() override; + bool CanSave() override; + void StartGame(FNewGameStartup& gs) override; + FSavegameInfo GetSaveSig() override; + void DrawCenteredTextScreen(const DVector2& origin, const char* text, int position, bool bg) override; + void DrawMenuCaption(const DVector2& origin, const char* text) override; + bool SaveGame(FSaveGameNode*) override; + bool LoadGame(FSaveGameNode*) override; + void DoPrintMessage(int prio, const char* text) override; + void DrawPlayerSprite(const DVector2& origin, bool onteam) override; + void QuitToTitle() override; + FString GetCoordString() override; + int GetStringTile(int font, const char* t, int f) override; +}; + +END_DUKE_NS + +#endif diff --git a/source/duke/src/events_defs.h b/source/duke/src/events_defs.h new file mode 100644 index 000000000..e31e3db34 --- /dev/null +++ b/source/duke/src/events_defs.h @@ -0,0 +1,50 @@ + +#ifndef EDUKE32_EVENTS_DEFS_H_ +#define EDUKE32_EVENTS_DEFS_H_ + +// the order of these can't be changed or else compatibility with EDuke 2.0 mods will break +enum GameEvent_t { + EVENT_INIT, // 0 + EVENT_ENTERLEVEL, + EVENT_RESETWEAPONS, + EVENT_RESETINVENTORY, + EVENT_HOLSTER, + EVENT_LOOKLEFT, // 5 + EVENT_LOOKRIGHT, + EVENT_SOARUP, + EVENT_SOARDOWN, + EVENT_CROUCH, + EVENT_JUMP, // 10 + EVENT_RETURNTOCENTER, + EVENT_LOOKUP, + EVENT_LOOKDOWN, + EVENT_AIMUP, + EVENT_FIRE, // 15 + EVENT_CHANGEWEAPON, + EVENT_GETSHOTRANGE, + EVENT_GETAUTOAIMANGLE, + EVENT_GETLOADTILE, + EVENT_CHEATGETSTEROIDS, // 20 + EVENT_CHEATGETHEAT, + EVENT_CHEATGETBOOT, + EVENT_CHEATGETSHIELD, + EVENT_CHEATGETSCUBA, + EVENT_CHEATGETHOLODUKE, // 25 + EVENT_CHEATGETJETPACK, + EVENT_CHEATGETFIRSTAID, + EVENT_QUICKKICK, + EVENT_INVENTORY, + EVENT_USENIGHTVISION, // 30 + EVENT_USESTEROIDS, + EVENT_INVENTORYLEFT, + EVENT_INVENTORYRIGHT, + EVENT_HOLODUKEON, + EVENT_HOLODUKEOFF, // 35 + EVENT_USEMEDKIT, + EVENT_USEJETPACK, + EVENT_TURNAROUND, + MAXEVENTS, + EVENT_AIMDOWN = EVENT_AIMUP, +}; + +#endif diff --git a/source/duke/src/filestream.cpp b/source/duke/src/filestream.cpp new file mode 100644 index 000000000..ded1dbaf5 --- /dev/null +++ b/source/duke/src/filestream.cpp @@ -0,0 +1,136 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010-2020 EDuke32 developers and contributors +Copyright (C) 2020 sirlemonhead +This file is part of Rednukem. +Rednukem 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. +*/ +//------------------------------------------------------------------------- + +#include "filestream.h" +#include + +namespace RedNukem { + +bool FileStream::Open(const char *fileName) +{ + file = kopen4loadfrommod(fileName, 0); + if (file == -1) + { + // log error + return false; + } + + return true; +} + +bool FileStream::Is_Open() +{ + return file != -1; +} + +void FileStream::Close() +{ + kclose(file); + file = -1; +} + +int32_t FileStream::ReadBytes(uint8_t *data, uint32_t nBytes) +{ + uint32_t nCount = (uint32_t)kread(file, data, static_cast(nBytes)); + + if (nCount != nBytes) { + return 0; + } + + return (int32_t)nCount; +} + +uint64_t FileStream::ReadUint64LE() +{ + uint64_t value; + kread(file, &value, 8); + return B_LITTLE64(value); +} + +uint64_t FileStream::ReadUint64BE() +{ + uint64_t value; + kread(file, &value, 8); + return B_BIG64(value); +} + +uint32_t FileStream::ReadUint32LE() +{ + uint32_t value; + kread(file, &value, 4); + return B_LITTLE32(value); +} + +uint32_t FileStream::ReadUint32BE() +{ + uint32_t value; + kread(file, &value, 4); + return B_BIG32(value); +} + +uint16_t FileStream::ReadUint16LE() +{ + uint16_t value; + kread(file, &value, 2); + return B_LITTLE16(value); +} + +uint16_t FileStream::ReadUint16BE() +{ + uint16_t value; + kread(file, &value, 2); + return B_BIG16(value); +} + +uint8_t FileStream::ReadByte() +{ + uint8_t value; + kread(file, &value, 1); + return value; +} + +int32_t FileStream::Seek(int32_t offset, SeekDirection direction) +{ + int32_t nStatus = -1; + if (kSeekStart == direction) + { + nStatus = klseek(file, offset, SEEK_SET); + } + else if (kSeekCurrent == direction) + { + nStatus = klseek(file, offset, SEEK_CUR); + } + else if (kSeekEnd == direction) + { + nStatus = klseek(file, offset, SEEK_END); + } + + return nStatus; +} + +int32_t FileStream::Skip(int32_t offset) +{ + return Seek(offset, kSeekCurrent); +} + +int32_t FileStream::GetPosition() +{ + return ktell(file); +} + +} // close namespace RedNukem diff --git a/source/duke/src/filestream.h b/source/duke/src/filestream.h new file mode 100644 index 000000000..190446988 --- /dev/null +++ b/source/duke/src/filestream.h @@ -0,0 +1,65 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010-2020 EDuke32 developers and contributors +Copyright (C) 2020 sirlemonhead +This file is part of Rednukem. +Rednukem 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. +*/ +//------------------------------------------------------------------------- + +#ifndef _RedNukemFileStream_h_ +#define _RedNukemFileStream_h_ + +#include "vfs.h" +#include "compat.h" +#include + +namespace RedNukem { + +class FileStream +{ + public: + bool Open(const char *fileName); + bool Is_Open(); + void Close(); + + int32_t ReadBytes(uint8_t *data, uint32_t nBytes); + + uint64_t ReadUint64LE(); + uint64_t ReadUint64BE(); + + uint32_t ReadUint32LE(); + uint32_t ReadUint32BE(); + + uint16_t ReadUint16LE(); + uint16_t ReadUint16BE(); + + uint8_t ReadByte(); + + enum SeekDirection { + kSeekCurrent = 0, + kSeekStart = 1, + kSeekEnd = 2 + }; + + int32_t Seek(int32_t offset, SeekDirection = kSeekStart); + int32_t Skip(int32_t offset); + + int32_t GetPosition(); + + private: + buildvfs_kfd file; +}; + +} // close namespace RedNukem + +#endif diff --git a/source/duke/src/game.cpp b/source/duke/src/game.cpp new file mode 100644 index 000000000..69a307325 --- /dev/null +++ b/source/duke/src/game.cpp @@ -0,0 +1,7779 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! + +#define game_c_ + +#include "duke3d.h" +#include "compat.h" +#include "baselayer.h" +#include "osdcmds.h" +#include "net.h" +#include "menus.h" +#include "savegame.h" +#include "anim.h" +#include "demo.h" + +#include "cheats.h" +#include "sbar.h" +#include "screens.h" +#include "cmdline.h" +#include "palette.h" +#include "gamecvars.h" +#include "gameconfigfile.h" +#include "printf.h" +#include "m_argv.h" +#include "filesystem.h" +#include "statistics.h" +#include "c_dispatch.h" +#include "mapinfo.h" +#include "v_video.h" +#include "glbackend/glbackend.h" +#include "playmve.h" + +// Uncomment to prevent anything except mirrors from drawing. It is sensible to +// also uncomment ENGINE_CLEAR_SCREEN in build/src/engine_priv.h. +//#define DEBUG_MIRRORS_ONLY + +#if KRANDDEBUG +# define GAME_INLINE +# define GAME_STATIC +#else +# define GAME_INLINE inline +# define GAME_STATIC static +#endif + +BEGIN_DUKE_NS + + +int32_t g_quitDeadline = 0; + +int32_t g_cameraDistance = 0, g_cameraClock = 0; +static int32_t g_quickExit; + +char boardfilename[BMAX_PATH] = {0}; + +int32_t voting = -1; +int32_t vote_map = -1, vote_episode = -1; + +int32_t g_Debug = 0; + +const char *defaultrtsfilename[GAMECOUNT] = { "DUKE.RTS", "REDNECK.RTS", "REDNECK.RTS", "NAM.RTS", "NAPALM.RTS" }; + +int32_t g_Shareware = 0; + +int32_t tempwallptr; + +static int32_t nonsharedtimer; + +int32_t ticrandomseed; + +GAME_STATIC GAME_INLINE int32_t G_MoveLoop(void); + +int32_t g_levelTextTime = 0; + +#if defined(RENDERTYPEWIN) && defined(USE_OPENGL) +extern char forcegl; +#endif + +const char *G_DefaultRtsFile(void) +{ + if (DUKE) + return defaultrtsfilename[GAME_DUKE]; + else if (NAPALM) + { + if (!fileSystem.FileExists(defaultrtsfilename[GAME_NAPALM]) && fileSystem.FileExists(defaultrtsfilename[GAME_NAM])) + return defaultrtsfilename[GAME_NAM]; // NAM/NAPALM Sharing + else + return defaultrtsfilename[GAME_NAPALM]; + } + else if (NAM) + { + if (!fileSystem.FileExists(defaultrtsfilename[GAME_NAM]) && fileSystem.FileExists(defaultrtsfilename[GAME_NAPALM])) + return defaultrtsfilename[GAME_NAPALM]; // NAM/NAPALM Sharing + else + return defaultrtsfilename[GAME_NAM]; + } + else if (RR) + return defaultrtsfilename[GAME_RR]; + + return defaultrtsfilename[0]; +} + +enum gametokens +{ + T_INCLUDE = 0, + T_INTERFACE = 0, + T_LOADGRP = 1, + T_MODE = 1, + T_CACHESIZE = 2, + T_ALLOW = 2, + T_NOAUTOLOAD, + T_INCLUDEDEFAULT, + T_MUSIC, + T_SOUND, + T_FILE, + T_CUTSCENE, + T_ANIMSOUNDS, + T_NOFLOORPALRANGE, + T_ID, + T_MINPITCH, + T_MAXPITCH, + T_PRIORITY, + T_TYPE, + T_DISTANCE, + T_VOLUME, + T_DELAY, + T_RENAMEFILE, + T_GLOBALGAMEFLAGS, + T_ASPECT, + T_FORCEFILTER, + T_FORCENOFILTER, + T_TEXTUREFILTER, +}; + +static void gameTimerHandler(void) +{ + S_Update(); + G_HandleSpecialKeys(); +} + +void G_HandleSpecialKeys(void) +{ + // we need CONTROL_GetInput in order to pick up joystick button presses + if (!(g_player[myconnectindex].ps->gm & MODE_GAME)) + { + ControlInfo noshareinfo; + CONTROL_GetInput(&noshareinfo); + } + + // only dispatch commands here when not in a game + if (!(g_player[myconnectindex].ps->gm & MODE_GAME)) + OSD_DispatchQueued(); + + if (g_quickExit == 0 && inputState.GetKeyStatus(sc_LeftControl) && inputState.GetKeyStatus(sc_LeftAlt) && (inputState.GetKeyStatus(sc_Delete)||inputState.GetKeyStatus(sc_End))) + { + g_quickExit = 1; + G_GameExit("Quick Exit."); + } +} + +void G_GameQuit(void) +{ + if (numplayers < 2) + G_GameExit(" "); + + if (g_gameQuit == 0) + { + g_gameQuit = 1; + g_quitDeadline = (int32_t) totalclock+120; + //g_netDisconnect = 1; + } + + if ((totalclock > g_quitDeadline) && (g_gameQuit == 1)) + g_netDisconnect = 1; + //G_GameExit("Timed out."); +} + + +int32_t A_CheckInventorySprite(spritetype *s) +{ + switch (DYNAMICTILEMAP(s->picnum)) + { + case FIRSTAID__STATIC: + case STEROIDS__STATIC: + case HEATSENSOR__STATIC: + case BOOTS__STATIC: + case JETPACK__STATIC: + case HOLODUKE__STATIC: + case AIRTANK__STATIC: + return 1; + default: + return 0; + } +} + +void G_OnMotorcycle(DukePlayer_t *pPlayer, int spriteNum) +{ + if (!pPlayer->on_motorcycle && !(sector[pPlayer->cursectnum].lotag == 2)) + { + if (spriteNum) + { + pPlayer->pos.x = sprite[spriteNum].x; + pPlayer->pos.y = sprite[spriteNum].y; + pPlayer->q16ang = F16(sprite[spriteNum].ang); + pPlayer->ammo_amount[MOTORCYCLE_WEAPON] = sprite[spriteNum].owner; + A_DeleteSprite(spriteNum); + } + pPlayer->over_shoulder_on = 0; + pPlayer->on_motorcycle = 1; + pPlayer->last_full_weapon = pPlayer->curr_weapon; + pPlayer->curr_weapon = MOTORCYCLE_WEAPON; + pPlayer->gotweapon |= (1 << MOTORCYCLE_WEAPON); + pPlayer->vel.x = 0; + pPlayer->vel.y = 0; + pPlayer->q16horiz = F16(100); + } + if (!A_CheckSoundPlaying(pPlayer->i,186)) + A_PlaySound(186, pPlayer->i); +} + +void G_OffMotorcycle(DukePlayer_t *pPlayer) +{ + int j; + if (pPlayer->on_motorcycle) + { + if (A_CheckSoundPlaying(pPlayer->i,188)) + S_StopEnvSound(188,pPlayer->i); + if (A_CheckSoundPlaying(pPlayer->i,187)) + S_StopEnvSound(187,pPlayer->i); + if (A_CheckSoundPlaying(pPlayer->i,186)) + S_StopEnvSound(186,pPlayer->i); + if (A_CheckSoundPlaying(pPlayer->i,214)) + S_StopEnvSound(214,pPlayer->i); + if (!A_CheckSoundPlaying(pPlayer->i,42)) + A_PlaySound(42, pPlayer->i); + pPlayer->on_motorcycle = 0; + pPlayer->gotweapon &= ~(1<curr_weapon = pPlayer->last_full_weapon; + P_CheckWeapon(pPlayer); + pPlayer->q16horiz = F16(100); + pPlayer->moto_do_bump = 0; + pPlayer->moto_speed = 0; + pPlayer->tilt_status = 0; + pPlayer->moto_drink = 0; + pPlayer->moto_bump_target = 0; + pPlayer->moto_bump = 0; + pPlayer->moto_turb = 0; + pPlayer->vel.x = 0; + pPlayer->vel.y = 0; + pPlayer->vel.x -= sintable[(fix16_to_int(pPlayer->q16ang)+512)&2047]<<7; + pPlayer->vel.y -= sintable[fix16_to_int(pPlayer->q16ang)&2047]<<7; + pPlayer->moto_underwater = 0; + j = A_Spawn(pPlayer->i, EMPTYBIKE); + sprite[j].ang = fix16_to_int(pPlayer->q16ang); + sprite[j].xvel += sintable[(fix16_to_int(pPlayer->q16ang)+512)&2047]<<7; + sprite[j].yvel += sintable[fix16_to_int(pPlayer->q16ang)&2047]<<7; + sprite[j].owner = pPlayer->ammo_amount[MOTORCYCLE_WEAPON]; + } +} + +void G_OnBoat(DukePlayer_t *pPlayer, int spriteNum) +{ + if (!pPlayer->on_boat) + { + if (spriteNum) + { + pPlayer->pos.x = sprite[spriteNum].x; + pPlayer->pos.y = sprite[spriteNum].y; + pPlayer->q16ang = F16(sprite[spriteNum].ang); + pPlayer->ammo_amount[BOAT_WEAPON] = sprite[spriteNum].owner; + deletesprite(spriteNum); + } + pPlayer->over_shoulder_on = 0; + pPlayer->on_boat = 1; + pPlayer->last_full_weapon = pPlayer->curr_weapon; + pPlayer->curr_weapon = BOAT_WEAPON; + pPlayer->gotweapon |= (1<vel.x = 0; + pPlayer->vel.y = 0; + pPlayer->q16horiz = F16(100); + } +} + +void G_OffBoat(DukePlayer_t *pPlayer) +{ + int j; + if (pPlayer->on_boat) + { + pPlayer->on_boat = 0; + pPlayer->gotweapon &= ~(1<curr_weapon = pPlayer->last_full_weapon; + P_CheckWeapon(pPlayer); + pPlayer->q16horiz = F16(100); + pPlayer->moto_do_bump = 0; + pPlayer->moto_speed = 0; + pPlayer->tilt_status = 0; + pPlayer->moto_drink = 0; + pPlayer->moto_bump_target = 0; + pPlayer->moto_bump = 0; + pPlayer->moto_turb = 0; + pPlayer->vel.x = 0; + pPlayer->vel.y = 0; + pPlayer->vel.x -= sintable[(fix16_to_int(pPlayer->q16ang)+512)&2047]<<7; + pPlayer->vel.y -= sintable[fix16_to_int(pPlayer->q16ang)&2047]<<7; + pPlayer->moto_underwater = 0; + j = A_Spawn(pPlayer->i, EMPTYBOAT); + sprite[j].ang = fix16_to_int(pPlayer->q16ang); + sprite[j].xvel += sintable[(fix16_to_int(pPlayer->q16ang)+512)&2047]<<7; + sprite[j].yvel += sintable[fix16_to_int(pPlayer->q16ang)&2047]<<7; + sprite[j].owner = pPlayer->ammo_amount[BOAT_WEAPON]; + } +} + + + +void G_GameExit(const char *msg) +{ + if (*msg != 0) g_player[myconnectindex].ps->palette = BASEPAL; + + if (ud.recstat == 1) + G_CloseDemoWrite(); + else if (ud.recstat == 2) + { + delete g_demo_filePtr; + g_demo_filePtr = nullptr; + } + // JBF: fixes crash on demo playback + // PK: modified from original + + if (!g_quickExit) + { + if (g_mostConcurrentPlayers > 1 && g_player[myconnectindex].ps->gm&MODE_GAME && GTFLAGS(GAMETYPE_SCORESHEET) && *msg == ' ') + { + G_BonusScreen(1); + } + + // shareware and TEN screens + if (*msg != 0 && *(msg+1) != 'V' && *(msg+1) != 'Y') + G_DisplayExtraScreens(); + } + + if (*msg != 0) + { + if (!(msg[0] == ' ' && msg[1] == 0)) + { + I_Error("%s", msg); + } + } + throw CExitEvent(0); +} + + + +static int32_t G_DoThirdPerson(const DukePlayer_t *pp, vec3_t *vect, int16_t *vsectnum, int16_t ang, int16_t horiz) +{ + spritetype *sp = &sprite[pp->i]; + int32_t i, hx, hy; + int32_t bakcstat = sp->cstat; + hitdata_t hit; + + vec3_t n = { + sintable[(ang+1536)&2047]>>4, + sintable[(ang+1024)&2047]>>4, + (horiz-100) * 128 + }; + + updatesectorz(vect->x,vect->y,vect->z,vsectnum); + + sp->cstat &= ~0x101; + hitscan(vect, *vsectnum, n.x,n.y,n.z, &hit, CLIPMASK1); + sp->cstat = bakcstat; + + if (*vsectnum < 0) + return -1; + + hx = hit.pos.x-(vect->x); + hy = hit.pos.y-(vect->y); + + if (klabs(n.x)+klabs(n.y) > klabs(hx)+klabs(hy)) + { + *vsectnum = hit.sect; + + if (hit.wall >= 0) + { + int32_t daang = getangle(wall[wall[hit.wall].point2].x-wall[hit.wall].x, + wall[wall[hit.wall].point2].y-wall[hit.wall].y); + + i = n.x*sintable[daang] + n.y*sintable[(daang+1536)&2047]; + + if (klabs(n.x) > klabs(n.y)) + hx -= mulscale28(n.x,i); + else hy -= mulscale28(n.y,i); + } + else if (hit.sprite < 0) + { + if (klabs(n.x) > klabs(n.y)) + hx -= (n.x>>5); + else hy -= (n.y>>5); + } + + if (klabs(n.x) > klabs(n.y)) + i = divscale16(hx,n.x); + else i = divscale16(hy,n.y); + + if (i < CAMERADIST) + CAMERADIST = i; + } + + vect->x += mulscale16(n.x,CAMERADIST); + vect->y += mulscale16(n.y,CAMERADIST); + vect->z += mulscale16(n.z,CAMERADIST); + + CAMERADIST = min(CAMERADIST+(((int32_t) totalclock-CAMERACLOCK)<<10),65536); + CAMERACLOCK = (int32_t) totalclock; + + updatesectorz(vect->x,vect->y,vect->z,vsectnum); + + return 0; +} + +int32_t SE150_TempSectorZ[MAXSECTORS]; +int32_t SE150_TempSectorPicnum[MAXSECTORS]; + +static void G_SE150_Draw(int32_t spnum, int32_t x, int32_t y, int32_t z, int32_t a, int32_t h, int32_t smoothratio) +{ + int32_t i = 13, j, k = 0; + int32_t floor1 = spnum, floor2 = 0, ok = 0, fofmode; + int32_t offx, offy; + + if (sprite[spnum].ang != 512) return; + + tileDelete(13); + if (!(gotpic[i >> 3] & (1 << (i & 7)))) return; + gotpic[i >> 3] &= ~(1 << (i & 7)); + + floor1 = spnum; + + if (sprite[spnum].lotag == 152) fofmode = 150; + if (sprite[spnum].lotag == 153) fofmode = 151; + if (sprite[spnum].lotag == 154) fofmode = 150; + if (sprite[spnum].lotag == 155) fofmode = 151; + + // fofmode=sprite[spnum].lotag-2; + + // sectnum=sprite[j].sectnum; + // sectnum=cursectnum; + ok++; + + /* recursive? + for(j=0;j= 0; i = nextspritestat[i]) + { + switch(sprite[i].lotag) + { +// case 40: +// case 41: +// SE40_Draw(i,x,y,a,smoothratio); +// break; + case 152: + case 153: + case 154: + case 155: + if(g_player[screenpeek].ps->cursectnum == sprite[i].sectnum) + G_SE150_Draw(i,x,y,z,a,h,smoothratio); + break; + } + } +} + +#ifdef LEGACY_ROR +char ror_protectedsectors[MAXSECTORS]; +static int32_t drawing_ror = 0; +static int32_t ror_sprite = -1; + +static void G_OROR_DupeSprites(const spritetype *sp) +{ + // dupe the sprites touching the portal to the other sector + int32_t k; + const spritetype *refsp; + + if ((unsigned)sp->yvel >= (unsigned)g_mostConcurrentPlayers) + return; + + refsp = &sprite[sp->yvel]; + + for (SPRITES_OF_SECT(sp->sectnum, k)) + { + if (spritesortcnt >= maxspritesonscreen) + break; + + if (sprite[k].picnum != SECTOREFFECTOR && sprite[k].z >= sp->z) + { + tspriteptr_t tsp = renderAddTSpriteFromSprite(k); + + tsp->x += (refsp->x - sp->x); + tsp->y += (refsp->y - sp->y); + tsp->z += -sp->z + actor[sp->yvel].ceilingz; + tsp->sectnum = refsp->sectnum; + +// Printf("duped sprite of pic %d at %d %d %d\n",tsp->picnum,tsp->x,tsp->y,tsp->z); + } + } +} + +static int16_t SE40backupStat[MAXSECTORS]; +static int32_t SE40backupZ[MAXSECTORS]; + +static void G_SE40(int32_t smoothratio) +{ + if ((unsigned)ror_sprite < MAXSPRITES) + { + int32_t x, y, z; + int16_t sect; + int32_t level = 0; + const spritetype *const sp = &sprite[ror_sprite]; + const int32_t sprite2 = sp->yvel; + + if ((unsigned)sprite2 >= MAXSPRITES) + return; + + if (klabs(sector[sp->sectnum].floorz - sp->z) < klabs(sector[sprite[sprite2].sectnum].floorz - sprite[sprite2].z)) + level = 1; + + x = CAMERA(pos.x) - sp->x; + y = CAMERA(pos.y) - sp->y; + z = CAMERA(pos.z) - (level ? sector[sp->sectnum].floorz : sector[sp->sectnum].ceilingz); + + sect = sprite[sprite2].sectnum; + updatesector(sprite[sprite2].x + x, sprite[sprite2].y + y, §); + + if (sect != -1) + { + int32_t renderz, picnum; + // XXX: PK: too large stack allocation for my taste + int32_t i; + int32_t pix_diff, newz; + // Printf("drawing ror\n"); + + if (level) + { + // renderz = sector[sprite[sprite2].sectnum].ceilingz; + renderz = sprite[sprite2].z - (sprite[sprite2].yrepeat * tilesiz[sprite[sprite2].picnum].y<<1); + picnum = sector[sprite[sprite2].sectnum].ceilingpicnum; + sector[sprite[sprite2].sectnum].ceilingpicnum = 562; + tileDelete(562); + + pix_diff = klabs(z) >> 8; + newz = - ((pix_diff / 128) + 1) * (128<<8); + + for (i = 0; i < numsectors; i++) + { + SE40backupStat[i] = sector[i].ceilingstat; + SE40backupZ[i] = sector[i].ceilingz; + if (!ror_protectedsectors[i] || sp->lotag == 41) + { + sector[i].ceilingstat = 1; + sector[i].ceilingz += newz; + } + } + } + else + { + // renderz = sector[sprite[sprite2].sectnum].floorz; + renderz = sprite[sprite2].z; + picnum = sector[sprite[sprite2].sectnum].floorpicnum; + sector[sprite[sprite2].sectnum].floorpicnum = 562; + tileDelete(562); + + pix_diff = klabs(z) >> 8; + newz = ((pix_diff / 128) + 1) * (128<<8); + + for (i = 0; i < numsectors; i++) + { + SE40backupStat[i] = sector[i].floorstat; + SE40backupZ[i] = sector[i].floorz; + if (!ror_protectedsectors[i] || sp->lotag == 41) + { + sector[i].floorstat = 1; + sector[i].floorz = +newz; + } + } + } + +#ifdef POLYMER + if (videoGetRenderMode() == REND_POLYMER) + polymer_setanimatesprites(G_DoSpriteAnimations, CAMERA(pos.x), CAMERA(pos.y), CAMERA(pos.z), fix16_to_int(CAMERA(q16ang)), smoothratio); +#endif + renderDrawRoomsQ16(sprite[sprite2].x + x, sprite[sprite2].y + y, + z + renderz, CAMERA(q16ang), CAMERA(q16horiz), sect); + drawing_ror = 1 + level; + + if (drawing_ror == 2) // viewing from top + G_OROR_DupeSprites(sp); + + G_DoSpriteAnimations(CAMERA(pos.x),CAMERA(pos.y),CAMERA(pos.z),fix16_to_int(CAMERA(q16ang)),smoothratio); + renderDrawMasks(); + + if (level) + { + sector[sprite[sprite2].sectnum].ceilingpicnum = picnum; + for (i = 0; i < numsectors; i++) + { + sector[i].ceilingstat = SE40backupStat[i]; + sector[i].ceilingz = SE40backupZ[i]; + } + } + else + { + sector[sprite[sprite2].sectnum].floorpicnum = picnum; + + for (i = 0; i < numsectors; i++) + { + sector[i].floorstat = SE40backupStat[i]; + sector[i].floorz = SE40backupZ[i]; + } + } + } + } +} +#endif + +void G_HandleMirror(int32_t x, int32_t y, int32_t z, fix16_t a, fix16_t q16horiz, int32_t smoothratio) +{ + if ((gotpic[MIRROR>>3]&(1<<(MIRROR&7))) +#ifdef POLYMER + && (videoGetRenderMode() != REND_POLYMER) +#endif + ) + { + if (g_mirrorCount == 0) + { + // NOTE: We can have g_mirrorCount==0 but gotpic'd MIRROR, + // for example in LNGA2. + gotpic[MIRROR>>3] &= ~(1<<(MIRROR&7)); + return; + } + + int32_t i = 0, dst = INT32_MAX; + + for (bssize_t k=g_mirrorCount-1; k>=0; k--) + { + if (!wallvisible(x, y, g_mirrorWall[k])) + continue; + + const int32_t j = + klabs(wall[g_mirrorWall[k]].x - x) + + klabs(wall[g_mirrorWall[k]].y - y); + + if (j < dst) + dst = j, i = k; + } + + if (wall[g_mirrorWall[i]].overpicnum != MIRROR) + { + // Try to find a new mirror wall in case the original one was broken. + + int32_t startwall = sector[g_mirrorSector[i]].wallptr; + int32_t endwall = startwall + sector[g_mirrorSector[i]].wallnum; + + for (bssize_t k=startwall; k= 0 && (wall[j].cstat&32) && wall[j].overpicnum==MIRROR) // cmp. premap.c + { + g_mirrorWall[i] = j; + break; + } + } + } + + if (wall[g_mirrorWall[i]].overpicnum == MIRROR) + { + int32_t tposx, tposy; + fix16_t tang; + + renderPrepareMirror(x, y, z, a, q16horiz, g_mirrorWall[i], &tposx, &tposy, &tang); + + int32_t j = g_visibility; + g_visibility = (j>>1) + (j>>2); + + renderDrawRoomsQ16(tposx,tposy,z,tang,q16horiz,g_mirrorSector[i]+MAXSECTORS); + display_mirror = 1; + G_DoSpriteAnimations(tposx,tposy,z,fix16_to_int(tang),smoothratio); + display_mirror = 0; + + renderDrawMasks(); + renderCompleteMirror(); //Reverse screen x-wise in this function + g_visibility = j; + } + +#ifdef SPLITSCREEN_MOD_HACKS + if (!g_fakeMultiMode) +#endif + { + // HACK for splitscreen mod: this is so that mirrors will be drawn + // from showview commands. Ugly, because we'll attempt do draw mirrors + // each frame then. But it's better than not drawing them, I guess. + // XXX: fix the sequence of setting/clearing this bit. Right now, + // we always draw one frame without drawing the mirror, after which + // the bit gets set and drawn subsequently. + gotpic[MIRROR>>3] &= ~(1<<(MIRROR&7)); + } + } +} + +void G_DrawRooms(int32_t playerNum, int32_t smoothRatio) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + int yxAspect = yxaspect; + int viewingRange = viewingrange; + + //if (g_networkMode == NET_DEDICATED_SERVER) return; + + totalclocklock = totalclock; + + if (pub > 0 || videoGetRenderMode() >= REND_POLYMOST) // JBF 20040101: redraw background always + { + videoClearScreen(0); +#ifndef EDUKE32_TOUCH_DEVICES + if (ud.screen_size >= 8) +#endif + G_DrawBackground(); + pub = 0; + } + + if (ud.overhead_on == 2 || (pPlayer->cursectnum == -1 && videoGetRenderMode() != REND_CLASSIC)) + return; + + if (r_usenewaspect) + { + newaspect_enable = 1; + videoSetCorrectedAspect(); + } + + if (paused || pPlayer->on_crane > -1) + smoothRatio = 65536; + else + smoothRatio = calc_smoothratio(totalclock, ototalclock); + + if (RRRA && g_fogType) + pPlayer->visibility = ud.const_visibility; + + int const playerVis = pPlayer->visibility; + g_visibility = (playerVis <= 0) ? 0 : (int32_t)(playerVis * (numplayers > 1 ? 1.f : r_ambientlightrecip)); + + CAMERA(sect) = pPlayer->cursectnum; + + G_DoInterpolations(smoothRatio); + G_AnimateCamSprite(smoothRatio); + + if (ud.camerasprite >= 0) + { + spritetype *const pSprite = &sprite[ud.camerasprite]; + + // XXX: what? + if (pSprite->yvel < 0) pSprite->yvel = -100; + else if (pSprite->yvel > 199) pSprite->yvel = 300; + + CAMERA(q16ang) = fix16_from_int(actor[ud.camerasprite].tempang + + mulscale16(((pSprite->ang + 1024 - actor[ud.camerasprite].tempang) & 2047) - 1024, smoothRatio)); + +#ifdef LEGACY_ROR + if (!RR) + G_SE40(smoothRatio); +#endif +#ifdef POLYMER + if (videoGetRenderMode() == REND_POLYMER) + polymer_setanimatesprites(G_DoSpriteAnimations, pSprite->x, pSprite->y, pSprite->z, fix16_to_int(CAMERA(q16ang)), smoothRatio); +#endif + yax_preparedrawrooms(); + renderDrawRoomsQ16(pSprite->x, pSprite->y, pSprite->z - ZOFFSET6, CAMERA(q16ang), fix16_from_int(pSprite->yvel), pSprite->sectnum); + yax_drawrooms(G_DoSpriteAnimations, pSprite->sectnum, 0, smoothRatio); + G_DoSpriteAnimations(pSprite->x, pSprite->y, pSprite->z, fix16_to_int(CAMERA(q16ang)), smoothRatio); + renderDrawMasks(); + } + else + { + int32_t floorZ, ceilZ; + + int const vr = divscale22(1, RR ? 64 : (sprite[pPlayer->i].yrepeat + 28)); + + viewingRange = Blrintf(float(vr) * tanf(r_fov * (PI/360.f))); + + if (!RRRA || !pPlayer->drug_mode) + { + if (!r_usenewaspect) + renderSetAspect(viewingRange, yxaspect); + else + { + yxAspect = tabledivide32_noinline(65536 * ydim * 8, xdim * 5); + + renderSetAspect(mulscale16(viewingRange,viewingrange), yxaspect); + } + } + + if (videoGetRenderMode() >= REND_POLYMOST && (ud.screen_tilting +#ifdef SPLITSCREEN_MOD_HACKS + && !g_fakeMultiMode +#endif + )) + { +#ifdef USE_OPENGL + renderSetRollAngle(fix16_to_float(pPlayer->q16rotscrnang)); +#endif + pPlayer->oq16rotscrnang = pPlayer->q16rotscrnang; + } + + if (RRRA && pPlayer->drug_mode > 0) + { + while (pPlayer->drug_timer < totalclock && !(pPlayer->gm & MODE_MENU) && !paused && !System_WantGuiCapture()) + { + int aspect; + if (pPlayer->drug_stat[0] == 0) + { + pPlayer->drug_stat[1]++; + aspect = viewingRange + pPlayer->drug_stat[1] * 5000; + if (viewingRange * 3 < aspect) + { + pPlayer->drug_aspect = viewingRange * 3; + pPlayer->drug_stat[0] = 2; + } + else + { + pPlayer->drug_aspect = aspect; + } + P_UpdateScreenPal(pPlayer); + } + else if (pPlayer->drug_stat[0] == 3) + { + pPlayer->drug_stat[1]--; + aspect = viewingRange + pPlayer->drug_stat[1] * 5000; + if (aspect < viewingRange) + { + pPlayer->drug_mode = 0; + pPlayer->drug_stat[0] = 0; + pPlayer->drug_stat[2] = 0; + pPlayer->drug_stat[1] = 0; + pPlayer->drug_aspect = viewingRange; + } + else + { + pPlayer->drug_aspect = aspect; + } + P_UpdateScreenPal(pPlayer); + } + else if (pPlayer->drug_stat[0] == 2) + { + if (pPlayer->drug_stat[2] > 30) + { + pPlayer->drug_stat[0] = 1; + } + else + { + pPlayer->drug_stat[2]++; + aspect = pPlayer->drug_stat[2] * 500 + viewingRange * 3; + pPlayer->drug_aspect = aspect; + P_UpdateScreenPal(pPlayer); + } + } + else + { + if (pPlayer->drug_stat[2] < 1) + { + pPlayer->drug_stat[0] = 2; + pPlayer->drug_mode--; + if (pPlayer->drug_mode == 1) + pPlayer->drug_stat[0] = 3; + } + else + { + pPlayer->drug_stat[2]--; + aspect = pPlayer->drug_stat[2] * 500 + viewingRange * 3; + pPlayer->drug_aspect = aspect; + P_UpdateScreenPal(pPlayer); + } + } + + pPlayer->drug_timer += TICSPERFRAME / 2; + } + if (!r_usenewaspect) + renderSetAspect(pPlayer->drug_aspect, yxaspect); + else + { + viewingRange = pPlayer->drug_aspect; + yxAspect = tabledivide32_noinline(65536 * ydim * 8, xdim * 5); + + renderSetAspect(mulscale16(viewingRange, viewingrange), yxaspect); + } + P_UpdateScreenPal(pPlayer); + } + + if (pPlayer->newowner < 0) + { + if (playerNum == myconnectindex && numplayers > 1) + { + vec3_t const camVect = { omypos.x + mulscale16(mypos.x - omypos.x, smoothRatio), + omypos.y + mulscale16(mypos.y - omypos.y, smoothRatio), + omypos.z + mulscale16(mypos.z - omypos.z, smoothRatio) }; + + CAMERA(pos) = camVect; + CAMERA(q16ang) = myang + pPlayer->q16look_ang; + CAMERA(q16horiz) = myhoriz + myhorizoff; + CAMERA(sect) = mycursectnum; + } + else + { + vec3_t const camVect = { pPlayer->opos.x + mulscale16(pPlayer->pos.x - pPlayer->opos.x, smoothRatio), + pPlayer->opos.y + mulscale16(pPlayer->pos.y - pPlayer->opos.y, smoothRatio), + pPlayer->opos.z + mulscale16(pPlayer->pos.z - pPlayer->opos.z, smoothRatio) }; + + CAMERA(pos) = camVect; + + if (pPlayer->wackedbyactor >= 0) + { + CAMERA(q16ang) = pPlayer->oq16ang + + mulscale16(((pPlayer->q16ang + F16(1024) - pPlayer->oq16ang) & 0x7FFFFFF) - F16(1024), smoothRatio) + + pPlayer->q16look_ang; + CAMERA(q16horiz) = pPlayer->oq16horiz + pPlayer->oq16horizoff + + mulscale16((pPlayer->q16horiz + pPlayer->q16horizoff - pPlayer->oq16horiz - pPlayer->oq16horizoff), smoothRatio); + } + else + { + CAMERA(q16ang) = pPlayer->q16ang + pPlayer->q16look_ang; + CAMERA(q16horiz) = pPlayer->q16horiz + pPlayer->q16horizoff; + } + } + + if (cl_viewbob) + { + int zAdd = (pPlayer->opyoff + mulscale16(pPlayer->pyoff-pPlayer->opyoff, smoothRatio)); + + if (pPlayer->over_shoulder_on) + zAdd >>= 3; + + CAMERA(pos.z) += zAdd; + } + + if (pPlayer->over_shoulder_on) + { + CAMERA(pos.z) -= 3072; + + if (G_DoThirdPerson(pPlayer, &CAMERA(pos), &CAMERA(sect), fix16_to_int(CAMERA(q16ang)), fix16_to_int(CAMERA(q16horiz))) < 0) + { + CAMERA(pos.z) += 3072; + G_DoThirdPerson(pPlayer, &CAMERA(pos), &CAMERA(sect), fix16_to_int(CAMERA(q16ang)), fix16_to_int(CAMERA(q16horiz))); + } + } + } + else + { + vec3_t const camVect = G_GetCameraPosition(pPlayer->newowner, smoothRatio); + + // looking through viewscreen + CAMERA(pos) = camVect; + CAMERA(q16ang) = pPlayer->q16ang + pPlayer->q16look_ang; + CAMERA(q16horiz) = fix16_from_int(100 + sprite[pPlayer->newowner].shade); + CAMERA(sect) = sprite[pPlayer->newowner].sectnum; + } + + ceilZ = actor[pPlayer->i].ceilingz; + floorZ = actor[pPlayer->i].floorz; + + if (g_earthquakeTime > 0 && pPlayer->on_ground == 1) + { + CAMERA(pos.z) += 256 - (((g_earthquakeTime)&1) << 9); + CAMERA(q16ang) += fix16_from_int((2 - ((g_earthquakeTime)&2)) << 2); + } + + if (sprite[pPlayer->i].pal == 1) + CAMERA(pos.z) -= (18<<8); + + if (pPlayer->newowner < 0 && pPlayer->spritebridge == 0) + { + // NOTE: when shrunk, p->pos.z can be below the floor. This puts the + // camera into the sector again then. + + if (CAMERA(pos.z) < (pPlayer->truecz + ZOFFSET6)) + CAMERA(pos.z) = ceilZ + ZOFFSET6; + else if (CAMERA(pos.z) > (pPlayer->truefz - ZOFFSET6)) + CAMERA(pos.z) = floorZ - ZOFFSET6; + } + + while (CAMERA(sect) >= 0) // if, really + { + getzsofslope(CAMERA(sect),CAMERA(pos.x),CAMERA(pos.y),&ceilZ,&floorZ); +#ifdef YAX_ENABLE + if (yax_getbunch(CAMERA(sect), YAX_CEILING) >= 0) + { + if (CAMERA(pos.z) < ceilZ) + { + updatesectorz(CAMERA(pos.x), CAMERA(pos.y), CAMERA(pos.z), &CAMERA(sect)); + break; // since CAMERA(sect) might have been updated to -1 + // NOTE: fist discovered in WGR2 SVN r134, til' death level 1 + // (Lochwood Hollow). A problem REMAINS with Polymost, maybe classic! + } + } + else +#endif + if (CAMERA(pos.z) < ceilZ+ZOFFSET6) + CAMERA(pos.z) = ceilZ+ZOFFSET6; + +#ifdef YAX_ENABLE + if (yax_getbunch(CAMERA(sect), YAX_FLOOR) >= 0) + { + if (CAMERA(pos.z) > floorZ) + updatesectorz(CAMERA(pos.x), CAMERA(pos.y), CAMERA(pos.z), &CAMERA(sect)); + } + else +#endif + if (CAMERA(pos.z) > floorZ-ZOFFSET6) + CAMERA(pos.z) = floorZ-ZOFFSET6; + + break; + } + + CAMERA(q16horiz) = fix16_clamp(CAMERA(q16horiz), F16(HORIZ_MIN), F16(HORIZ_MAX)); + + G_HandleMirror(CAMERA(pos.x), CAMERA(pos.y), CAMERA(pos.z), CAMERA(q16ang), CAMERA(q16horiz), smoothRatio); +#ifdef LEGACY_ROR + if (!RR) + G_SE40(smoothRatio); +#endif + if (RRRA) + G_SE150(CAMERA(pos.x), CAMERA(pos.y), CAMERA(pos.z), CAMERA(q16ang), CAMERA(q16horiz), smoothRatio); +#ifdef POLYMER + if (videoGetRenderMode() == REND_POLYMER) + polymer_setanimatesprites(G_DoSpriteAnimations, CAMERA(pos.x),CAMERA(pos.y),CAMERA(pos.z),fix16_to_int(CAMERA(q16ang)),smoothRatio); +#endif + // for G_PrintCoords + dr_viewingrange = viewingrange; + dr_yxaspect = yxaspect; +#ifdef DEBUG_MIRRORS_ONLY + gotpic[MIRROR>>3] |= (1<<(MIRROR&7)); +#else + if (RR && sector[CAMERA(sect)].lotag == 848) + { + yax_preparedrawrooms(); + renderDrawRoomsQ16(CAMERA(pos.x),CAMERA(pos.y),CAMERA(pos.z),CAMERA(q16ang),CAMERA(q16horiz),CAMERA(sect)); + yax_drawrooms(G_DoSpriteAnimations, CAMERA(sect), 0, smoothRatio); + + G_DoSpriteAnimations(CAMERA(pos.x),CAMERA(pos.y),CAMERA(pos.z),fix16_to_int(CAMERA(q16ang)),smoothRatio); + + renderDrawMasks(); + + int geoSector = 0; + + for (bsize_t gs = 0; gs < g_geoSectorCnt; gs++) + { + int spriteNum = headspritesect[g_geoSector[gs]]; + while (spriteNum != -1) + { + int spriteNext = nextspritesect[spriteNum]; + changespritesect(spriteNum, g_geoSectorWarp[gs]); + sprite[spriteNum].x -= g_geoSectorX[gs]; + sprite[spriteNum].y -= g_geoSectorY[gs]; + setsprite(spriteNum, (vec3_t*)&sprite[spriteNum]); + spriteNum = spriteNext; + } + if (CAMERA(sect) == g_geoSector[gs]) + geoSector = gs; + } + + CAMERA(pos.x) -= g_geoSectorX[geoSector]; + CAMERA(pos.y) -= g_geoSectorY[geoSector]; + yax_preparedrawrooms(); + renderDrawRoomsQ16(CAMERA(pos.x),CAMERA(pos.y),CAMERA(pos.z),CAMERA(q16ang),CAMERA(q16horiz),g_geoSectorWarp[geoSector]); + yax_drawrooms(G_DoSpriteAnimations, g_geoSectorWarp[geoSector], 0, smoothRatio); + CAMERA(pos.x) += g_geoSectorX[geoSector]; + CAMERA(pos.y) += g_geoSectorY[geoSector]; + + for (bsize_t gs = 0; gs < g_geoSectorCnt; gs++) + { + int spriteNum = headspritesect[g_geoSectorWarp[gs]]; + while (spriteNum != -1) + { + int spriteNext = nextspritesect[spriteNum]; + changespritesect(spriteNum, g_geoSector[gs]); + sprite[spriteNum].x += g_geoSectorX[gs]; + sprite[spriteNum].y += g_geoSectorY[gs]; + setsprite(spriteNum, (vec3_t*)&sprite[spriteNum]); + spriteNum = spriteNext; + } + } + + G_DoSpriteAnimations(CAMERA(pos.x),CAMERA(pos.y),CAMERA(pos.z),fix16_to_int(CAMERA(q16ang)),smoothRatio); + + renderDrawMasks(); + + for (bsize_t gs = 0; gs < g_geoSectorCnt; gs++) + { + int spriteNum = headspritesect[g_geoSector[gs]]; + while (spriteNum != -1) + { + int spriteNext = nextspritesect[spriteNum]; + changespritesect(spriteNum, g_geoSectorWarp2[gs]); + sprite[spriteNum].x -= g_geoSectorX2[gs]; + sprite[spriteNum].y -= g_geoSectorY2[gs]; + setsprite(spriteNum, (vec3_t*)&sprite[spriteNum]); + spriteNum = spriteNext; + } + if (CAMERA(sect) == g_geoSector[gs]) + geoSector = gs; + } + + CAMERA(pos.x) -= g_geoSectorX2[geoSector]; + CAMERA(pos.y) -= g_geoSectorY2[geoSector]; + yax_preparedrawrooms(); + renderDrawRoomsQ16(CAMERA(pos.x),CAMERA(pos.y),CAMERA(pos.z),CAMERA(q16ang),CAMERA(q16horiz),g_geoSectorWarp2[geoSector]); + yax_drawrooms(G_DoSpriteAnimations, g_geoSectorWarp2[geoSector], 0, smoothRatio); + CAMERA(pos.x) += g_geoSectorX2[geoSector]; + CAMERA(pos.y) += g_geoSectorY2[geoSector]; + + for (bsize_t gs = 0; gs < g_geoSectorCnt; gs++) + { + int spriteNum = headspritesect[g_geoSectorWarp2[gs]]; + while (spriteNum != -1) + { + int spriteNext = nextspritesect[spriteNum]; + changespritesect(spriteNum, g_geoSector[gs]); + sprite[spriteNum].x += g_geoSectorX2[gs]; + sprite[spriteNum].y += g_geoSectorY2[gs]; + setsprite(spriteNum, (vec3_t*)&sprite[spriteNum]); + spriteNum = spriteNext; + } + } + + G_DoSpriteAnimations(CAMERA(pos.x),CAMERA(pos.y),CAMERA(pos.z),fix16_to_int(CAMERA(q16ang)),smoothRatio); + + renderDrawMasks(); + } + else + { + yax_preparedrawrooms(); + renderDrawRoomsQ16(CAMERA(pos.x),CAMERA(pos.y),CAMERA(pos.z),CAMERA(q16ang),CAMERA(q16horiz),CAMERA(sect)); + yax_drawrooms(G_DoSpriteAnimations, CAMERA(sect), 0, smoothRatio); +#ifdef LEGACY_ROR + if (!RR && (unsigned)ror_sprite < MAXSPRITES && drawing_ror == 1) // viewing from bottom + G_OROR_DupeSprites(&sprite[ror_sprite]); +#endif + G_DoSpriteAnimations(CAMERA(pos.x),CAMERA(pos.y),CAMERA(pos.z),fix16_to_int(CAMERA(q16ang)),smoothRatio); + } +#ifdef LEGACY_ROR + drawing_ror = 0; +#endif + renderDrawMasks(); +#endif + } + + G_RestoreInterpolations(); + + if (!RRRA || !g_fogType) + { + // Totalclock count of last step of p->visibility converging towards + // ud.const_visibility. + static int32_t lastvist; + const int32_t visdif = ud.const_visibility-pPlayer->visibility; + + // Check if totalclock was cleared (e.g. restarted game). + if (totalclock < lastvist) + lastvist = 0; + + // Every 2nd totalclock increment (each 1/60th second), ... + while (totalclock >= lastvist+2) + { + // ... approximately three-quarter the difference between + // p->visibility and ud.const_visibility. + const int32_t visinc = visdif>>2; + + if (klabs(visinc) == 0) + { + pPlayer->visibility = ud.const_visibility; + break; + } + + pPlayer->visibility += visinc; + lastvist = (int32_t) totalclock; + } + } + + if (r_usenewaspect) + { + newaspect_enable = 0; + renderSetAspect(viewingRange, yxAspect); + } +} + +bool GameInterface::GenerateSavePic() +{ + G_DrawRooms(myconnectindex, 65536); + return true; +} + + +void G_DumpDebugInfo(void) +{ + int32_t j,x; + // FILE * fp=fopen("condebug.log","w"); + + VM_ScriptInfo(insptr, 64); + + for (x=0; x= 0) + { + buildprint("Sprite ", j, " (", TrackerCast(sprite[j].x), ",", TrackerCast(sprite[j].y), ",", TrackerCast(sprite[j].z), + ") (picnum: ", TrackerCast(sprite[j].picnum), ")\n"); + buildprint("\n"); + j = nextspritestat[j]; + } + } +} + +// if is true, set the moveflag unconditionally, +// else only if it equals 0. +static int32_t G_InitActor(int32_t i, int32_t tilenum, int32_t set_movflag_uncond) +{ + if (g_tile[tilenum].execPtr) + { + SH(i) = *(g_tile[tilenum].execPtr); + AC_ACTION_ID(actor[i].t_data) = *(g_tile[tilenum].execPtr+1); + AC_MOVE_ID(actor[i].t_data) = *(g_tile[tilenum].execPtr+2); + + if (set_movflag_uncond || (*(g_tile[tilenum].execPtr + 3) && SHT(i) == 0)) // AC_MOVFLAGS + SHT(i) = *(g_tile[tilenum].execPtr+3); + + return 1; + } + + return 0; +} + +static actor_t NullActor; +static spriteext_t NullSprExt; +static spritesmooth_t NullSprSmooth; + +int32_t A_InsertSprite(int16_t whatsect,int32_t s_x,int32_t s_y,int32_t s_z,int16_t s_pn,int8_t s_s, + uint8_t s_xr,uint8_t s_yr,int16_t s_a,int16_t s_ve,int16_t s_zv,int16_t s_ow,int16_t s_ss) +{ + if (RR && s_ow < 0) + return 0; + + int32_t i = /*Net_IsRelevantStat(s_ss) ? Net_InsertSprite(whatsect, s_ss) : */insertsprite(whatsect, s_ss); + + if (EDUKE32_PREDICT_FALSE((unsigned)i >= MAXSPRITES)) + { + G_DumpDebugInfo(); + Printf("Failed spawning pic %d spr from pic %d spr %d at x:%d,y:%d,z:%d,sect:%d\n", + s_pn,s_ow < 0 ? -1 : TrackerCast(sprite[s_ow].picnum),s_ow,s_x,s_y,s_z,whatsect); + G_GameExit("Too many sprites spawned."); + } + + uspritetype spr_temp = { s_x, s_y, s_z, 0, s_pn, s_s, 0, 0, 0, s_xr, s_yr, 0, + 0, whatsect, s_ss, s_a, s_ow, s_ve, 0, s_zv, 0, 0, 0 }; + +#ifdef DEBUGGINGAIDS + g_spriteStat.numins++; +#endif + + spritetype *s = &sprite[i]; + *s = *(spritetype *)&spr_temp; + actor[i] = NullActor; + actor[i].bpos = *(vec3_t *)s; + + if ((unsigned)s_ow < MAXSPRITES) + { + actor[i].picnum = sprite[s_ow].picnum; + actor[i].floorz = actor[s_ow].floorz; + actor[i].ceilingz = actor[s_ow].ceilingz; + } + + actor[i].actorstayput = actor[i].extra = -1; +#ifdef POLYMER + actor[i].lightId = -1; +#endif + actor[i].owner = s_ow; + + G_InitActor(i, s_pn, 1); + + spriteext[i] = NullSprExt; + spritesmooth[i] = NullSprSmooth; + + return i; +} + +#ifdef YAX_ENABLE +void Yax_SetBunchZs(int32_t sectnum, int32_t cf, int32_t daz) +{ + int32_t i, bunchnum = yax_getbunch(sectnum, cf); + + if (bunchnum < 0 || bunchnum >= numyaxbunches) + return; + + for (SECTORS_OF_BUNCH(bunchnum, YAX_CEILING, i)) + SECTORFLD(i,z, YAX_CEILING) = daz; + for (SECTORS_OF_BUNCH(bunchnum, YAX_FLOOR, i)) + SECTORFLD(i,z, YAX_FLOOR) = daz; +} + +static void Yax_SetBunchInterpolation(int32_t sectnum, int32_t cf) +{ + int32_t i, bunchnum = yax_getbunch(sectnum, cf); + + if (bunchnum < 0 || bunchnum >= numyaxbunches) + return; + + for (SECTORS_OF_BUNCH(bunchnum, YAX_CEILING, i)) + G_SetInterpolation(§or[i].ceilingz); + for (SECTORS_OF_BUNCH(bunchnum, YAX_FLOOR, i)) + G_SetInterpolation(§or[i].floorz); +} +#else +# define Yax_SetBunchInterpolation(sectnum, cf) +#endif + +// A_Spawn has two forms with arguments having different meaning: +// +// 1. spriteNum>=0: Spawn from parent sprite with picnum +// 2. spriteNum<0: Spawn from already *existing* sprite +int A_Spawn(int spriteNum, int tileNum) +{ + int newSprite; + spritetype *pSprite; + actor_t * pActor; + int sectNum; + + + if (spriteNum >= 0) + { + // spawn from parent sprite + newSprite = A_InsertSprite(sprite[spriteNum].sectnum,sprite[spriteNum].x,sprite[spriteNum].y,sprite[spriteNum].z, + tileNum,0,0,0,0,0,0,spriteNum,0); + actor[newSprite].picnum = sprite[spriteNum].picnum; + } + else + { + // spawn from already existing sprite + newSprite = tileNum; + spritetype *const pSprite = &sprite[newSprite]; + actor_t *const pActor = &actor[newSprite]; + + Bmemset(&actor[newSprite], 0, sizeof(actor_t)); + Bmemcpy(&pActor->bpos, &sprite[newSprite], sizeof(vec3_t)); + + pActor->picnum = pSprite->picnum; + + if (pSprite->picnum == SECTOREFFECTOR && pSprite->lotag == 50) + pActor->picnum = pSprite->owner; + + pSprite->owner = pActor->owner = newSprite; + + pActor->floorz = sector[pSprite->sectnum].floorz; + pActor->ceilingz = sector[pSprite->sectnum].ceilingz; + + pActor->actorstayput = pActor->extra = -1; + +#ifdef POLYMER + pActor->lightId = -1; +#endif + + if ((pSprite->cstat & 48) + && (RR || (pSprite->picnum != SPEAKER + && pSprite->picnum != LETTER + && pSprite->picnum != DUCK + && pSprite->picnum != TARGET + && pSprite->picnum != TRIPBOMB + && pSprite->picnum != VIEWSCREEN + && pSprite->picnum != VIEWSCREEN2)) + && (!(pSprite->picnum >= CRACK1 && pSprite->picnum <= CRACK4))) + { + if (pSprite->shade == 127) + goto SPAWN_END; + + if (A_CheckSwitchTile(newSprite) && (pSprite->cstat & 16)) + { + if (pSprite->pal && pSprite->picnum != ACCESSSWITCH && pSprite->picnum != ACCESSSWITCH2) + { + if (((!g_netServer && ud.multimode < 2)) || ((g_netServer || ud.multimode > 1) && !GTFLAGS(GAMETYPE_DMSWITCHES))) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + pSprite->lotag = pSprite->hitag = 0; + pSprite->cstat = 32768; + goto SPAWN_END; + } + } + + pSprite->cstat |= 257; + + if (pSprite->pal && pSprite->picnum != ACCESSSWITCH && pSprite->picnum != ACCESSSWITCH2) + pSprite->pal = 0; + + goto SPAWN_END; + } + + if (pSprite->hitag) + { + changespritestat(newSprite, STAT_FALLER); + pSprite->cstat |= 257; + pSprite->extra = g_impactDamage; + goto SPAWN_END; + } + } + + if (pSprite->cstat & 1) + pSprite->cstat |= 256; + + if (!G_InitActor(newSprite, pSprite->picnum, 0)) + T2(newSprite) = T5(newSprite) = 0; // AC_MOVE_ID, AC_ACTION_ID + } + + pSprite = &sprite[newSprite]; + pActor = &actor[newSprite]; + sectNum = pSprite->sectnum; + + //some special cases that can't be handled through the dynamictostatic system. + + if (pSprite->picnum >= CAMERA1 && pSprite->picnum <= CAMERA1 + 4) + pSprite->picnum = CAMERA1; + else if (pSprite->picnum >= BOLT1 && pSprite->picnum <= BOLT1 + 3) + pSprite->picnum = BOLT1; + else if (!RR && pSprite->picnum >= SIDEBOLT1 && pSprite->picnum <= SIDEBOLT1 + 3) + pSprite->picnum = SIDEBOLT1; + if (DEER && pSprite->picnum != APLAYER && pSprite->picnum != RRTILE7936) + { + goto default_case; + } + else if (RRRA && pSprite->picnum == PIG+11) + { + pSprite->xrepeat = 16; + pSprite->yrepeat = 16; + pSprite->clipdist = 0; + pSprite->extra = 0; + pSprite->cstat = 0; + changespritestat(newSprite, 121); + } + else + switch (DYNAMICTILEMAP(pSprite->picnum)) + { + default: +default_case: + if (G_HaveActor(pSprite->picnum)) + { + if (spriteNum == -1 && pSprite->lotag > ud.player_skill) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + + // Init the size + if (pSprite->xrepeat == 0 || pSprite->yrepeat == 0) + pSprite->xrepeat = pSprite->yrepeat = 1; + + if (A_CheckSpriteFlags(newSprite, SFLAG_BADGUY)) + { + if (ud.monsters_off == 1) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + + A_Fall(newSprite); + + if (A_CheckSpriteFlags(newSprite, SFLAG_BADGUYSTAYPUT)) + pActor->actorstayput = pSprite->sectnum; + + if (!RR || A_CheckSpriteFlags(newSprite, SFLAG_KILLCOUNT)) + g_player[myconnectindex].ps->max_actors_killed++; + pSprite->clipdist = 80; + + if (spriteNum >= 0) + { + if (sprite[spriteNum].picnum == RESPAWN) + pActor->tempang = sprite[newSprite].pal = sprite[spriteNum].pal; + + A_PlayAlertSound(newSprite); + changespritestat(newSprite, STAT_ACTOR); + } + else + changespritestat(newSprite, STAT_ZOMBIEACTOR); + } + else + { + pSprite->clipdist = 40; + pSprite->owner = newSprite; + changespritestat(newSprite, STAT_ACTOR); + } + + pActor->timetosleep = 0; + + if (spriteNum >= 0) + pSprite->ang = sprite[spriteNum].ang; + } + break; + case FOF__STATIC: + if (RR) goto default_case; + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + case RRTILE280__STATICRR: + case RRTILE281__STATICRR: + case RRTILE282__STATICRR: + case RRTILE283__STATICRR: + case RRTILE2025__STATICRR: + case RRTILE2026__STATICRR: + case RRTILE2027__STATICRR: + case RRTILE2028__STATICRR: + pSprite->cstat = 0; + pSprite->cstat |= 32768; + pSprite->xrepeat = 0; + pSprite->yrepeat = 0; + pSprite->clipdist = 0; + pSprite->extra = 0; + changespritestat(newSprite, 105); + break; + case RRTILE3410__STATICRR: + pSprite->extra = 0; + changespritestat(newSprite, 107); + break; + case RRTILE8450__STATICRR: + if (!RRRA) goto default_case; + pSprite->xrepeat = 64; + pSprite->yrepeat = 64; + pSprite->extra = pSprite->lotag; + pSprite->cstat |= 257; + changespritestat(newSprite, 116); + break; + case RRTILE8487__STATICRR: + case RRTILE8489__STATICRR: + if (!RRRA) goto default_case; + pSprite->xrepeat = 32; + pSprite->yrepeat = 32; + pSprite->extra = 0; + pSprite->cstat |= 257; + pSprite->hitag = 0; + changespritestat(newSprite, 117); + break; + case RRTILE7424__STATICRR: + if (!RRRA) goto default_case; + pSprite->extra = 0; + pSprite->xrepeat = 0; + pSprite->yrepeat = 0; + changespritestat(newSprite, 11); + break; + case RRTILE7936__STATICRR: + if (!RRRA) goto default_case; + pSprite->xrepeat = 0; + pSprite->yrepeat = 0; + G_SetFog(2); + g_fogType = 1; + break; + case RRTILE6144__STATICRR: + if (!RRRA) goto default_case; + pSprite->xrepeat = 0; + pSprite->yrepeat = 0; + for (bssize_t TRAVERSE_CONNECT(playerNum)) + g_player[playerNum].ps->sea_sick_stat = 1; + break; + case RRTILE8448__STATICRR: + if (!RRRA) goto default_case; + pSprite->lotag = 1; + pSprite->clipdist = 0; + break; + case RRTILE8099__STATICRR: + if (!RRRA) goto default_case; + pSprite->lotag = 5; + pSprite->clipdist = 0; + changespritestat(newSprite, 123); + break; + case RRTILE8704__STATICRR: + if (!RRRA) goto default_case; + pSprite->lotag = 1; + pSprite->clipdist = 0; + break; + case RRTILE8192__STATICRR: + if (!RRRA) goto default_case; + pSprite->xrepeat = 0; + pSprite->yrepeat = 0; + g_ufoSpawnMinion = 1; + break; + case RRTILE8193__STATICRR: + if (!RRRA) goto default_case; + pSprite->xrepeat = 0; + pSprite->yrepeat = 0; + g_pistonSound = 1; + break; + case RRTILE8165__STATICRR: + if (!RRRA) goto default_case; + pSprite->lotag = 1; + pSprite->clipdist = 0; + pSprite->owner = newSprite; + pSprite->extra = 0; + changespritestat(newSprite, 115); + break; + case RRTILE8593__STATICRR: + if (!RRRA) goto default_case; + pSprite->lotag = 1; + pSprite->clipdist = 0; + pSprite->owner = newSprite; + pSprite->extra = 0; + changespritestat(newSprite, 122); + break; +//#endif + case RRTILE285__STATICRR: + case RRTILE286__STATICRR: + case RRTILE287__STATICRR: + case RRTILE288__STATICRR: + case RRTILE289__STATICRR: + case RRTILE290__STATICRR: + case RRTILE291__STATICRR: + case RRTILE292__STATICRR: + case RRTILE293__STATICRR: + pSprite->cstat = 0; + pSprite->cstat |= 32768; + pSprite->xrepeat = 0; + pSprite->yrepeat = 0; + pSprite->clipdist = 0; + pSprite->lotag = 0; + changespritestat(newSprite, 106); + break; + + case WATERSPLASH2__STATIC: + case MUD__STATICRR: + if (spriteNum >= 0) + { + setsprite(newSprite, (vec3_t *)&sprite[spriteNum]); + pSprite->xrepeat = pSprite->yrepeat = 8+(krand2()&7); + } + else pSprite->xrepeat = pSprite->yrepeat = 16+(krand2()&15); + + pSprite->shade = -16; + pSprite->cstat |= 128; + + if (spriteNum >= 0) + { + if (sector[sprite[spriteNum].sectnum].lotag == ST_2_UNDERWATER) + { + pSprite->z = getceilzofslope(pSprite->sectnum, pSprite->x, pSprite->y) + (16 << 8); + pSprite->cstat |= 8; + } + else if (sector[sprite[spriteNum].sectnum].lotag == ST_1_ABOVE_WATER) + pSprite->z = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y); + } + + if (sector[sectNum].floorpicnum == FLOORSLIME || sector[sectNum].ceilingpicnum == FLOORSLIME) + pSprite->pal = 7; + fallthrough__; + case NEON1__STATIC: + case NEON2__STATIC: + case NEON3__STATIC: + case NEON4__STATIC: + case NEON5__STATIC: + case NEON6__STATIC: + case DOMELITE__STATIC: + if (pSprite->picnum != WATERSPLASH2) + pSprite->cstat |= 257; + fallthrough__; + case NUKEBUTTON__STATIC: + if (RR && pSprite->picnum == NUKEBUTTON) + goto default_case; + if (pSprite->picnum == DOMELITE) + pSprite->cstat |= 257; + fallthrough__; + case JIBS1__STATIC: + case JIBS2__STATIC: + case JIBS3__STATIC: + case JIBS4__STATIC: + case JIBS5__STATIC: + case JIBS6__STATIC: + case DUKETORSO__STATIC: + case DUKEGUN__STATIC: + case DUKELEG__STATIC: + if (RR && pSprite->picnum == JIBS6) + { + pSprite->xrepeat >>= 1; + pSprite->yrepeat >>= 1; + } + changespritestat(newSprite, STAT_MISC); + break; + case HEADJIB1__STATIC: + case ARMJIB1__STATIC: + case LEGJIB1__STATIC: + case LIZMANHEAD1__STATIC: + case LIZMANARM1__STATIC: + case LIZMANLEG1__STATIC: + if (RR) goto default_case; + changespritestat(newSprite, STAT_MISC); + break; + case RRTILE2460__STATICRR: + case RRTILE2465__STATICRR: + case BIKEJIBA__STATICRR: + case BIKEJIBB__STATICRR: + case BIKEJIBC__STATICRR: + case BIKERJIBA__STATICRR: + case BIKERJIBB__STATICRR: + case BIKERJIBC__STATICRR: + case BIKERJIBD__STATICRR: + case CHEERJIBA__STATICRR: + case CHEERJIBB__STATICRR: + case CHEERJIBC__STATICRR: + case CHEERJIBD__STATICRR: + case FBOATJIBA__STATICRR: + case FBOATJIBB__STATICRR: + case RABBITJIBA__STATICRR: + case RABBITJIBB__STATICRR: + case RABBITJIBC__STATICRR: + case MAMAJIBA__STATICRR: + case MAMAJIBB__STATICRR: + if (!RRRA) goto default_case; + if (pSprite->picnum == RABBITJIBA) + { + pSprite->xrepeat = 18; + pSprite->yrepeat = 18; + } + else if (pSprite->picnum == RABBITJIBB) + { + pSprite->xrepeat = 36; + pSprite->yrepeat = 36; + } + else if (pSprite->picnum == RABBITJIBC) + { + pSprite->xrepeat = 54; + pSprite->yrepeat = 54; + } + fallthrough__; + case BILLYJIBA__STATICRR: + case BILLYJIBB__STATICRR: + case HULKJIBA__STATICRR: + case HULKJIBB__STATICRR: + case HULKJIBC__STATICRR: + case MINJIBA__STATICRR: + case MINJIBB__STATICRR: + case MINJIBC__STATICRR: + case COOTJIBA__STATICRR: + case COOTJIBB__STATICRR: + case COOTJIBC__STATICRR: + changespritestat(newSprite, STAT_MISC); + break; + case TONGUE__STATIC: + if (spriteNum >= 0) + pSprite->ang = sprite[spriteNum].ang; + pSprite->z -= 38<<8; + pSprite->zvel = 256-(krand2()&511); + pSprite->xvel = 64-(krand2()&127); + changespritestat(newSprite, STAT_PROJECTILE); + break; + case NATURALLIGHTNING__STATIC: + if (RR) goto default_case; + pSprite->cstat &= ~257; + pSprite->cstat |= 32768; + break; + case TRANSPORTERSTAR__STATIC: + case TRANSPORTERBEAM__STATIC: + if (spriteNum == -1) break; + if (pSprite->picnum == TRANSPORTERBEAM) + { + pSprite->xrepeat = 31; + pSprite->yrepeat = 1; + pSprite->z = sector[sprite[spriteNum].sectnum].floorz-PHEIGHT; + } + else + { + if (sprite[spriteNum].statnum == STAT_PROJECTILE) + pSprite->xrepeat = pSprite->yrepeat = 8; + else + { + pSprite->xrepeat = 48; + pSprite->yrepeat = 64; + if (sprite[spriteNum].statnum == STAT_PLAYER || A_CheckEnemySprite(&sprite[spriteNum])) + pSprite->z -= ZOFFSET5; + } + } + + pSprite->shade = -127; + pSprite->cstat = 128|2; + pSprite->ang = sprite[spriteNum].ang; + + pSprite->xvel = 128; + changespritestat(newSprite, STAT_MISC); + A_SetSprite(newSprite,CLIPMASK0); + setsprite(newSprite,(vec3_t *)pSprite); + break; + + case FRAMEEFFECT1__STATIC: + if (spriteNum >= 0) + { + pSprite->xrepeat = sprite[spriteNum].xrepeat; + pSprite->yrepeat = sprite[spriteNum].yrepeat; + if (RR && sprite[spriteNum].picnum == APLAYER) + T2(newSprite) = SMALLSMOKE; + else + T2(newSprite) = sprite[spriteNum].picnum; + } + else pSprite->xrepeat = pSprite->yrepeat = 0; + + changespritestat(newSprite, STAT_MISC); + + break; + + case LASERLINE__STATIC: + if (RR) goto default_case; + pSprite->yrepeat = 6; + pSprite->xrepeat = 32; + + if (g_tripbombLaserMode == 1) + pSprite->cstat = 16 + 2; + else if (g_tripbombLaserMode == 0 || g_tripbombLaserMode == 2) + pSprite->cstat = 16; + else + { + pSprite->xrepeat = 0; + pSprite->yrepeat = 0; + } + + if (spriteNum >= 0) pSprite->ang = actor[spriteNum].t_data[5]+512; + changespritestat(newSprite, STAT_MISC); + break; + + case FORCESPHERE__STATIC: + if (spriteNum == -1) + { + pSprite->cstat = 32768; + changespritestat(newSprite, STAT_ZOMBIEACTOR); + } + else + { + pSprite->xrepeat = pSprite->yrepeat = 1; + changespritestat(newSprite, STAT_MISC); + } + break; + + case BLOOD__STATIC: + pSprite->xrepeat = pSprite->yrepeat = RR ? 4 : 16; + pSprite->z -= (26<<8); + if (!RR && spriteNum >= 0 && sprite[spriteNum].pal == 6) + pSprite->pal = 6; + changespritestat(newSprite, STAT_MISC); + break; + case BLOODPOOL__STATIC: + case PUKE__STATIC: + { + if (RR && pSprite->picnum == PUKE) goto default_case; + int16_t pukeSect = pSprite->sectnum; + + updatesector(pSprite->x + 108, pSprite->y + 108, &pukeSect); + if (pukeSect >= 0 && sector[pukeSect].floorz == sector[pSprite->sectnum].floorz) + { + updatesector(pSprite->x - 108, pSprite->y - 108, &pukeSect); + if (pukeSect >= 0 && sector[pukeSect].floorz == sector[pSprite->sectnum].floorz) + { + updatesector(pSprite->x + 108, pSprite->y - 108, &pukeSect); + if (pukeSect >= 0 && sector[pukeSect].floorz == sector[pSprite->sectnum].floorz) + { + updatesector(pSprite->x - 108, pSprite->y + 108, &pukeSect); + if (pukeSect >= 0 && sector[pukeSect].floorz != sector[pSprite->sectnum].floorz) + goto zero_puke; + } + else goto zero_puke; + } + else goto zero_puke; + } + else + { + zero_puke: + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + + if (sector[sectNum].lotag == ST_1_ABOVE_WATER) + { + changespritestat(newSprite, STAT_MISC); + break; + } + + if (spriteNum >= 0 && (RR || pSprite->picnum != PUKE)) + { + if (sprite[spriteNum].pal == 1) + pSprite->pal = 1; + else if (sprite[spriteNum].pal != 6 && sprite[spriteNum].picnum != NUKEBARREL && sprite[spriteNum].picnum != TIRE) + pSprite->pal = (!RR && sprite[spriteNum].picnum == FECES) ? 7 : 2; // Brown or red + else + pSprite->pal = 0; // green + + if (sprite[spriteNum].picnum == TIRE) + pSprite->shade = 127; + } + pSprite->cstat |= 32; + if (RR) goto rrbloodpool_fallthrough; + fallthrough__; + } + case FECES__STATIC: + if (RR) goto default_case; + if (spriteNum >= 0) + pSprite->xrepeat = pSprite->yrepeat = 1; + changespritestat(newSprite, STAT_MISC); + break; + + case BLOODSPLAT1__STATIC: + case BLOODSPLAT2__STATIC: + case BLOODSPLAT3__STATIC: + case BLOODSPLAT4__STATIC: +rrbloodpool_fallthrough: + pSprite->cstat |= 16; + pSprite->xrepeat = 7 + (krand2() & 7); + pSprite->yrepeat = 7 + (krand2() & 7); + pSprite->z -= ZOFFSET2; + + if (pSprite->picnum == BLOODPOOL) + pSprite->cstat |= 32768; + + if (spriteNum >= 0 && sprite[spriteNum].pal == 6) + pSprite->pal = 6; + + A_AddToDeleteQueue(newSprite); + changespritestat(newSprite, STAT_MISC); + break; + + case TRIPBOMB__STATIC: + if (RR) goto default_case; + if (pSprite->lotag > ud.player_skill) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + + pSprite->xrepeat = 4; + pSprite->yrepeat = 5; + pSprite->hitag = newSprite; + pSprite->owner = pSprite->hitag; + pSprite->xvel = 16; + + A_SetSprite(newSprite, CLIPMASK0); + + pActor->t_data[0] = 17; + pActor->t_data[2] = 0; + pActor->t_data[5] = pSprite->ang; + + changespritestat(newSprite, STAT_ZOMBIEACTOR); + break; + + case SPACEMARINE__STATIC: + if (RR) goto default_case; + pSprite->extra = 20; + pSprite->cstat |= 257; + changespritestat(newSprite, STAT_ZOMBIEACTOR); + break; + + case PANNEL1__STATIC: + case PANNEL2__STATIC: + case OCEANSPRITE1__STATIC: + case OCEANSPRITE2__STATIC: + case OCEANSPRITE3__STATIC: + case OCEANSPRITE5__STATIC: + case MONK__STATIC: + case INDY__STATIC: + case LUKE__STATIC: + case JURYGUY__STATIC: + case HANGLIGHT__STATIC: + case FETUS__STATIC: + case FETUSBROKE__STATIC: + case TRIPODCAMERA__STATIC: + if (RR) goto default_case; + fallthrough__; + case HYDRENT__STATIC: + case SATELITE__STATIC: + case FUELPOD__STATIC: + case SOLARPANNEL__STATIC: + case ANTENNA__STATIC: + case CHAIR1__STATIC: + case CHAIR2__STATIC: + case CHAIR3__STATIC: + case BOTTLE1__STATIC: + case BOTTLE2__STATIC: + case BOTTLE3__STATIC: + case BOTTLE4__STATIC: + case BOTTLE5__STATIC: + case BOTTLE6__STATIC: + case BOTTLE7__STATIC: + case BOTTLE8__STATIC: + case BOTTLE10__STATIC: + case BOTTLE11__STATIC: + case BOTTLE12__STATIC: + case BOTTLE13__STATIC: + case BOTTLE14__STATIC: + case BOTTLE15__STATIC: + case BOTTLE16__STATIC: + case BOTTLE17__STATIC: + case BOTTLE18__STATIC: + case BOTTLE19__STATIC: + case SCALE__STATIC: + case VACUUM__STATIC: + case CACTUS__STATIC: + case CACTUSBROKE__STATIC: + case CAMERALIGHT__STATIC: + case MOVIECAMERA__STATIC: + case IVUNIT__STATIC: + case POT1__STATIC: + case POT2__STATIC: + case POT3__STATIC: + case SUSHIPLATE1__STATIC: + case SUSHIPLATE2__STATIC: + case SUSHIPLATE3__STATIC: + case SUSHIPLATE4__STATIC: + case SUSHIPLATE5__STATIC: + case WAITTOBESEATED__STATIC: + case VASE__STATIC: + case PIPE1__STATIC: + case PIPE2__STATIC: + case PIPE3__STATIC: + case PIPE4__STATIC: + case PIPE5__STATIC: + case PIPE6__STATIC: + case GRATE1__STATIC: + case FANSPRITE__STATIC: + pSprite->clipdist = 32; + pSprite->cstat |= 257; + fallthrough__; + case OCEANSPRITE4__STATIC: + if (RR && pSprite->picnum == OCEANSPRITE4) goto default_case; + changespritestat(newSprite, STAT_DEFAULT); + break; + case FEMMAG1__STATIC: + case FEMMAG2__STATIC: + pSprite->cstat &= ~257; + changespritestat(newSprite, STAT_DEFAULT); + break; + case DUKETAG__STATIC: + case SIGN1__STATIC: + case SIGN2__STATIC: + if (RR) goto default_case; + if ((!g_netServer && ud.multimode < 2) && pSprite->pal) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + } + else pSprite->pal = 0; + break; + + case MASKWALL1__STATIC: + case MASKWALL2__STATIC: + case MASKWALL3__STATIC: + case MASKWALL4__STATIC: + case MASKWALL5__STATIC: + case MASKWALL6__STATIC: + case MASKWALL8__STATIC: + case MASKWALL9__STATIC: + case MASKWALL10__STATIC: + case MASKWALL11__STATIC: + case MASKWALL12__STATIC: + case MASKWALL13__STATIC: + case MASKWALL14__STATIC: + case MASKWALL15__STATIC: + if (RR) goto default_case; + fallthrough__; + case MASKWALL7__STATIC: + { + int const j = pSprite->cstat & SPAWN_PROTECT_CSTAT_MASK; + pSprite->cstat = j | CSTAT_SPRITE_BLOCK; + changespritestat(newSprite, STAT_DEFAULT); + break; + } + case FOOTPRINTS__STATIC: + case FOOTPRINTS2__STATIC: + case FOOTPRINTS3__STATIC: + case FOOTPRINTS4__STATIC: + if (spriteNum >= 0) + { + int16_t footSect = pSprite->sectnum; + + updatesector(pSprite->x + 84, pSprite->y + 84, &footSect); + if (footSect >= 0 && sector[footSect].floorz == sector[pSprite->sectnum].floorz) + { + updatesector(pSprite->x - 84, pSprite->y - 84, &footSect); + if (footSect >= 0 && sector[footSect].floorz == sector[pSprite->sectnum].floorz) + { + updatesector(pSprite->x + 84, pSprite->y - 84, &footSect); + if (footSect >= 0 && sector[footSect].floorz == sector[pSprite->sectnum].floorz) + { + updatesector(pSprite->x - 84, pSprite->y + 84, &footSect); + if (footSect >= 0 && sector[footSect].floorz != sector[pSprite->sectnum].floorz) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + } + else goto zero_footprint; + } + else goto zero_footprint; + } + else + { + zero_footprint: + pSprite->xrepeat = pSprite->yrepeat = 0; + break; + } + + pSprite->cstat = 32 + ((g_player[P_Get(spriteNum)].ps->footprintcount & 1) << 2); + pSprite->ang = sprite[spriteNum].ang; + } + + pSprite->z = sector[sectNum].floorz; + + if (sector[sectNum].lotag != ST_1_ABOVE_WATER && sector[sectNum].lotag != ST_2_UNDERWATER) + pSprite->xrepeat = pSprite->yrepeat = 32; + + A_AddToDeleteQueue(newSprite); + changespritestat(newSprite, STAT_MISC); + break; + + case PODFEM1__STATIC: + if (RR) goto default_case; + pSprite->extra <<= 1; + fallthrough__; + case FEM1__STATIC: + case FEM2__STATIC: + case FEM3__STATIC: + case FEM4__STATIC: + case FEM5__STATIC: + case FEM6__STATIC: + case FEM7__STATIC: + case FEM8__STATIC: + case FEM9__STATIC: + if (RR) goto default_case; + fallthrough__; + case FEM10__STATIC: + case NAKED1__STATIC: + case STATUE__STATIC: + case TOUGHGAL__STATIC: + pSprite->yvel = pSprite->hitag; + pSprite->hitag = -1; + fallthrough__; + case BLOODYPOLE__STATIC: + if (RR && pSprite->picnum == BLOODYPOLE) goto default_case; + pSprite->cstat |= 257; + pSprite->clipdist = 32; + changespritestat(newSprite, STAT_ZOMBIEACTOR); + break; + + case QUEBALL__STATIC: + case STRIPEBALL__STATIC: + pSprite->cstat = 256; + pSprite->clipdist = 8; + changespritestat(newSprite, STAT_ZOMBIEACTOR); + break; + case BOWLINGBALL__STATICRR: + pSprite->cstat = 256; + pSprite->clipdist = 64; + pSprite->xrepeat = 11; + pSprite->yrepeat = 9; + changespritestat(newSprite, 2); + break; + case HENSTAND__STATICRR: + pSprite->cstat = 257; + pSprite->clipdist = 48; + pSprite->xrepeat = 21; + pSprite->yrepeat = 15; + changespritestat(newSprite, 2); + break; + case RRTILE295__STATICRR: + pSprite->cstat |= 32768; + changespritestat(newSprite, 107); + break; + case RRTILE296__STATICRR: + case RRTILE297__STATICRR: + pSprite->xrepeat = 64; + pSprite->yrepeat = 64; + pSprite->clipdist = 64; + changespritestat(newSprite, 108); + break; + case RRTILE3190__STATICRR: + case RRTILE3191__STATICRR: + case RRTILE3192__STATICRR: + pSprite->cstat = 257; + pSprite->clipdist = 8; + pSprite->xrepeat = 32; + pSprite->yrepeat = 26; + pSprite->xvel = 32; + changespritestat(newSprite, 1); + break; + case RRTILE3120__STATICRR: + pSprite->cstat = 257; + pSprite->clipdist = 8; + pSprite->xrepeat = 12; + pSprite->yrepeat = 10; + pSprite->xvel = 32; + changespritestat(newSprite, 1); + break; + case RRTILE3122__STATICRR: + pSprite->cstat = 257; + pSprite->clipdist = 2; + pSprite->xrepeat = 8; + pSprite->yrepeat = 6; + pSprite->xvel = 16; + changespritestat(newSprite, 1); + break; + case RRTILE3123__STATICRR: + pSprite->cstat = 257; + pSprite->clipdist = 8; + pSprite->xrepeat = 13; + pSprite->yrepeat = 13; + pSprite->xvel = 16; + changespritestat(newSprite, 1); + break; + case RRTILE3124__STATICRR: + pSprite->cstat = 257; + pSprite->clipdist = 8; + pSprite->xrepeat = 17; + pSprite->yrepeat = 12; + pSprite->xvel = 32; + changespritestat(newSprite, 1); + break; + case RRTILE3132__STATICRR: + pSprite->cstat = 257; + pSprite->clipdist = 8; + pSprite->xrepeat = 13; + pSprite->yrepeat = 10; + pSprite->xvel = 0; + changespritestat(newSprite, 1); + break; + case RRTILE3440__STATICRR: + pSprite->cstat = 257; + pSprite->clipdist = 48; + pSprite->xrepeat = 23; + pSprite->yrepeat = 23; + changespritestat(newSprite, 2); + break; + + case DUKELYINGDEAD__STATIC: + if (spriteNum >= 0 && sprite[spriteNum].picnum == APLAYER) + { + pSprite->xrepeat = sprite[spriteNum].xrepeat; + pSprite->yrepeat = sprite[spriteNum].yrepeat; + pSprite->shade = sprite[spriteNum].shade; + pSprite->pal = g_player[P_Get(spriteNum)].ps->palookup; + } + fallthrough__; + case DUKECAR__STATIC: + case HELECOPT__STATIC: + // if(sp->picnum == HELECOPT || sp->picnum == DUKECAR) sp->xvel = 1024; + if (RR && (pSprite->picnum == DUKECAR || pSprite->picnum == HELECOPT)) goto default_case; + pSprite->cstat = 0; + pSprite->extra = 1; + pSprite->xvel = 292; + pSprite->zvel = 360; + fallthrough__; + case BLIMP__STATIC: + if (RR && pSprite->picnum == BLIMP) goto default_case; + pSprite->cstat |= 257; + pSprite->clipdist = 128; + changespritestat(newSprite, STAT_ACTOR); + break; + + case RESPAWNMARKERRED__STATIC: + pSprite->xrepeat = pSprite->yrepeat = RR ? 8 : 24; + if (spriteNum >= 0) + pSprite->z = actor[spriteNum].floorz; // -(1<<4); + changespritestat(newSprite, STAT_ACTOR); + break; + + case MIKE__STATIC: + pSprite->yvel = pSprite->hitag; + pSprite->hitag = 0; + changespritestat(newSprite, STAT_ACTOR); + break; + case WEATHERWARN__STATIC: + if (RR) goto default_case; + changespritestat(newSprite, STAT_ACTOR); + break; + + case SPOTLITE__STATIC: + T1(newSprite) = pSprite->x; + T2(newSprite) = pSprite->y; + break; + case BULLETHOLE__STATIC: + pSprite->xrepeat = 3; + pSprite->yrepeat = 3; + pSprite->cstat = 16 + (krand2() & 12); + + A_AddToDeleteQueue(newSprite); + changespritestat(newSprite, STAT_MISC); + break; + + case MONEY__STATIC: + case MAIL__STATIC: + case PAPER__STATIC: + if (RR && (pSprite->picnum == MAIL || pSprite->picnum == PAPER)) goto default_case; + pActor->t_data[0] = krand2() & 2047; + + pSprite->cstat = krand2() & 12; + pSprite->xrepeat = 8; + pSprite->yrepeat = 8; + pSprite->ang = krand2() & 2047; + + changespritestat(newSprite, STAT_MISC); + break; + + case VIEWSCREEN__STATIC: + case VIEWSCREEN2__STATIC: + if (RR) goto default_case; + pSprite->owner = newSprite; + pSprite->lotag = pSprite->extra = 1; + changespritestat(newSprite, STAT_STANDABLE); + break; + + case SHELL__STATIC: //From the player + case SHOTGUNSHELL__STATIC: + if (spriteNum >= 0) + { + int shellAng; + + if (sprite[spriteNum].picnum == APLAYER) + { + int const playerNum = P_Get(spriteNum); + const DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + shellAng = fix16_to_int(pPlayer->q16ang) - (krand2() & 63) + 8; // Fine tune + + T1(newSprite) = krand2() & 1; + + pSprite->z = (3 << 8) + pPlayer->pyoff + pPlayer->pos.z - (fix16_to_int((pPlayer->q16horizoff + pPlayer->q16horiz - F16(100))) << 4); + + if (pSprite->picnum == SHOTGUNSHELL) + pSprite->z += (3 << 8); + + pSprite->zvel = -(krand2() & 255); + } + else + { + shellAng = pSprite->ang; + pSprite->z = sprite[spriteNum].z - PHEIGHT + (RR ? (7 << 8) : (3 << 8)); + } + + pSprite->x = sprite[spriteNum].x + (sintable[(shellAng + 512) & 2047] >> 7); + pSprite->y = sprite[spriteNum].y + (sintable[shellAng & 2047] >> 7); + pSprite->shade = -8; + + if (NAM_WW2GI) + { + pSprite->ang = shellAng + 512; + pSprite->xvel = 30; + } + else + { + pSprite->ang = shellAng - 512; + pSprite->xvel = 20; + } + + if (RR && pSprite->picnum == SHELL) + pSprite->xrepeat = pSprite->yrepeat = 2; + else + pSprite->xrepeat = pSprite->yrepeat = 4; + + changespritestat(newSprite, STAT_MISC); + } + break; + case RESPAWN__STATIC: + pSprite->extra = 66-13; + fallthrough__; + case MUSICANDSFX__STATIC: + if ((!g_netServer && ud.multimode < 2) && pSprite->pal == 1) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + pSprite->cstat = 32768; + changespritestat(newSprite, STAT_FX); + break; + case SOUNDFX__STATICRR: + pSprite->cstat |= 32768; + changespritestat(newSprite, STAT_ZOMBIEACTOR); + break; + + case EXPLOSION2__STATIC: + case EXPLOSION3__STATICRR: +#ifdef POLYMER + if (pSprite->yrepeat > 32) + { + G_AddGameLight(0, newSprite, ((pSprite->yrepeat*tilesiz[pSprite->picnum].y)<<1), 32768, 255+(95<<8),PR_LIGHT_PRIO_MAX_GAME); + pActor->lightcount = 2; + } + fallthrough__; +#endif + case EXPLOSION2BOT__STATIC: + case BURNING__STATIC: + case BURNING2__STATIC: + case SMALLSMOKE__STATIC: + case SHRINKEREXPLOSION__STATIC: + case COOLEXPLOSION1__STATIC: + if (RR && (pSprite->picnum == EXPLOSION2BOT || pSprite->picnum == BURNING2 + || pSprite->picnum == SHRINKEREXPLOSION || pSprite->picnum == COOLEXPLOSION1)) goto default_case; + if (spriteNum >= 0) + { + pSprite->ang = sprite[spriteNum].ang; + pSprite->shade = -64; + pSprite->cstat = 128|(krand2()&4); + } + + if (pSprite->picnum == EXPLOSION2 || (!RR && pSprite->picnum == EXPLOSION2BOT)) + { + pSprite->xrepeat = pSprite->yrepeat = 48; + pSprite->shade = -127; + pSprite->cstat |= 128; + } + else if (RR && pSprite->picnum == EXPLOSION3) + { + pSprite->xrepeat = pSprite->yrepeat = 128; + pSprite->shade = -127; + pSprite->cstat |= 128; + } + else if (!RR && pSprite->picnum == SHRINKEREXPLOSION) + pSprite->xrepeat = pSprite->yrepeat = 32; + else if (pSprite->picnum == SMALLSMOKE) + { + // 64 "money" + pSprite->xrepeat = pSprite->yrepeat = RR ? 12 : 24; + } + else if (pSprite->picnum == BURNING || (!RR && pSprite->picnum == BURNING2)) + pSprite->xrepeat = pSprite->yrepeat = 4; + + pSprite->cstat |= 8192; + + if (spriteNum >= 0) + { + int const floorZ = getflorzofslope(pSprite->sectnum, pSprite->x, pSprite->y); + + if (pSprite->z > floorZ-ZOFFSET4) + pSprite->z = floorZ-ZOFFSET4; + } + + changespritestat(newSprite, STAT_MISC); + + break; + + case PLAYERONWATER__STATIC: + if (spriteNum >= 0) + { + pSprite->xrepeat = sprite[spriteNum].xrepeat; + pSprite->yrepeat = sprite[spriteNum].yrepeat; + pSprite->zvel = 128; + if (sector[pSprite->sectnum].lotag != ST_2_UNDERWATER) + pSprite->cstat |= 32768; + } + changespritestat(newSprite, STAT_DUMMYPLAYER); + break; + + case APLAYER__STATIC: + pSprite->xrepeat = 0; + pSprite->yrepeat = 0; + pSprite->cstat = 32768; + + changespritestat(newSprite, ((!g_netServer && ud.multimode < 2) + || ((g_gametypeFlags[ud.coop] & GAMETYPE_COOPSPAWN) / GAMETYPE_COOPSPAWN) != pSprite->lotag) + ? STAT_MISC + : STAT_PLAYER); + break; + + case WATERBUBBLE__STATIC: + if (spriteNum >= 0) + { + if (sprite[spriteNum].picnum == APLAYER) + pSprite->z -= (16 << 8); + + pSprite->ang = sprite[spriteNum].ang; + } + + pSprite->xrepeat = pSprite->yrepeat = RR ? (1+(krand2()&7)) : 4; + changespritestat(newSprite, STAT_MISC); + break; + + case CRANE__STATIC: + + pSprite->cstat |= 64|257; + + pSprite->picnum += 2; + pSprite->z = sector[sectNum].ceilingz+(48<<8); + T5(newSprite) = tempwallptr; + + g_origins[tempwallptr] = *(vec2_t *) pSprite; + g_origins[tempwallptr+2].x = pSprite->z; + + + if (headspritestat[STAT_DEFAULT] != -1) + { + int findSprite = headspritestat[STAT_DEFAULT]; + + do + { + if (sprite[findSprite].picnum == CRANEPOLE && pSprite->hitag == (sprite[findSprite].hitag)) + { + g_origins[tempwallptr + 2].y = findSprite; + + T2(newSprite) = sprite[findSprite].sectnum; + + sprite[findSprite].xrepeat = 48; + sprite[findSprite].yrepeat = 128; + + g_origins[tempwallptr + 1] = *(vec2_t *) &sprite[findSprite]; + *(vec3_t *) &sprite[findSprite] = *(vec3_t *) pSprite; + sprite[findSprite].shade = pSprite->shade; + + setsprite(findSprite, (vec3_t *) &sprite[findSprite]); + break; + } + findSprite = nextspritestat[findSprite]; + } while (findSprite >= 0); + } + + tempwallptr += 3; + pSprite->owner = -1; + pSprite->extra = 8; + changespritestat(newSprite, STAT_STANDABLE); + break; + + case TRASH__STATIC: + pSprite->ang = krand2()&2047; + pSprite->xrepeat = pSprite->yrepeat = 24; + changespritestat(newSprite, STAT_STANDABLE); + break; + + case WATERDRIP__STATIC: + if (spriteNum >= 0 && (sprite[spriteNum].statnum == STAT_PLAYER || sprite[spriteNum].statnum == STAT_ACTOR)) + { + if (sprite[spriteNum].pal != 1) + { + pSprite->pal = 2; + pSprite->z -= (18<<8); + } + else pSprite->z -= (13<<8); + + pSprite->shade = 32; + pSprite->ang = getangle(g_player[0].ps->pos.x - pSprite->x, g_player[0].ps->pos.y - pSprite->y); + pSprite->xvel = 48 - (krand2() & 31); + + A_SetSprite(newSprite, CLIPMASK0); + } + else if (spriteNum == -1) + { + pSprite->z += ZOFFSET6; + T1(newSprite) = pSprite->z; + if (!RR) + T2(newSprite) = krand2()&127; + } + fallthrough__; + case WATERDRIPSPLASH__STATIC: + if (RR && pSprite->picnum == WATERDRIPSPLASH) goto default_case; + pSprite->xrepeat = pSprite->yrepeat = 24; + changespritestat(newSprite, STAT_STANDABLE); + break; + + case PLUG__STATIC: + pSprite->lotag = 9999; + changespritestat(newSprite, STAT_STANDABLE); + break; + case TOUCHPLATE__STATIC: + T3(newSprite) = sector[sectNum].floorz; + + if (sector[sectNum].lotag != ST_1_ABOVE_WATER && sector[sectNum].lotag != ST_2_UNDERWATER) + sector[sectNum].floorz = pSprite->z; + + if (pSprite->pal && (g_netServer || ud.multimode > 1)) + { + pSprite->xrepeat=pSprite->yrepeat=0; + changespritestat(newSprite, STAT_MISC); + break; + } + fallthrough__; + case WATERBUBBLEMAKER__STATIC: + if (EDUKE32_PREDICT_FALSE(pSprite->hitag && pSprite->picnum == WATERBUBBLEMAKER)) + { + // JBF 20030913: Pisses off X_Move(), eg. in bobsp2 + Printf(TEXTCOLOR_RED "WARNING: WATERBUBBLEMAKER %d @ %d,%d with hitag!=0. Applying fixup.\n", + newSprite,TrackerCast(pSprite->x),TrackerCast(pSprite->y)); + pSprite->hitag = 0; + } + pSprite->cstat |= 32768; + changespritestat(newSprite, STAT_STANDABLE); + break; + + case BOLT1__STATIC: + case SIDEBOLT1__STATIC: + if (RR && pSprite->picnum >= SIDEBOLT1 && pSprite->picnum <= SIDEBOLT1+3) goto default_case; + T1(newSprite) = pSprite->xrepeat; + T2(newSprite) = pSprite->yrepeat; + pSprite->yvel = 0; + + changespritestat(newSprite, STAT_STANDABLE); + break; + + case MASTERSWITCH__STATIC: + if (pSprite->picnum == MASTERSWITCH) + pSprite->cstat |= 32768; + pSprite->yvel = 0; + changespritestat(newSprite, STAT_STANDABLE); + break; + + case TARGET__STATIC: + case DUCK__STATIC: + case LETTER__STATIC: + if (RR) goto default_case; + pSprite->extra = 1; + pSprite->cstat |= 257; + changespritestat(newSprite, STAT_ACTOR); + break; + + case OCTABRAINSTAYPUT__STATIC: + case LIZTROOPSTAYPUT__STATIC: + case PIGCOPSTAYPUT__STATIC: + case LIZMANSTAYPUT__STATIC: + case BOSS1STAYPUT__STATIC: + case PIGCOPDIVE__STATIC: + case COMMANDERSTAYPUT__STATIC: + case BOSS4STAYPUT__STATIC: + if (RR) goto default_case; + pActor->actorstayput = pSprite->sectnum; + fallthrough__; + case BOSS1__STATIC: + case BOSS2__STATIC: + case BOSS3__STATIC: + case BOSS4__STATIC: + case ROTATEGUN__STATIC: + case GREENSLIME__STATIC: + if (RR) goto default_case; + if (pSprite->picnum == GREENSLIME) + pSprite->extra = 1; + fallthrough__; + case DRONE__STATIC: + case LIZTROOPONTOILET__STATIC: + case LIZTROOPJUSTSIT__STATIC: + case LIZTROOPSHOOT__STATIC: + case LIZTROOPJETPACK__STATIC: + case LIZTROOPDUCKING__STATIC: + case LIZTROOPRUNNING__STATIC: + case LIZTROOP__STATIC: + case OCTABRAIN__STATIC: + case COMMANDER__STATIC: + case PIGCOP__STATIC: + case LIZMAN__STATIC: + case LIZMANSPITTING__STATIC: + case LIZMANFEEDING__STATIC: + case LIZMANJUMP__STATIC: + case ORGANTIC__STATIC: + case RAT__STATIC: + case SHARK__STATIC: + if (RR) + { + if (pSprite->picnum == RAT || pSprite->picnum == SHARK || pSprite->picnum == DRONE) + goto rr_badguy; + goto default_case; + } + + if (pSprite->pal == 0) + { + switch (DYNAMICTILEMAP(pSprite->picnum)) + { + case LIZTROOPONTOILET__STATIC: + case LIZTROOPSHOOT__STATIC: + case LIZTROOPJETPACK__STATIC: + case LIZTROOPDUCKING__STATIC: + case LIZTROOPRUNNING__STATIC: + case LIZTROOPSTAYPUT__STATIC: + case LIZTROOPJUSTSIT__STATIC: + case LIZTROOP__STATIC: pSprite->pal = 22; break; + } + } + else + { + if (!PLUTOPAK) + pSprite->extra <<= 1; + } + + if (pSprite->picnum == BOSS4STAYPUT || pSprite->picnum == BOSS1 || pSprite->picnum == BOSS2 || + pSprite->picnum == BOSS1STAYPUT || pSprite->picnum == BOSS3 || pSprite->picnum == BOSS4) + { + if (spriteNum >= 0 && sprite[spriteNum].picnum == RESPAWN) + pSprite->pal = sprite[spriteNum].pal; + + if (pSprite->pal) + { + pSprite->clipdist = 80; + pSprite->xrepeat = pSprite->yrepeat = 40; + } + else + { + pSprite->xrepeat = pSprite->yrepeat = 80; + pSprite->clipdist = 164; + } + } + else + { + if (pSprite->picnum != SHARK) + { + pSprite->xrepeat = pSprite->yrepeat = 40; + pSprite->clipdist = 80; + } + else + { + pSprite->xrepeat = pSprite->yrepeat = 60; + pSprite->clipdist = 40; + } + } + + // If spawned from parent sprite (as opposed to 'from premap'), + // ignore skill. + if (spriteNum >= 0) + pSprite->lotag = 0; + + if ((pSprite->lotag > ud.player_skill) || ud.monsters_off == 1) + { + pSprite->xrepeat=pSprite->yrepeat=0; + changespritestat(newSprite, STAT_MISC); + break; + } + else + { + A_Fall(newSprite); + + if (pSprite->picnum == RAT) + { + pSprite->ang = krand2()&2047; + pSprite->xrepeat = pSprite->yrepeat = 48; + pSprite->cstat = 0; + } + else + { + pSprite->cstat |= 257; + + if (pSprite->picnum != SHARK) + g_player[myconnectindex].ps->max_actors_killed++; + } + + if (pSprite->picnum == ORGANTIC) pSprite->cstat |= 128; + + if (spriteNum >= 0) + { + pActor->timetosleep = 0; + A_PlayAlertSound(newSprite); + changespritestat(newSprite, STAT_ACTOR); + } + else changespritestat(newSprite, STAT_ZOMBIEACTOR); + } + + if (pSprite->picnum == ROTATEGUN) + pSprite->zvel = 0; + + break; + case BIKERB__STATICRR: + case BIKERBV2__STATICRR: + case BIKER__STATICRR: + case MAKEOUT__STATICRR: + case CHEERB__STATICRR: + case CHEER__STATICRR: + case COOTPLAY__STATICRR: + case BILLYPLAY__STATICRR: + case MINIONBOAT__STATICRR: + case HULKBOAT__STATICRR: + case CHEERBOAT__STATICRR: + case RABBIT__STATICRR: + case ROCK__STATICRR: + case ROCK2__STATICRR: + case MAMACLOUD__STATICRR: + case MAMA__STATICRR: + if (!RRRA) goto default_case; + goto rr_badguy; + case BILLYRAYSTAYPUT__STATICRR: + case BRAYSNIPER__STATICRR: + case BUBBASTAND__STATICRR: + case HULKSTAYPUT__STATICRR: + case HENSTAYPUT__STATICRR: + case PIGSTAYPUT__STATICRR: + case MINIONSTAYPUT__STATICRR: + case COOTSTAYPUT__STATICRR: + case SBSWIPE__STATICRR: + case CHEERSTAYPUT__STATICRR: + case SBMOVE__STATICRR: + if ((RRRA && pSprite->picnum == SBMOVE) || (!RRRA && (pSprite->picnum == SBSWIPE || pSprite->picnum == CHEERSTAYPUT))) goto default_case; + pActor->actorstayput = pSprite->sectnum; + fallthrough__; + case BOULDER__STATICRR: + case BOULDER1__STATICRR: + //case RAT__STATIC: + case TORNADO__STATICRR: + case BILLYCOCK__STATICRR: + case BILLYRAY__STATICRR: + case DOGRUN__STATICRR: + case LTH__STATICRR: + case HULK__STATICRR: + case HEN__STATICRR: + //case DRONE__STATIC: + case PIG__STATICRR: + case MINION__STATICRR: + case UFO1__STATICRR: + case UFO2__STATICRR: + case UFO3__STATICRR: + case UFO4__STATICRR: + case UFO5__STATICRR: + case COW__STATICRR: + case COOT__STATICRR: + //case SHARK__STATIC: + case VIXEN__STATICRR: +rr_badguy: + pSprite->xrepeat = 40; + pSprite->yrepeat = 40; + switch (DYNAMICTILEMAP(pSprite->picnum)) + { + case VIXEN__STATICRR: + if (pSprite->pal == 34) + { + pSprite->xrepeat = 22; + pSprite->yrepeat = 21; + } + else + { + pSprite->xrepeat = 22; + pSprite->yrepeat = 20; + } + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case HULKHANG__STATICRR: + case HULKHANGDEAD__STATICRR: + case HULKJUMP__STATICRR: + case HULK__STATICRR: + case HULKSTAYPUT__STATICRR: + pSprite->xrepeat = 32; + pSprite->yrepeat = 32; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case COOTPLAY__STATICRR: + if (!RRRA) break; + fallthrough__; + case COOT__STATICRR: + case COOTSTAYPUT__STATICRR: + pSprite->xrepeat = 24; + pSprite->yrepeat = 18; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + pSprite->clipdist <<= 2; + break; + case DRONE__STATIC: + pSprite->xrepeat = 14; + pSprite->yrepeat = 7; + pSprite->clipdist = 128; + break; + case SBSWIPE__STATICRR: + case BILLYPLAY__STATICRR: + if (!RRRA) break; + fallthrough__; + case BILLYCOCK__STATICRR: + case BILLYRAY__STATICRR: + case BILLYRAYSTAYPUT__STATICRR: + case BRAYSNIPER__STATICRR: + case BUBBASTAND__STATICRR: + pSprite->xrepeat = 25; + pSprite->yrepeat = 21; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case COW__STATICRR: + pSprite->xrepeat = 32; + pSprite->yrepeat = 32; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case HEN__STATICRR: + case HENSTAYPUT__STATICRR: + case HENSTAND__STATICRR: + if (pSprite->pal == 35) + { + pSprite->xrepeat = 42; + pSprite->yrepeat = 30; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + } + else + { + pSprite->xrepeat = 21; + pSprite->yrepeat = 15; + pSprite->clipdist = 64; + } + break; + case MINION__STATICRR: + case MINIONSTAYPUT__STATICRR: + pSprite->xrepeat = 16; + pSprite->yrepeat = 16; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + if (RRRA && g_ufoSpawnMinion) + pSprite->pal = 8; + break; + case DOGRUN__STATICRR: + case PIG__STATICRR: + pSprite->xrepeat = 16; + pSprite->yrepeat = 16; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case RABBIT__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 18; + pSprite->yrepeat = 18; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case MAMACLOUD__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 64; + pSprite->yrepeat = 64; + pSprite->cstat = 2; + pSprite->cstat |= 512; + pSprite->x += (krand2() & 2047) - 1024; + pSprite->y += (krand2() & 2047) - 1024; + pSprite->z += (krand2() & 2047) - 1024; + break; + case MAMA__STATICRR: + if (!RRRA) break; + if (pSprite->pal == 30) + { + pSprite->xrepeat = 26; + pSprite->yrepeat = 26; + pSprite->clipdist = 75; + } + else if (pSprite->pal == 31) + { + pSprite->xrepeat = 36; + pSprite->yrepeat = 36; + pSprite->clipdist = 100; + } + else if (pSprite->pal == 32) + { + pSprite->xrepeat = 50; + pSprite->yrepeat = 50; + pSprite->clipdist = 100; + } + else + { + pSprite->xrepeat = 50; + pSprite->yrepeat = 50; + pSprite->clipdist = 100; + } + break; + case BIKERB__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 28; + pSprite->yrepeat = 22; + pSprite->clipdist = 72; + break; + case BIKERBV2__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 28; + pSprite->yrepeat = 22; + pSprite->clipdist = 72; + break; + case BIKER__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 28; + pSprite->yrepeat = 22; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case CHEERB__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 28; + pSprite->yrepeat = 22; + pSprite->clipdist = 72; + break; + case CHEER__STATICRR: + case CHEERSTAYPUT__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 20; + pSprite->yrepeat = 20; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case MAKEOUT__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 26; + pSprite->yrepeat = 26; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case MINIONBOAT__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 16; + pSprite->yrepeat = 16; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case HULKBOAT__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 48; + pSprite->yrepeat = 48; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case CHEERBOAT__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 32; + pSprite->yrepeat = 32; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case TORNADO__STATICRR: + pSprite->xrepeat = 64; + pSprite->yrepeat = 128; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + pSprite->clipdist >>= 2; + pSprite->cstat = 2; + break; + case LTH__STATICRR: + pSprite->xrepeat = 24; + pSprite->yrepeat = 22; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case ROCK__STATICRR: + case ROCK2__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 64; + pSprite->yrepeat = 64; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + case UFO1__STATICRR: + case UFO2__STATICRR: + case UFO3__STATICRR: + case UFO4__STATICRR: + case UFO5__STATICRR: + pSprite->xrepeat = 32; + pSprite->yrepeat = 32; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + pSprite->extra = 50; + break; + case SBMOVE__STATICRR: + if (RRRA) break; + pSprite->xrepeat = 48; + pSprite->yrepeat = 48; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + break; + } + + if (spriteNum >= 0) pSprite->lotag = 0; + + if ((pSprite->lotag > ud.player_skill) || ud.monsters_off == 1) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + else + { + A_Fall(newSprite); + + if (pSprite->picnum == RAT) + { + pSprite->ang = krand2() & 2047; + pSprite->xrepeat = pSprite->yrepeat = 48; + pSprite->cstat = 0; + } + else + { + pSprite->cstat |= 257; + + if (pSprite->picnum != SHARK) + if (!RR || A_CheckSpriteFlags(newSprite, SFLAG_KILLCOUNT)) + g_player[myconnectindex].ps->max_actors_killed++; + } + + if (spriteNum >= 0) + { + pActor->timetosleep = 0; + A_PlayAlertSound(newSprite); + changespritestat(newSprite, STAT_ACTOR); + } + else changespritestat(newSprite, STAT_ZOMBIEACTOR); + + if (RR && spriteNum >= 0) + pSprite->shade = sprite[spriteNum].shade; + } + + break; + case LOCATORS__STATIC: + pSprite->cstat |= 32768; + changespritestat(newSprite, STAT_LOCATOR); + break; + + case ACTIVATORLOCKED__STATIC: + case ACTIVATOR__STATIC: + if (RR) + { + pSprite->cstat |= 32768; + if (pSprite->picnum == ACTIVATORLOCKED) + sector[pSprite->sectnum].lotag ^= 16384; + } + else + { + pSprite->cstat = 32768; + if (pSprite->picnum == ACTIVATORLOCKED) + sector[pSprite->sectnum].lotag |= 16384; + } + changespritestat(newSprite, STAT_ACTIVATOR); + break; + + case DOORSHOCK__STATIC: + pSprite->cstat |= 1+256; + pSprite->shade = -12; + changespritestat(newSprite, STAT_STANDABLE); + break; + + case OOZ__STATIC: + case OOZ2__STATIC: + { + if (RR && pSprite->picnum == OOZ2) goto default_case; + pSprite->shade = -12; + + if (spriteNum >= 0) + { + if (sprite[spriteNum].picnum == NUKEBARREL) + pSprite->pal = 8; + if (!RR) + A_AddToDeleteQueue(newSprite); + } + + changespritestat(newSprite, STAT_ACTOR); + + A_GetZLimits(newSprite); + + int const oozSize = (pActor->floorz-pActor->ceilingz)>>9; + + pSprite->yrepeat = oozSize; + pSprite->xrepeat = 25 - (oozSize >> 1); + pSprite->cstat |= (krand2() & 4); + + break; + } + + case REACTOR2__STATIC: + case REACTOR__STATIC: + pSprite->extra = g_impactDamage; + pSprite->cstat |= 257; + if ((!g_netServer && ud.multimode < 2) && pSprite->pal != 0) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + + pSprite->pal = 0; + pSprite->shade = -17; + + changespritestat(newSprite, STAT_ZOMBIEACTOR); + break; + + case HEAVYHBOMB__STATIC: + if (!RR && spriteNum >= 0) + pSprite->owner = spriteNum; + else pSprite->owner = newSprite; + + pSprite->xrepeat = pSprite->yrepeat = 9; + pSprite->yvel = 4; + pSprite->cstat |= 257; + + if ((!g_netServer && ud.multimode < 2) && pSprite->pal != 0) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + pSprite->pal = 0; + pSprite->shade = -17; + + changespritestat(newSprite, STAT_ZOMBIEACTOR); + break; + + case RECON__STATIC: + if (pSprite->lotag > ud.player_skill) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + goto SPAWN_END; + } + if (!RR || A_CheckSpriteFlags(newSprite, SFLAG_KILLCOUNT)) + g_player[myconnectindex].ps->max_actors_killed++; + pActor->t_data[5] = 0; + if (ud.monsters_off == 1) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + pSprite->extra = 130; + pSprite->cstat |= 257; // Make it hitable + + if ((!g_netServer && ud.multimode < 2) && pSprite->pal != 0) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + pSprite->pal = 0; + pSprite->shade = -17; + + changespritestat(newSprite, STAT_ZOMBIEACTOR); + break; + + case ATOMICHEALTH__STATIC: + case STEROIDS__STATIC: + case HEATSENSOR__STATIC: + case SHIELD__STATIC: + case AIRTANK__STATIC: + case TRIPBOMBSPRITE__STATIC: + case JETPACK__STATIC: + case HOLODUKE__STATIC: + + case FIRSTGUNSPRITE__STATIC: + case CHAINGUNSPRITE__STATIC: + case SHOTGUNSPRITE__STATIC: + case RPGSPRITE__STATIC: + case SHRINKERSPRITE__STATIC: + case FREEZESPRITE__STATIC: + case DEVISTATORSPRITE__STATIC: + + case SHOTGUNAMMO__STATIC: + case FREEZEAMMO__STATIC: + case HBOMBAMMO__STATIC: + case CRYSTALAMMO__STATIC: + case GROWAMMO__STATIC: + case BATTERYAMMO__STATIC: + case DEVISTATORAMMO__STATIC: + case RPGAMMO__STATIC: + case BOOTS__STATIC: + case AMMO__STATIC: + case AMMOLOTS__STATIC: + case COLA__STATIC: + case FIRSTAID__STATIC: + case SIXPAK__STATIC: + case RRTILE43__STATICRR: + case BOWLINGBALLSPRITE__STATICRR: + case RPG2SPRITE__STATICRR: + case MOTOAMMO__STATICRR: + case BOATAMMO__STATICRR: + + if (RR && !RRRA && (pSprite->picnum == RPG2SPRITE || pSprite->picnum == MOTOAMMO || pSprite->picnum == BOATAMMO)) goto default_case; + + if (spriteNum >= 0) + { + pSprite->lotag = 0; + if (RR && pSprite->picnum == BOWLINGBALLSPRITE) + pSprite->zvel = 0; + else + { + pSprite->z -= ZOFFSET5; + pSprite->zvel = -1024; + } + A_SetSprite(newSprite, CLIPMASK0); + pSprite->cstat = krand2()&4; + } + else + { + pSprite->owner = newSprite; + pSprite->cstat = 0; + } + + if (((!g_netServer && ud.multimode < 2) && pSprite->pal != 0) || (pSprite->lotag > ud.player_skill)) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + + pSprite->pal = 0; + + if (pSprite->picnum == ATOMICHEALTH) + pSprite->cstat |= 128; + + fallthrough__; + case ACCESSCARD__STATIC: + if ((g_netServer || ud.multimode > 1) && !GTFLAGS(GAMETYPE_ACCESSCARDSPRITES) && pSprite->picnum == ACCESSCARD) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + else + { + if (pSprite->picnum == AMMO) + pSprite->xrepeat = pSprite->yrepeat = 16; + else pSprite->xrepeat = pSprite->yrepeat = 32; + } + + pSprite->shade = -17; + + if (spriteNum >= 0) + { + changespritestat(newSprite, STAT_ACTOR); + } + else + { + changespritestat(newSprite, STAT_ZOMBIEACTOR); + A_Fall(newSprite); + } + if (RR) + { + switch (DYNAMICTILEMAP(pSprite->picnum)) + { + case FIRSTGUNSPRITE__STATIC: + pSprite->xrepeat = 16; + pSprite->yrepeat = 16; + break; + case SHOTGUNAMMO__STATIC: + pSprite->xrepeat = 18; + pSprite->yrepeat = 17; + if (RRRA) + pSprite->cstat = 256; + break; + case SIXPAK__STATIC: + pSprite->xrepeat = 13; + pSprite->yrepeat = 9; + if (RRRA) + pSprite->cstat = 256; + break; + case FIRSTAID__STATIC: + pSprite->xrepeat = 8; + pSprite->yrepeat = 8; + break; + case COLA__STATIC: + pSprite->xrepeat = 5; + pSprite->yrepeat = 4; + break; + case AMMO__STATIC: + pSprite->xrepeat = 9; + pSprite->yrepeat = 9; + break; + case MOTOAMMO__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 23; + pSprite->yrepeat = 23; + break; + case BOATAMMO__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 16; + pSprite->yrepeat = 16; + break; + case JETPACK__STATIC: + pSprite->xrepeat = 8; + pSprite->yrepeat = 6; + break; + case STEROIDS__STATIC: + pSprite->xrepeat = 13; + pSprite->yrepeat = 9; + break; + case ACCESSCARD__STATIC: + pSprite->xrepeat = 11; + pSprite->yrepeat = 12; + break; + case HEATSENSOR__STATIC: + pSprite->xrepeat = 6; + pSprite->yrepeat = 4; + break; + case AIRTANK__STATIC: + pSprite->xrepeat = 19; + pSprite->yrepeat = 16; + break; + case BATTERYAMMO__STATIC: + pSprite->xrepeat = 15; + pSprite->yrepeat = 15; + break; + case BOWLINGBALLSPRITE__STATICRR: + pSprite->xrepeat = 11; + pSprite->yrepeat = 11; + break; + case TRIPBOMBSPRITE__STATIC: + pSprite->xrepeat = 11; + pSprite->yrepeat = 11; + pSprite->yvel = 4; + pSprite->xvel = 32; + break; + case RPGSPRITE__STATIC: + pSprite->xrepeat = 16; + pSprite->yrepeat = 14; + break; + case RPG2SPRITE__STATICRR: + if (!RRRA) break; + pSprite->xrepeat = 20; + pSprite->yrepeat = 20; + break; + case SHRINKERSPRITE__STATIC: + pSprite->xrepeat = 22; + pSprite->yrepeat = 13; + break; + case DEVISTATORSPRITE__STATIC: + pSprite->xrepeat = 18; + pSprite->yrepeat = 17; + break; + case RRTILE43__STATICRR: + pSprite->xrepeat = 12; + pSprite->yrepeat = 7; + break; + case GROWSPRITEICON__STATIC: + pSprite->xrepeat = 10; + pSprite->yrepeat = 9; + break; + case DEVISTATORAMMO__STATIC: + pSprite->xrepeat = 10; + pSprite->yrepeat = 9; + break; + case ATOMICHEALTH__STATIC: + pSprite->xrepeat = 8; + pSprite->yrepeat = 8; + break; + case FREEZESPRITE__STATIC: + pSprite->xrepeat = 17; + pSprite->yrepeat = 16; + break; + } + pSprite->shade = sector[pSprite->sectnum].floorshade; + } + break; + + case WATERFOUNTAIN__STATIC: + SLT(newSprite) = 1; + fallthrough__; + case TREE1__STATIC: + case TREE2__STATIC: + case TIRE__STATIC: + case CONE__STATIC: + case BOX__STATIC: + if (RR && (pSprite->picnum == CONE || pSprite->picnum == BOX)) goto default_case; + pSprite->cstat = 257; // Make it hitable + sprite[newSprite].extra = 1; + changespritestat(newSprite, STAT_STANDABLE); + break; + + case FLOORFLAME__STATIC: + if (RR) goto default_case; + pSprite->shade = -127; + changespritestat(newSprite, STAT_STANDABLE); + break; + + case BOUNCEMINE__STATIC: + if (RR) goto default_case; + pSprite->owner = newSprite; + pSprite->cstat |= 1+256; //Make it hitable + pSprite->xrepeat = pSprite->yrepeat = 24; + pSprite->shade = -127; + pSprite->extra = g_impactDamage<<2; + changespritestat(newSprite, STAT_ZOMBIEACTOR); + break; + case CAMERA1__STATIC: + pSprite->extra = 1; + pSprite->cstat &= 32768; + + if (g_damageCameras) + pSprite->cstat |= 257; + + if ((!g_netServer && ud.multimode < 2) && pSprite->pal != 0) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + } + else + { + pSprite->pal = 0; + changespritestat(newSprite, STAT_ACTOR); + } + break; + case CAMERAPOLE__STATIC: + pSprite->extra = 1; + pSprite->cstat &= 32768; + + if (g_damageCameras) + pSprite->cstat |= 257; + fallthrough__; + case GENERICPOLE__STATIC: + if (RR && pSprite->picnum == GENERICPOLE) goto default_case; + if ((!g_netServer && ud.multimode < 2) && pSprite->pal != 0) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + } + else + pSprite->pal = 0; + break; + + case STEAM__STATIC: + if (spriteNum >= 0) + { + pSprite->ang = sprite[spriteNum].ang; + pSprite->cstat = 16+128+2; + pSprite->xrepeat=pSprite->yrepeat=1; + pSprite->xvel = -8; + A_SetSprite(newSprite, CLIPMASK0); + } + fallthrough__; + case CEILINGSTEAM__STATIC: + changespritestat(newSprite, STAT_STANDABLE); + break; + + case SECTOREFFECTOR__STATIC: + pSprite->cstat |= 32768; + pSprite->xrepeat = pSprite->yrepeat = 0; + + switch (pSprite->lotag) + { +#ifdef LEGACY_ROR + case 40: + case 41: + if (RR) break; + pSprite->cstat = 32; + pSprite->xrepeat = pSprite->yrepeat = 64; + changespritestat(newSprite, STAT_EFFECTOR); + for (spriteNum=0; spriteNum < MAXSPRITES; spriteNum++) + if (sprite[spriteNum].picnum == SECTOREFFECTOR && (sprite[spriteNum].lotag == 40 || sprite[spriteNum].lotag == 41) && + sprite[spriteNum].hitag == pSprite->hitag && newSprite != spriteNum) + { +// Printf("found ror match\n"); + pSprite->yvel = spriteNum; + break; + } + goto SPAWN_END; + break; + case 46: + if (RR) break; + ror_protectedsectors[pSprite->sectnum] = 1; + /* XXX: fall-through intended? */ + fallthrough__; +#endif + case SE_49_POINT_LIGHT: + case SE_50_SPOT_LIGHT: + { + int32_t j, nextj; + + for (TRAVERSE_SPRITE_SECT(headspritesect[pSprite->sectnum], j, nextj)) + if (sprite[j].picnum == ACTIVATOR || sprite[j].picnum == ACTIVATORLOCKED) + pActor->flags |= SFLAG_USEACTIVATOR; + } + changespritestat(newSprite, pSprite->lotag==46 ? STAT_EFFECTOR : STAT_LIGHT); + goto SPAWN_END; + break; + } + + pSprite->yvel = sector[sectNum].extra; + + switch (pSprite->lotag) + { + case SE_28_LIGHTNING: + if (!RR) + T6(newSprite) = 65;// Delay for lightning + break; + case SE_7_TELEPORT: // Transporters!!!! + case SE_23_ONE_WAY_TELEPORT:// XPTR END + if (pSprite->lotag != SE_23_ONE_WAY_TELEPORT) + { + for (spriteNum=0; spriteNumcstat = 0; + changespritestat(newSprite, STAT_TRANSPORT); + goto SPAWN_END; + case SE_1_PIVOT: + pSprite->owner = -1; + T1(newSprite) = 1; + break; + case SE_18_INCREMENTAL_SECTOR_RISE_FALL: + + if (pSprite->ang == 512) + { + T2(newSprite) = sector[sectNum].ceilingz; + if (pSprite->pal) + sector[sectNum].ceilingz = pSprite->z; + } + else + { + T2(newSprite) = sector[sectNum].floorz; + if (pSprite->pal) + sector[sectNum].floorz = pSprite->z; + } + + pSprite->hitag <<= 2; + break; + + case SE_19_EXPLOSION_LOWERS_CEILING: + pSprite->owner = -1; + break; + case SE_25_PISTON: // Pistons + if (RR) + T5(newSprite) = sector[sectNum].ceilingz; + else + { + T4(newSprite) = sector[sectNum].ceilingz; + T5(newSprite) = 1; + } + sector[sectNum].ceilingz = pSprite->z; + G_SetInterpolation(§or[sectNum].ceilingz); + break; + case SE_35: + sector[sectNum].ceilingz = pSprite->z; + break; + case SE_27_DEMO_CAM: + if (ud.recstat == 1) + { + pSprite->xrepeat=pSprite->yrepeat=64; + pSprite->cstat &= 32768; + } + break; + case 47: + case 48: + if (!RRRA) break; + fallthrough__; + case SE_12_LIGHT_SWITCH: + + T2(newSprite) = sector[sectNum].floorshade; + T3(newSprite) = sector[sectNum].ceilingshade; + break; + + case SE_13_EXPLOSIVE: + + T1(newSprite) = sector[sectNum].ceilingz; + T2(newSprite) = sector[sectNum].floorz; + + if (klabs(T1(newSprite)-pSprite->z) < klabs(T2(newSprite)-pSprite->z)) + pSprite->owner = 1; + else pSprite->owner = 0; + + if (pSprite->ang == 512) + { + if (pSprite->owner) + sector[sectNum].ceilingz = pSprite->z; + else + sector[sectNum].floorz = pSprite->z; +#ifdef YAX_ENABLE + { + int16_t cf=!pSprite->owner, bn=yax_getbunch(sectNum, cf); + int32_t jj, daz=SECTORFLD(sectNum,z, cf); + + if (bn >= 0) + { + for (SECTORS_OF_BUNCH(bn, cf, jj)) + { + SECTORFLD(jj,z, cf) = daz; + SECTORFLD(jj,stat, cf) &= ~256; + SECTORFLD(jj,stat, cf) |= 128 + 512+2048; + } + for (SECTORS_OF_BUNCH(bn, !cf, jj)) + { + SECTORFLD(jj,z, !cf) = daz; + SECTORFLD(jj,stat, !cf) &= ~256; + SECTORFLD(jj,stat, !cf) |= 128 + 512+2048; + } + } + } +#endif + } + else + sector[sectNum].ceilingz = sector[sectNum].floorz = pSprite->z; + + if (sector[sectNum].ceilingstat&1) + { + sector[sectNum].ceilingstat ^= 1; + T4(newSprite) = 1; + + if (!pSprite->owner && pSprite->ang==512) + { + sector[sectNum].ceilingstat ^= 1; + T4(newSprite) = 0; + } + + sector[sectNum].ceilingshade = + sector[sectNum].floorshade; + + if (pSprite->ang==512) + { + int const startwall = sector[sectNum].wallptr; + int const endwall = startwall + sector[sectNum].wallnum; + for (bssize_t j = startwall; j < endwall; j++) + { + int const nextSect = wall[j].nextsector; + + if (nextSect >= 0) + { + if (!(sector[nextSect].ceilingstat & 1)) + { + sector[sectNum].ceilingpicnum = sector[nextSect].ceilingpicnum; + sector[sectNum].ceilingshade = sector[nextSect].ceilingshade; + break; // Leave earily + } + } + } + } + } + + break; + + case SE_17_WARP_ELEVATOR: + { + T3(newSprite) = sector[sectNum].floorz; // Stopping loc + + int nextSectNum = nextsectorneighborz(sectNum, sector[sectNum].floorz, -1, -1); + + if (EDUKE32_PREDICT_TRUE(nextSectNum >= 0)) + T4(newSprite) = sector[nextSectNum].ceilingz; + else + { + // use elevator sector's ceiling as heuristic + T4(newSprite) = sector[sectNum].ceilingz; + + Printf(TEXTCOLOR_RED "WARNING: SE17 sprite %d using own sector's ceilingz to " + "determine when to warp. Sector %d adjacent to a door?\n", + newSprite, sectNum); + } + + nextSectNum = nextsectorneighborz(sectNum, sector[sectNum].ceilingz, 1, 1); + + if (EDUKE32_PREDICT_TRUE(nextSectNum >= 0)) + T5(newSprite) = sector[nextSectNum].floorz; + else + { + // heuristic + T5(newSprite) = sector[sectNum].floorz; + + Printf(TEXTCOLOR_RED "WARNING: SE17 sprite %d using own sector %d's floorz.\n", + newSprite, sectNum); + } + + if (numplayers < 2 && !g_netServer) + { + G_SetInterpolation(§or[sectNum].floorz); + G_SetInterpolation(§or[sectNum].ceilingz); + } + } + break; + + case SE_24_CONVEYOR: + pSprite->yvel <<= 1; + case SE_36_PROJ_SHOOTER: + break; + + case SE_20_STRETCH_BRIDGE: + { + int closestDist = INT32_MAX; + int closestWall = 0; + int const startWall = sector[sectNum].wallptr; + int const endWall = startWall + sector[sectNum].wallnum; + + for (bssize_t findWall=startWall; findWallx - x, pSprite->y - y); + + if (d < closestDist) + { + closestDist = d; + closestWall = findWall; + } + } + + T2(newSprite) = closestWall; + + closestDist = INT32_MAX; + + for (bssize_t findWall=startWall; findWallx - x, pSprite->y - y); + + if (d < closestDist && findWall != T2(newSprite)) + { + closestDist = d; + closestWall = findWall; + } + } + + T3(newSprite) = closestWall; + } + + break; + + case SE_3_RANDOM_LIGHTS_AFTER_SHOT_OUT: + { + + T4(newSprite)=sector[sectNum].floorshade; + + sector[sectNum].floorshade = pSprite->shade; + sector[sectNum].ceilingshade = pSprite->shade; + + pSprite->owner = sector[sectNum].ceilingpal << 8; + pSprite->owner |= sector[sectNum].floorpal; + + //fix all the walls; + + int const startWall = sector[sectNum].wallptr; + int const endWall = startWall+sector[sectNum].wallnum; + + for (bssize_t w=startWall; wshade; + + if ((wall[w].cstat & 2) && wall[w].nextwall >= 0) + wall[wall[w].nextwall].shade = pSprite->shade; + } + break; + } + + case SE_31_FLOOR_RISE_FALL: + { + T2(newSprite) = sector[sectNum].floorz; + + if (pSprite->ang != 1536) + { + sector[sectNum].floorz = pSprite->z; + Yax_SetBunchZs(sectNum, YAX_FLOOR, pSprite->z); + } + + int const startWall = sector[sectNum].wallptr; + int const endWall = startWall + sector[sectNum].wallnum; + + for (bssize_t w = startWall; w < endWall; ++w) + if (wall[w].hitag == 0) + wall[w].hitag = 9999; + + G_SetInterpolation(§or[sectNum].floorz); + Yax_SetBunchInterpolation(sectNum, YAX_FLOOR); + } + break; + + case SE_32_CEILING_RISE_FALL: + { + T2(newSprite) = sector[sectNum].ceilingz; + T3(newSprite) = pSprite->hitag; + + if (pSprite->ang != 1536) + { + sector[sectNum].ceilingz = pSprite->z; + Yax_SetBunchZs(sectNum, YAX_CEILING, pSprite->z); + } + + int const startWall = sector[sectNum].wallptr; + int const endWall = startWall + sector[sectNum].wallnum; + + for (bssize_t w = startWall; w < endWall; ++w) + if (wall[w].hitag == 0) + wall[w].hitag = 9999; + + G_SetInterpolation(§or[sectNum].ceilingz); + Yax_SetBunchInterpolation(sectNum, YAX_CEILING); + } + break; + + case SE_4_RANDOM_LIGHTS: //Flashing lights + { + T3(newSprite) = sector[sectNum].floorshade; + + int const startWall = sector[sectNum].wallptr; + int const endWall = startWall + sector[sectNum].wallnum; + + pSprite->owner = sector[sectNum].ceilingpal << 8; + pSprite->owner |= sector[sectNum].floorpal; + + for (bssize_t w = startWall; w < endWall; ++w) + if (wall[w].shade > T4(newSprite)) + T4(newSprite) = wall[w].shade; + } + break; + + case SE_9_DOWN_OPEN_DOOR_LIGHTS: + if (sector[sectNum].lotag && + labs(sector[sectNum].ceilingz-pSprite->z) > 1024) + sector[sectNum].lotag |= 32768u; //If its open + fallthrough__; + case SE_8_UP_OPEN_DOOR_LIGHTS: + //First, get the ceiling-floor shade + { + T1(newSprite) = sector[sectNum].floorshade; + T2(newSprite) = sector[sectNum].ceilingshade; + + int const startWall = sector[sectNum].wallptr; + int const endWall = startWall + sector[sectNum].wallnum; + + for (bssize_t w = startWall; w < endWall; ++w) + if (wall[w].shade > T3(newSprite)) + T3(newSprite) = wall[w].shade; + + T4(newSprite) = 1; // Take Out; + } + break; + case 88: + //First, get the ceiling-floor shade + { + if (!RRRA) break; + T1(newSprite) = sector[sectNum].floorshade; + T2(newSprite) = sector[sectNum].ceilingshade; + + int const startWall = sector[sectNum].wallptr; + int const endWall = startWall + sector[sectNum].wallnum; + + for (bssize_t w = startWall; w < endWall; ++w) + if (wall[w].shade > T3(newSprite)) + T3(newSprite) = wall[w].shade; + + T4(newSprite) = 1; // Take Out; + } + break; + + case SE_11_SWINGING_DOOR: // Pivitor rotater + T4(newSprite) = (pSprite->ang > 1024) ? 2 : -2; + fallthrough__; + case SE_0_ROTATING_SECTOR: + case SE_2_EARTHQUAKE: // Earthquakemakers + case SE_5: // Boss Creature + case SE_6_SUBWAY: // Subway + case SE_14_SUBWAY_CAR: // Caboos + case SE_15_SLIDING_DOOR: // Subwaytype sliding door + case SE_16_REACTOR: // That rotating blocker reactor thing + case SE_26: // ESCELATOR + case SE_30_TWO_WAY_TRAIN: // No rotational subways + if (pSprite->lotag == SE_0_ROTATING_SECTOR) + { + if (sector[sectNum].lotag == ST_30_ROTATE_RISE_BRIDGE) + { + sprite[newSprite].clipdist = (pSprite->pal) ? 1 : 0; + T4(newSprite) = sector[sectNum].floorz; + sector[sectNum].hitag = newSprite; + } + + for (spriteNum = MAXSPRITES-1; spriteNum>=0; spriteNum--) + { + if (sprite[spriteNum].statnum < MAXSTATUS) + if (sprite[spriteNum].picnum == SECTOREFFECTOR && + sprite[spriteNum].lotag == SE_1_PIVOT && + sprite[spriteNum].hitag == pSprite->hitag) + { + if (pSprite->ang == 512) + { + pSprite->x = sprite[spriteNum].x; + pSprite->y = sprite[spriteNum].y; + } + break; + } + } + if (EDUKE32_PREDICT_FALSE(spriteNum == -1)) + { + Printf(TEXTCOLOR_RED "Found lonely Sector Effector (lotag 0) at (%d,%d)\n", + TrackerCast(pSprite->x),TrackerCast(pSprite->y)); + changespritestat(newSprite, STAT_ACTOR); + goto SPAWN_END; + } + pSprite->owner = spriteNum; + } + + { + int const startWall = sector[sectNum].wallptr; + int const endWall = startWall+sector[sectNum].wallnum; + + T2(newSprite) = tempwallptr; + for (bssize_t w = startWall; w < endWall; ++w) + { + g_origins[tempwallptr].x = wall[w].x - pSprite->x; + g_origins[tempwallptr].y = wall[w].y - pSprite->y; + + tempwallptr++; + if (EDUKE32_PREDICT_FALSE(tempwallptr >= MAXANIMPOINTS)) + { + Bsprintf(tempbuf, "Too many moving sectors at (%d,%d).\n", + TrackerCast(wall[w].x), TrackerCast(wall[w].y)); + G_GameExit(tempbuf); + } + } + } + + if (pSprite->lotag == SE_5 || pSprite->lotag == SE_30_TWO_WAY_TRAIN || + pSprite->lotag == SE_6_SUBWAY || pSprite->lotag == SE_14_SUBWAY_CAR) + { +#ifdef YAX_ENABLE + int outerWall = -1; +#endif + int const startWall = sector[sectNum].wallptr; + int const endWall = startWall + sector[sectNum].wallnum; + + pSprite->extra = (uint16_t)((uint16_t)sector[sectNum].hitag != UINT16_MAX); + + // TRAIN_SECTOR_TO_SE_INDEX + sector[sectNum].hitag = newSprite; + + spriteNum = 0; + + int foundWall = startWall; + + for (; foundWall= 0 && + sector[ wall[ foundWall ].nextsector].hitag == 0 && + ((int16_t)sector[ wall[ foundWall ].nextsector].lotag < 3 || (RRRA && (int16_t)sector[wall[foundWall].nextsector].lotag == 160))) + { +#ifdef YAX_ENABLE + outerWall = wall[foundWall].nextwall; +#endif + foundWall = wall[foundWall].nextsector; + spriteNum = 1; + break; + } + } + +#ifdef YAX_ENABLE + pActor->t_data[9] = -1; + + if (outerWall >= 0) + { + int upperSect = yax_vnextsec(outerWall, YAX_CEILING); + + if (upperSect >= 0) + { + int foundEffector = headspritesect[upperSect]; + + for (; foundEffector >= 0; foundEffector = nextspritesect[foundEffector]) + if (sprite[foundEffector].picnum == SECTOREFFECTOR && sprite[foundEffector].lotag == pSprite->lotag) + break; + + if (foundEffector < 0) + { + Sect_SetInterpolation(upperSect); + pActor->t_data[9] = upperSect; + } + } + } +#endif + if (spriteNum == 0) + { + Bsprintf(tempbuf,"Subway found no zero'd sectors with locators\nat (%d,%d).\n", + TrackerCast(pSprite->x),TrackerCast(pSprite->y)); + G_GameExit(tempbuf); + } + + pSprite->owner = -1; + T1(newSprite) = foundWall; + + if (pSprite->lotag != SE_30_TWO_WAY_TRAIN) + T4(newSprite) = pSprite->hitag; + } + else if (pSprite->lotag == SE_16_REACTOR) + T4(newSprite) = sector[sectNum].ceilingz; + else if (pSprite->lotag == SE_26) + { + T4(newSprite) = pSprite->x; + T5(newSprite) = pSprite->y; + pSprite->zvel = (pSprite->shade == sector[sectNum].floorshade) ? -256 : 256; // UP + pSprite->shade = 0; + } + else if (pSprite->lotag == SE_2_EARTHQUAKE) + { + T6(newSprite) = sector[pSprite->sectnum].floorheinum; + sector[pSprite->sectnum].floorheinum = 0; + } + } + + switch (pSprite->lotag) + { + case SE_6_SUBWAY: + case SE_14_SUBWAY_CAR: + S_FindMusicSFX(sectNum, &spriteNum); + // XXX: uh.. what? + if (spriteNum == -1) + { + if (RR && sector[pSprite->sectnum].floorpal == 7) + spriteNum = 456; + else + spriteNum = SUBWAY; + } + pActor->lastv.x = spriteNum; + fallthrough__; + case SE_30_TWO_WAY_TRAIN: + if (g_netServer || numplayers > 1) + break; + fallthrough__; + case SE_0_ROTATING_SECTOR: + case SE_1_PIVOT: + case SE_5: + case SE_11_SWINGING_DOOR: + case SE_15_SLIDING_DOOR: + case SE_16_REACTOR: + case SE_26: Sect_SetInterpolation(sprite[newSprite].sectnum); break; + } + + if (RRRA && sprite[newSprite].lotag >= 150 && sprite[newSprite].lotag <= 155) + changespritestat(newSprite, STAT_RAROR); + else + changespritestat(newSprite, STAT_EFFECTOR); + break; + + case SEENINE__STATIC: + case OOZFILTER__STATIC: + pSprite->shade = -16; + if (pSprite->xrepeat <= 8) + { + pSprite->cstat = 32768; + pSprite->xrepeat = 0; + pSprite->yrepeat = 0; + } + else pSprite->cstat = 1+256; + + pSprite->extra = g_impactDamage << 2; + pSprite->owner = newSprite; + + changespritestat(newSprite, STAT_STANDABLE); + break; + + case CRACK1__STATIC: + case CRACK2__STATIC: + case CRACK3__STATIC: + case CRACK4__STATIC: + case FIREEXT__STATIC: + if (RR && pSprite->picnum == FIREEXT) goto default_case; + if (!RR && pSprite->picnum == FIREEXT) + { + pSprite->cstat = 257; + pSprite->extra = g_impactDamage<<2; + } + else + { + pSprite->cstat |= (pSprite->cstat & 48) ? 1 : 17; + pSprite->extra = 1; + } + + if ((!g_netServer && ud.multimode < 2) && pSprite->pal != 0) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + break; + } + + pSprite->pal = 0; + pSprite->owner = newSprite; + pSprite->xvel = 8; + + changespritestat(newSprite, STAT_STANDABLE); + A_SetSprite(newSprite,CLIPMASK0); + break; + + case EMPTYBIKE__STATICRR: + if (!RRRA) goto default_case; + if ((!g_netServer && ud.multimode < 2) && pSprite->pal == 1) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + break; + } + pSprite->pal = 0; + pSprite->xrepeat = 18; + pSprite->yrepeat = 18; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + pSprite->owner = 100; + pSprite->cstat = 257; + pSprite->lotag = 1; + changespritestat(newSprite, 1); + break; + case EMPTYBOAT__STATICRR: + if (!RRRA) goto default_case; + if ((!g_netServer && ud.multimode < 2) && pSprite->pal == 1) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + break; + } + pSprite->pal = 0; + pSprite->xrepeat = 32; + pSprite->yrepeat = 32; + pSprite->clipdist = mulscale7(pSprite->xrepeat, tilesiz[pSprite->picnum].x); + pSprite->owner = 20; + pSprite->cstat = 257; + pSprite->lotag = 1; + changespritestat(newSprite, 1); + break; + + case TOILET__STATIC: + case STALL__STATIC: + case RRTILE2121__STATICRR: + case RRTILE2122__STATICRR: + pSprite->lotag = 1; + pSprite->cstat |= 257; + pSprite->clipdist = 8; + pSprite->owner = newSprite; + break; + + case CANWITHSOMETHING2__STATIC: + case CANWITHSOMETHING3__STATIC: + case CANWITHSOMETHING4__STATIC: + if (RR) goto default_case; + fallthrough__; + case CANWITHSOMETHING__STATIC: + case RUBBERCAN__STATIC: + pSprite->extra = 0; + fallthrough__; + case EXPLODINGBARREL__STATIC: + case HORSEONSIDE__STATIC: + case FIREBARREL__STATIC: + case NUKEBARREL__STATIC: + case FIREVASE__STATIC: + case NUKEBARRELDENTED__STATIC: + case NUKEBARRELLEAKED__STATIC: + case WOODENHORSE__STATIC: + if (spriteNum >= 0) + pSprite->xrepeat = pSprite->yrepeat = 32; + pSprite->clipdist = 72; + A_Fall(newSprite); + if (spriteNum >= 0) + pSprite->owner = spriteNum; + else pSprite->owner = newSprite; + fallthrough__; + case EGG__STATIC: + if (ud.monsters_off == 1 && pSprite->picnum == EGG) + { + pSprite->xrepeat = pSprite->yrepeat = 0; + changespritestat(newSprite, STAT_MISC); + } + else + { + if (pSprite->picnum == EGG) + pSprite->clipdist = 24; + pSprite->cstat = 257|(krand2()&4); + changespritestat(newSprite, STAT_ZOMBIEACTOR); + } + break; + + case TOILETWATER__STATIC: + pSprite->shade = -16; + changespritestat(newSprite, STAT_STANDABLE); + break; + case RRTILE63__STATICRR: + pSprite->cstat |= 32768; + pSprite->xrepeat = 1; + pSprite->yrepeat = 1; + pSprite->clipdist = 1; + changespritestat(newSprite, 100); + break; + } + +SPAWN_END: + return newSprite; +} + +static int G_MaybeTakeOnFloorPal(tspritetype *pSprite, int sectNum) +{ + int const floorPal = sector[sectNum].floorpal; + + if (floorPal && !lookups.noFloorPal(floorPal) && !A_CheckSpriteFlags(pSprite->owner, SFLAG_NOPAL)) + { + pSprite->pal = floorPal; + return 1; + } + + return 0; +} + +template +static int getofs_viewtype(int angDiff) +{ + return ((((angDiff + 3072) & 2047) * rotations + 1024) >> 11) % rotations; +} + +template +static int viewtype_mirror(uint16_t & cstat, int frameOffset) +{ + if (frameOffset > rotations / 2) + { + cstat |= 4; + return rotations - frameOffset; + } + + cstat &= ~4; + return frameOffset; +} + +template +static int getofs_viewtype_mirrored(uint16_t & cstat, int angDiff) +{ + return viewtype_mirror(cstat, getofs_viewtype(angDiff)); +} + +// XXX: this fucking sucks and needs to be replaced with a SFLAG +static int G_CheckAdultTile(int tileNum) +{ + UNREFERENCED_PARAMETER(tileNum); + switch (tileNum) + { + case FEM1__STATIC: + case FEM2__STATIC: + case FEM3__STATIC: + case FEM4__STATIC: + case FEM5__STATIC: + case FEM6__STATIC: + case FEM7__STATIC: + case FEM8__STATIC: + case FEM9__STATIC: + case MAN__STATIC: + case MAN2__STATIC: + case WOMAN__STATIC: + case PODFEM1__STATIC: + case FEMPIC1__STATIC: + case FEMPIC2__STATIC: + case FEMPIC3__STATIC: + case FEMPIC4__STATIC: + case FEMPIC5__STATIC: + case FEMPIC6__STATIC: + case FEMPIC7__STATIC: + case BLOODYPOLE__STATIC: + case FEM6PAD__STATIC: + case OOZ2__STATIC: + case WALLBLOOD7__STATIC: + case WALLBLOOD8__STATIC: + case FETUS__STATIC: + case FETUSJIB__STATIC: + case FETUSBROKE__STATIC: + case HOTMEAT__STATIC: + case FOODOBJECT16__STATIC: + case TAMPON__STATIC: + case XXXSTACY__STATIC: + case 4946: + case 4947: + case 693: + case 2254: + case 4560: + case 4561: + case 4562: + case 4498: + case 4957: + if (RR) return 0; + return 1; + case FEM10__STATIC: + case NAKED1__STATIC: + case FEMMAG1__STATIC: + case FEMMAG2__STATIC: + case STATUE__STATIC: + case STATUEFLASH__STATIC: + case OOZ__STATIC: + case WALLBLOOD1__STATIC: + case WALLBLOOD2__STATIC: + case WALLBLOOD3__STATIC: + case WALLBLOOD4__STATIC: + case WALLBLOOD5__STATIC: + case SUSHIPLATE1__STATIC: + case SUSHIPLATE2__STATIC: + case SUSHIPLATE3__STATIC: + case SUSHIPLATE4__STATIC: + case DOLPHIN1__STATIC: + case DOLPHIN2__STATIC: + case TOUGHGAL__STATIC: + return 1; + } + return 0; +} + +void G_DoSpriteAnimations(int32_t ourx, int32_t oury, int32_t ourz, int32_t oura, int32_t smoothratio) +{ + UNREFERENCED_PARAMETER(ourz); + int32_t j, frameOffset, playerNum; + intptr_t l; + + if (spritesortcnt == 0) + { +#ifdef DEBUGGINGAIDS + g_spriteStat.numonscreen = 0; +#endif + return; + } +#ifdef LEGACY_ROR + ror_sprite = -1; +#endif + for (j=spritesortcnt-1; j>=0; j--) + { + auto const t = &tsprite[j]; + const int32_t i = t->owner; + auto const s = &sprite[i]; + + switch (DYNAMICTILEMAP(s->picnum)) + { + case SECTOREFFECTOR__STATIC: + if (!RR && (s->lotag == 40 || s->lotag == 41)) + { + t->cstat = 32768; +#ifdef LEGACY_ROR + if (ror_sprite == -1) + ror_sprite = i; +#endif + } + + if (t->lotag == SE_27_DEMO_CAM && ud.recstat == 1) + { + t->picnum = 11+(((int) totalclock>>3)&1); + t->cstat |= 128; + } + else + t->xrepeat = t->yrepeat = 0; + break; + } + } + + for (j=spritesortcnt-1; j>=0; j--) + { + auto const t = &tsprite[j]; + const int32_t i = t->owner; + spritetype *const s = &sprite[i]; + + if (t->picnum < GREENSLIME || t->picnum > GREENSLIME+7) + switch (DYNAMICTILEMAP(t->picnum)) + { + case PIG__STATICRR: + case DOGRUN__STATICRR: + case VIXEN__STATICRR: + case CHEER__STATICRR: + if (DEER) + { + if ((t->cstat & 32768) == 0 && (t->cstat & 257) != 0) + { + if (klabs(ourx - t->x) + klabs(oury - t->y) < 46080) + { + if (klabs(oura - (getangle(t->x - ourx, t->y - oury) & 2047)) < 128) + sub_5A250(32); + else + sub_5A250(64); + } + } + } + goto default_case1; + case PUKE__STATIC: + if (RR) goto default_case1; + fallthrough__; + case BLOODPOOL__STATIC: + case FOOTPRINTS__STATIC: + case FOOTPRINTS2__STATIC: + case FOOTPRINTS3__STATIC: + case FOOTPRINTS4__STATIC: + if (t->shade == 127) continue; + break; + case RESPAWNMARKERRED__STATIC: + case RESPAWNMARKERYELLOW__STATIC: + case RESPAWNMARKERGREEN__STATIC: + if (RR) goto default_case1; + if (ud.marker == 0) + t->xrepeat = t->yrepeat = 0; + continue; + case CHAIR3__STATIC: +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(t->picnum,t->pal) >= 0 && !(spriteext[i].flags&SPREXT_NOTMD)) + { + t->cstat &= ~4; + break; + } +#endif + frameOffset = getofs_viewtype_mirrored<5>(t->cstat, t->ang - oura); + t->picnum = s->picnum+frameOffset; + break; + case BLOODSPLAT1__STATIC: + case BLOODSPLAT2__STATIC: + case BLOODSPLAT3__STATIC: + case BLOODSPLAT4__STATIC: + if (adult_lockout) t->xrepeat = t->yrepeat = 0; + else if (t->pal == 6) + { + t->shade = -127; + continue; + } + fallthrough__; + case BULLETHOLE__STATIC: + case CRACK1__STATIC: + case CRACK2__STATIC: + case CRACK3__STATIC: + case CRACK4__STATIC: + t->shade = 16; + continue; + case NEON1__STATIC: + case NEON2__STATIC: + case NEON3__STATIC: + case NEON4__STATIC: + case NEON5__STATIC: + case NEON6__STATIC: + continue; + case RRTILE1947__STATICRR: + case RRTILE2859__STATICRR: + case RRTILE3774__STATICRR: + case RRTILE5088__STATICRR: + case RRTILE8094__STATICRR: + case RRTILE8096__STATICRR: + if (!RRRA) goto default_case1; + continue; + default: +default_case1: + // NOTE: wall-aligned sprites will never take on ceiling/floor shade... + if ((t->cstat&16) || (A_CheckEnemySprite(t) && + (unsigned)t->owner < MAXSPRITES && sprite[t->owner].extra > 0) || t->statnum == STAT_PLAYER) + { + if (RR && g_shadedSector[s->sectnum] == 1) + { + s->shade = 16; + t->shade = 16; + } + continue; + } + } + + // ... since this is not reached: + if (t->cstat&CSTAT_SPRITE_NOSHADE) + l = sprite[t->owner].shade; + else + { + if (sector[t->sectnum].ceilingstat&1) + { + if (RR) + l = s->shade; + else + l = sector[t->sectnum].ceilingshade; + } + else + l = sector[t->sectnum].floorshade; + + if (l < -127) + l = -127; + } + + t->shade = l; + } + + for (j=spritesortcnt-1; j>=0; j--) //Between drawrooms() and drawmasks() + { + int32_t switchpic; + int32_t curframe; + int32_t scrofs_action; + //is the perfect time to animate sprites + auto const t = &tsprite[j]; + const int32_t i = t->owner; + // XXX: what's up with the (i < 0) check? + // NOTE: not const spritetype because set at SET_SPRITE_NOT_TSPRITE (see below). + EDUKE32_STATIC_ASSERT(sizeof(uspritetype) == sizeof(tspritetype)); // see TSPRITE_SIZE + uspritetype *const pSprite = (i < 0) ? (uspritetype *)&tsprite[j] : (uspritetype *)&sprite[i]; + + if (adult_lockout && G_CheckAdultTile(DYNAMICTILEMAP(pSprite->picnum))) + { + t->xrepeat = t->yrepeat = 0; + continue; + } + + if (!RR && pSprite->picnum == NATURALLIGHTNING) + { + t->shade = -127; + t->clipdist |= TSPR_FLAGS_NO_SHADOW; + } + + if (t->statnum == TSPR_TEMP) + continue; + + Bassert(i >= 0); + + const DukePlayer_t *const ps = (pSprite->statnum != STAT_ACTOR && pSprite->picnum == APLAYER && pSprite->owner >= 0) ? g_player[P_GetP(pSprite)].ps : NULL; + if (ps && ps->newowner == -1) + { + t->x -= mulscale16(65536-smoothratio,ps->pos.x-ps->opos.x); + t->y -= mulscale16(65536-smoothratio,ps->pos.y-ps->opos.y); + t->z = ps->opos.z + mulscale16(smoothratio,ps->pos.z-ps->opos.z) + (40<<8); + + if (RR) + { + pSprite->xrepeat = 24; + pSprite->yrepeat = 17; + } + } + else if ((pSprite->statnum == STAT_DEFAULT && pSprite->picnum != CRANEPOLE) || pSprite->statnum == STAT_PLAYER || + pSprite->statnum == STAT_STANDABLE || pSprite->statnum == STAT_PROJECTILE || pSprite->statnum == STAT_MISC || pSprite->statnum == STAT_ACTOR) + { + t->x -= mulscale16(65536-smoothratio,pSprite->x-actor[i].bpos.x); + t->y -= mulscale16(65536-smoothratio,pSprite->y-actor[i].bpos.y); + t->z -= mulscale16(65536-smoothratio,pSprite->z-actor[i].bpos.z); + } + + const int32_t sect = pSprite->sectnum; + + curframe = AC_CURFRAME(actor[i].t_data); + scrofs_action = AC_ACTION_ID(actor[i].t_data); + switchpic = pSprite->picnum; + // Some special cases because dynamictostatic system can't handle + // addition to constants. + if ((pSprite->picnum >= SCRAP6) && (pSprite->picnum<=SCRAP6+7)) + switchpic = SCRAP5; + else if ((pSprite->picnum==MONEY+1) || (pSprite->picnum==MAIL+1) || (pSprite->picnum==PAPER+1)) + switchpic--; + + switch (DYNAMICTILEMAP(switchpic)) + { + case RESPAWNMARKERRED__STATICRR: + case RESPAWNMARKERYELLOW__STATICRR: + case RESPAWNMARKERGREEN__STATICRR: + if (!RR) goto default_case2; + t->picnum = 861 + (((int32_t) totalclock >> 4) & 13); + if (pSprite->picnum == RESPAWNMARKERRED) + t->pal = 0; + else if (pSprite->picnum == RESPAWNMARKERYELLOW) + t->pal = 1; + else + t->pal = 2; + if (ud.marker == 0) + t->xrepeat = t->yrepeat = 0; + break; + case DUKELYINGDEAD__STATIC: + if (RR) + { + pSprite->x = 24; + pSprite->y = 17; + if (pSprite->extra > 0) + t->z += (6<<8); + } + else + t->z += (24<<8); + break; + case BLOODPOOL__STATIC: + case FOOTPRINTS__STATIC: + case FOOTPRINTS2__STATIC: + case FOOTPRINTS3__STATIC: + case FOOTPRINTS4__STATIC: + if (t->pal == 6) + t->shade = -127; + fallthrough__; + case PUKE__STATIC: + case MONEY__STATIC: + //case MONEY+1__STATIC: + case MAIL__STATIC: + //case MAIL+1__STATIC: + case PAPER__STATIC: + //case PAPER+1__STATIC: + if (RR && (switchpic == PUKE || switchpic == MAIL || switchpic == PAPER)) goto default_case2; + if (adult_lockout && pSprite->pal == 2) + { + t->xrepeat = t->yrepeat = 0; + continue; + } + break; + case TRIPBOMB__STATIC: + if (RR) goto default_case2; + continue; + case TRIPBOMBSPRITE__STATIC: + if (!RR) goto default_case2; + continue; + case FORCESPHERE__STATIC: + if (t->statnum == STAT_MISC) + { + int16_t const sqa = getangle(sprite[pSprite->owner].x - g_player[screenpeek].ps->pos.x, + sprite[pSprite->owner].y - g_player[screenpeek].ps->pos.y); + int16_t const sqb = getangle(sprite[pSprite->owner].x - t->x, sprite[pSprite->owner].y - t->y); + + if (klabs(G_GetAngleDelta(sqa,sqb)) > 512) + if (ldist(&sprite[pSprite->owner],(const spritetype *)t) < ldist(&sprite[g_player[screenpeek].ps->i],&sprite[pSprite->owner])) + t->xrepeat = t->yrepeat = 0; + } + continue; + case BURNING2__STATIC: + if (RR) goto default_case2; + fallthrough__; + case BURNING__STATIC: + if (sprite[pSprite->owner].statnum == STAT_PLAYER) + { + int const playerNum = P_Get(pSprite->owner); + + if (display_mirror == 0 && playerNum == screenpeek && g_player[playerNum].ps->over_shoulder_on == 0) + t->xrepeat = 0; + else + { + t->ang = getangle(ourx - t->x, oury - t->y); + t->x = sprite[pSprite->owner].x + (sintable[(t->ang + 512) & 2047] >> 10); + t->y = sprite[pSprite->owner].y + (sintable[t->ang & 2047] >> 10); + } + } + break; + + case ATOMICHEALTH__STATIC: + t->z -= ZOFFSET6; + break; + case CRYSTALAMMO__STATIC: + t->shade = (sintable[((int32_t) totalclock<<4)&2047]>>10); + if (RR) break; + continue; + case VIEWSCREEN__STATIC: + case VIEWSCREEN2__STATIC: + { + if (RR) goto default_case2; + int const viewscrTile = TILE_VIEWSCR; + + if (g_curViewscreen >= 0 && actor[OW(i)].t_data[0] == 1) + { + t->picnum = STATIC; + t->cstat |= (rand()&12); + t->xrepeat += 10; + t->yrepeat += 9; + } + else if (g_curViewscreen == i && display_mirror != 3) + { + // this exposes a sprite sorting issue which needs to be debugged further... + + t->picnum = viewscrTile; + } + + break; + } + case SHRINKSPARK__STATIC: + if (RR) + { + if (RRRA && (sprite[pSprite->owner].picnum == CHEER || sprite[pSprite->owner].picnum == CHEERSTAYPUT)) + { + t->picnum = CHEERBLADE + (((int32_t) totalclock >> 4) & 3); + t->shade = -127; + } + else + t->picnum = SHRINKSPARK + (((int32_t) totalclock >> 4) & 7); + } + else + t->picnum = SHRINKSPARK+(((int32_t) totalclock>>4)&3); + break; + case CHEERBOMB__STATICRR: + if (!RRRA) goto default_case2; + t->picnum = CHEERBOMB+( ((int32_t) totalclock>>4)&3 ); + break; + case GROWSPARK__STATIC: + if (RR) goto default_case2; + t->picnum = GROWSPARK+(((int32_t) totalclock>>4)&3); + break; + case SPIT__STATIC: + if (!RR) goto default_case2; + t->picnum = SPIT + (((int32_t) totalclock >> 4) & 3); + if (RRRA) + { + if (sprite[pSprite->owner].picnum == MINION && sprite[pSprite->owner].pal == 8) + t->picnum = RRTILE3500 + (((int32_t) totalclock >> 4) % 6); + else if (sprite[pSprite->owner].picnum == MINION && sprite[pSprite->owner].pal == 19) + { + t->picnum = RRTILE5090 + (((int32_t) totalclock >> 4) & 3); + t->shade = -127; + } + else if (sprite[pSprite->owner].picnum == MAMA) + { +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(t->picnum, t->pal) >= 0 && + !(spriteext[i].flags & SPREXT_NOTMD)) + { + int32_t v = getangle(t->xvel, t->zvel >> 4); + + spriteext[i].pitch = (v > 1023 ? v - 2048 : v); + t->cstat &= ~4; + t->picnum = RRTILE7274; + break; + } +#endif + frameOffset = getofs_viewtype_mirrored<5>(t->cstat, pSprite->ang - getangle(pSprite->x-ourx, pSprite->y-oury)); + t->picnum = RRTILE7274 + frameOffset; + } + } + break; + case EMPTYBIKE__STATICRR: + if (!RRRA) goto default_case2; +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(t->picnum, t->pal) >= 0 && !(spriteext[i].flags&SPREXT_NOTMD)) + { + t->cstat &= ~4; + break; + } +#endif + frameOffset = getofs_viewtype_mirrored<7>(t->cstat, pSprite->ang - getangle(pSprite->x - ourx, pSprite->y - oury)); + t->picnum = EMPTYBIKE + frameOffset; + break; + case EMPTYBOAT__STATICRR: + if (!RRRA) goto default_case2; +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(t->picnum, t->pal) >= 0 && !(spriteext[i].flags&SPREXT_NOTMD)) + { + t->cstat &= ~4; + break; + } +#endif + frameOffset = getofs_viewtype_mirrored<7>(t->cstat, pSprite->ang - getangle(pSprite->x - ourx, pSprite->y - oury)); + t->picnum = EMPTYBOAT + frameOffset; + break; + case RPG__STATIC: +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(t->picnum,t->pal) >= 0 && + !(spriteext[i].flags & SPREXT_NOTMD)) + { + int32_t v = getangle(t->xvel, t->zvel>>4); + + spriteext[i].pitch = (v > 1023 ? v-2048 : v); + t->cstat &= ~4; + break; + } +#endif + frameOffset = getofs_viewtype_mirrored<7>(t->cstat, pSprite->ang - getangle(pSprite->x-ourx, pSprite->y-oury)); + t->picnum = RPG+frameOffset; + break; + case RPG2__STATICRR: + if (!RRRA) goto default_case2; +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(t->picnum,t->pal) >= 0 && + !(spriteext[i].flags & SPREXT_NOTMD)) + { + int32_t v = getangle(t->xvel, t->zvel>>4); + + spriteext[i].pitch = (v > 1023 ? v-2048 : v); + t->cstat &= ~4; + break; + } +#endif + frameOffset = getofs_viewtype_mirrored<7>(t->cstat, pSprite->ang - getangle(pSprite->x-ourx, pSprite->y-oury)); + t->picnum = RPG2+frameOffset; + break; + + case RECON__STATIC: +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(t->picnum,t->pal) >= 0 && !(spriteext[i].flags&SPREXT_NOTMD)) + { + t->cstat &= ~4; + break; + } +#endif + frameOffset = getofs_viewtype_mirrored<7>(t->cstat, pSprite->ang - getangle(pSprite->x-ourx, pSprite->y-oury)); + + // RECON_T4 + if (klabs(curframe) > 64) + frameOffset += 7; // tilted recon car + + t->picnum = RECON+frameOffset; + + break; + case APLAYER__STATIC: + playerNum = P_GetP(pSprite); + + if (t->pal == 1) t->z -= (18<<8); + + if (g_player[playerNum].ps->over_shoulder_on > 0 && g_player[playerNum].ps->newowner < 0) + { + t->ang = fix16_to_int( + g_player[playerNum].ps->q16ang + + mulscale16((((g_player[playerNum].ps->q16ang + 1024 - g_player[playerNum].ps->oq16ang) & 2047) - 1024), smoothratio)); +#ifdef USE_OPENGL + if (bpp > 8 && hw_models && md_tilehasmodel(t->picnum, t->pal) >= 0) + { + static int32_t targetang = 0; + + if (g_player[playerNum].input->extbits&(1<<1)) + { + if (g_player[playerNum].input->extbits&(1<<2))targetang += 16; + else if (g_player[playerNum].input->extbits&(1<<3)) targetang -= 16; + else if (targetang > 0) targetang -= targetang>>2; + else if (targetang < 0) targetang += (-targetang)>>2; + } + else + { + if (g_player[playerNum].input->extbits&(1<<2))targetang -= 16; + else if (g_player[playerNum].input->extbits&(1<<3)) targetang += 16; + else if (targetang > 0) targetang -= targetang>>2; + else if (targetang < 0) targetang += (-targetang)>>2; + } + + targetang = clamp(targetang, -128, 128); + t->ang += targetang; + } + else +#endif + t->cstat |= 2; + if (screenpeek == myconnectindex && numplayers >= 2) + { + t->x = omypos.x+mulscale16(mypos.x-omypos.x,smoothratio); + t->y = omypos.y+mulscale16(mypos.y-omypos.y,smoothratio); + t->z = omypos.z+mulscale16(mypos.z-omypos.z,smoothratio)+(40<<8); + t->ang = fix16_to_int(omyang+mulscale16((fix16_to_int(myang+F16(1024)-omyang)&2047)-1024,smoothratio)); + t->sectnum = mycursectnum; + } + + } + + if ((g_netServer || ud.multimode > 1) && (display_mirror || screenpeek != playerNum || pSprite->owner == -1)) + { + if (ud.showweapons && sprite[g_player[playerNum].ps->i].extra > 0 && g_player[playerNum].ps->curr_weapon > 0 + && spritesortcnt < maxspritesonscreen) + { + tspritetype *const newTspr = &tsprite[spritesortcnt]; + int const currentWeapon = g_player[playerNum].ps->curr_weapon; + + *newTspr = *t; + newTspr->statnum = TSPR_TEMP; + newTspr->cstat = 0; + newTspr->pal = 0; + newTspr->picnum = (currentWeapon == GROW_WEAPON ? GROWSPRITEICON : WeaponPickupSprites[currentWeapon]); + if (RR) + { + newTspr->picnum = 0; + switch(DYNAMICWEAPONMAP(g_player[playerNum].ps->curr_weapon)) + { + case PISTOL_WEAPON__STATIC: newTspr->picnum = FIRSTGUNSPRITE; break; + case SHOTGUN_WEAPON__STATIC: newTspr->picnum = SHOTGUNSPRITE; break; + case CHAINGUN_WEAPON__STATIC: newTspr->picnum = CHAINGUNSPRITE; break; + case RPG_WEAPON__STATIC: newTspr->picnum = RPGSPRITE; break; + case CHICKEN_WEAPON__STATIC: newTspr->picnum = RPGSPRITE; break; + case HANDREMOTE_WEAPON__STATIC: + case HANDBOMB_WEAPON__STATIC: newTspr->picnum = HEAVYHBOMB; break; + case TRIPBOMB_WEAPON__STATIC: newTspr->picnum = TRIPBOMBSPRITE; break; + case BOWLINGBALL_WEAPON__STATIC: newTspr->picnum = BOWLINGBALLSPRITE; break; + case SHRINKER_WEAPON__STATIC: newTspr->picnum = SHRINKSPARK; break; + case GROW_WEAPON__STATIC: newTspr->picnum = SHRINKSPARK; break; + case FREEZE_WEAPON__STATIC: newTspr->picnum = DEVISTATORSPRITE; break; + case DEVISTATOR_WEAPON__STATIC: newTspr->picnum = FREEZESPRITE; break; + } + } + newTspr->z = (pSprite->owner >= 0) ? g_player[playerNum].ps->pos.z - ZOFFSET4 : pSprite->z - (51 << 8); + newTspr->xrepeat = (newTspr->picnum == HEAVYHBOMB) ? 10 : 16; + if (RRRA && (g_player[playerNum].ps->on_motorcycle || g_player[playerNum].ps->on_boat)) + newTspr->xrepeat = 0; + newTspr->yrepeat = newTspr->xrepeat; + + spritesortcnt++; + } + + if (g_player[playerNum].input->extbits & (1 << 7) && !paused && spritesortcnt < maxspritesonscreen) + { + tspritetype *const playerTyping = t; + + playerTyping->statnum = TSPR_TEMP; + playerTyping->cstat = 0; + playerTyping->picnum = RESPAWNMARKERGREEN; + playerTyping->z = (pSprite->owner >= 0) ? (g_player[playerNum].ps->pos.z - (20 << 8)) : (pSprite->z - (96 << 8)); + playerTyping->xrepeat = 32; + playerTyping->yrepeat = 32; + playerTyping->pal = 20; + + spritesortcnt++; + } + } + + if (pSprite->owner == -1) + { +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(pSprite->picnum,t->pal) >= 0 && !(spriteext[i].flags&SPREXT_NOTMD)) + { + frameOffset = 0; + t->cstat &= ~4; + } + else +#endif + frameOffset = getofs_viewtype_mirrored<5>(t->cstat, pSprite->ang - oura); + + if (sector[pSprite->sectnum].lotag == ST_2_UNDERWATER) frameOffset += 1795-1405; + else if ((actor[i].floorz-pSprite->z) > (64<<8)) frameOffset += 60; + + t->picnum += frameOffset; + t->pal = g_player[playerNum].ps->palookup; + + goto PALONLY; + } + + if (g_player[playerNum].ps->on_crane == -1 && (sector[pSprite->sectnum].lotag&0x7ff) != 1) // ST_1_ABOVE_WATER ? + { + l = pSprite->z-actor[g_player[playerNum].ps->i].floorz+(3<<8); + // SET_SPRITE_NOT_TSPRITE + if (l > 1024 && pSprite->yrepeat > 32 && pSprite->extra > 0) + pSprite->yoffset = (int8_t)tabledivide32_noinline(l, pSprite->yrepeat<<2); + else pSprite->yoffset=0; + } + + if (g_player[playerNum].ps->newowner > -1) + { + // Display APLAYER sprites with action PSTAND when viewed through + // a camera. + const intptr_t *aplayer_scr = g_tile[APLAYER].execPtr; + // [0]=strength, [1]=actionofs, [2]=moveofs + + scrofs_action = aplayer_scr[1]; + curframe = 0; + } + + if (ud.camerasprite == -1 && g_player[playerNum].ps->newowner == -1) + { + if (pSprite->owner >= 0 && display_mirror == 0 && g_player[playerNum].ps->over_shoulder_on == 0) + { + if ((!g_netServer && ud.multimode < 2) || ((g_netServer || ud.multimode > 1) && playerNum == screenpeek)) + { + if (videoGetRenderMode() == REND_POLYMER) + t->clipdist |= TSPR_FLAGS_INVISIBLE_WITH_SHADOW; + else + { + t->owner = -1; + t->xrepeat = t->yrepeat = 0; + continue; + } + +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(pSprite->picnum, t->pal) >= 0 && !(spriteext[i].flags&SPREXT_NOTMD)) + { + frameOffset = 0; + t->cstat &= ~4; + } + else +#endif + frameOffset = getofs_viewtype_mirrored<5>(t->cstat, pSprite->ang - oura); + + if (sector[t->sectnum].lotag == ST_2_UNDERWATER) frameOffset += 1795-1405; + else if ((actor[i].floorz-pSprite->z) > (64<<8)) frameOffset += 60; + + t->picnum += frameOffset; + t->pal = g_player[playerNum].ps->palookup; + } + } + } +PALONLY: + G_MaybeTakeOnFloorPal(t, sect); + + if (pSprite->owner == -1) continue; + + if (t->z > actor[i].floorz && t->xrepeat < 32) + t->z = actor[i].floorz; + + if (RRRA) + { + if (g_player[playerNum].ps->on_motorcycle && playerNum == screenpeek) + { + t->picnum = RRTILE7219; + t->xrepeat = 18; + t->yrepeat = 18; + scrofs_action = 0; + curframe = 0; + } + else if (g_player[playerNum].ps->on_motorcycle) + { + t->xrepeat = 18; + t->yrepeat = 18; + scrofs_action = 0; + curframe = 0; +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(pSprite->picnum, t->pal) >= 0 && !(spriteext[i].flags&SPREXT_NOTMD)) + { + frameOffset = 0; + t->cstat &= ~4; + t->picnum = RRTILE7213; + } + else +#endif + frameOffset = getofs_viewtype_mirrored<7>(t->cstat, pSprite->ang - oura); + + t->picnum = RRTILE7213 + frameOffset; + } + else if (g_player[playerNum].ps->on_boat && playerNum == screenpeek) + { + t->picnum = RRTILE7190; + t->xrepeat = 32; + t->yrepeat = 32; + scrofs_action = 0; + curframe = 0; + } + else if (g_player[playerNum].ps->on_boat) + { + t->xrepeat = 32; + t->yrepeat = 32; + scrofs_action = 0; + curframe = 0; +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(pSprite->picnum, t->pal) >= 0 && !(spriteext[i].flags&SPREXT_NOTMD)) + { + frameOffset = 0; + t->cstat &= ~4; + t->picnum = RRTILE7213; + } + else +#endif + frameOffset = getofs_viewtype_mirrored<7>(t->cstat, pSprite->ang - oura); + + t->picnum = RRTILE7184 + frameOffset; + } + } + + break; + case RRTILE2460__STATICRR: + case RRTILE2465__STATICRR: + case BIKEJIBA__STATICRR: + case BIKEJIBB__STATICRR: + case BIKEJIBC__STATICRR: + case BIKERJIBA__STATICRR: + case BIKERJIBB__STATICRR: + case BIKERJIBC__STATICRR: + case BIKERJIBD__STATICRR: + case CHEERJIBA__STATICRR: + case CHEERJIBB__STATICRR: + case CHEERJIBC__STATICRR: + case CHEERJIBD__STATICRR: + case FBOATJIBA__STATICRR: + case FBOATJIBB__STATICRR: + case RABBITJIBA__STATICRR: + case RABBITJIBB__STATICRR: + case RABBITJIBC__STATICRR: + case MAMAJIBA__STATICRR: + case MAMAJIBB__STATICRR: + if (!RRRA) goto default_case2; + fallthrough__; + case MINJIBA__STATICRR: + case MINJIBB__STATICRR: + case MINJIBC__STATICRR: + case JIBS1__STATIC: + case JIBS2__STATIC: + case JIBS3__STATIC: + case JIBS4__STATIC: + case JIBS5__STATIC: + case JIBS6__STATIC: + case HEADJIB1__STATIC: + case LEGJIB1__STATIC: + case ARMJIB1__STATIC: + case LIZMANHEAD1__STATIC: + case LIZMANARM1__STATIC: + case LIZMANLEG1__STATIC: + case DUKELEG__STATIC: + case DUKEGUN__STATIC: + case DUKETORSO__STATIC: + case BILLYJIBA__STATICRR: + case BILLYJIBB__STATICRR: + case HULKJIBA__STATICRR: + case HULKJIBB__STATICRR: + case HULKJIBC__STATICRR: + case COOTJIBA__STATICRR: + case COOTJIBB__STATICRR: + case COOTJIBC__STATICRR: + if (RR) + { + if (switchpic == HEADJIB1 || switchpic == LEGJIB1 || switchpic == ARMJIB1 + || switchpic == LIZMANHEAD1 || switchpic == LIZMANARM1 || switchpic == LIZMANLEG1) + goto default_case2; + } + if (RRRA && t->pal == 19 && (switchpic == MINJIBA || switchpic == MINJIBB || switchpic == MINJIBC)) + t->shade = -127; + if (adult_lockout) + { + t->xrepeat = t->yrepeat = 0; + continue; + } + if (t->pal == 6) + t->shade = -120; + if (RR && g_shadedSector[pSprite->sectnum] == 1) + t->shade = 16; + fallthrough__; + case SCRAP1__STATIC: + case SCRAP2__STATIC: + case SCRAP3__STATIC: + case SCRAP4__STATIC: + case SCRAP5__STATIC: + if ((RR || actor[i].picnum == BLIMP) && t->picnum == SCRAP1 && pSprite->yvel >= 0) + t->picnum = pSprite->yvel < MAXUSERTILES ? pSprite->yvel : 0; + else t->picnum += T1(i); + if (!RR) + t->shade = -128+6 < t->shade ? t->shade-6 : -128; // effectively max(t->shade-6, -128) while avoiding (signed!) underflow + + G_MaybeTakeOnFloorPal(t, sect); + break; + case WATERBUBBLE__STATIC: + if (sector[t->sectnum].floorpicnum == FLOORSLIME) + { + t->pal = 7; + break; + } + fallthrough__; + default: +default_case2: + G_MaybeTakeOnFloorPal(t, sect); + break; + } + + if (G_HaveActor(pSprite->picnum) && scrofs_action != 0 && (!RR || (t->cstat & 48) != 48)) + { + if ((unsigned)scrofs_action + ACTION_VIEWTYPE >= (unsigned)g_scriptSize) + goto skip; + + l = apScript[scrofs_action + ACTION_VIEWTYPE]; + uint16_t const action_flags = apScript[scrofs_action + ACTION_FLAGS]; + + int const invertp = l < 0; + l = klabs(l); + +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(pSprite->picnum,t->pal) >= 0 && !(spriteext[i].flags&SPREXT_NOTMD)) + { + frameOffset = 0; + t->cstat &= ~4; + } + else +#endif + { + int const viewAng = ((l > 4 && l != 8) || action_flags & AF_VIEWPOINT) ? getangle(pSprite->x-ourx, pSprite->y-oury) : oura; + int const angDiff = invertp ? viewAng - pSprite->ang : pSprite->ang - viewAng; + + switch (l) + { + case 2: + frameOffset = getofs_viewtype<8>(angDiff) & 1; + break; + + case 3: + case 4: + frameOffset = viewtype_mirror<7>(t->cstat, getofs_viewtype<16>(angDiff) & 7); + break; + + case 5: + frameOffset = getofs_viewtype_mirrored<5>(t->cstat, angDiff); + break; + case 7: + frameOffset = getofs_viewtype_mirrored<7>(t->cstat, angDiff); + break; + case 8: + frameOffset = getofs_viewtype<8>(angDiff); + t->cstat &= ~4; + break; + /*case 9: + frameOffset = getofs_viewtype_mirrored<9>(t->cstat, angDiff); + break; + case 12: + frameOffset = getofs_viewtype<12>(angDiff); + t->cstat &= ~4; + break; + case 16: + frameOffset = getofs_viewtype<16>(angDiff); + t->cstat &= ~4; + break;*/ + default: + if (RR) + { + if (A_CheckEnemySprite(pSprite) && pSprite->statnum == STAT_ZOMBIEACTOR && pSprite->extra > 0) + { + int const angDiff = pSprite->ang-getangle(pSprite->x-ourx, pSprite->y-oury); + frameOffset = getofs_viewtype_mirrored<5>(t->cstat, angDiff); + break; + } + } + frameOffset = 0; + break; + } + } + + t->picnum += frameOffset + apScript[scrofs_action + ACTION_STARTFRAME] + l*curframe; + // XXX: t->picnum can be out-of-bounds by bad user code. + + if (l > 0) + while (tilesiz[t->picnum].x == 0 && t->picnum > 0) + t->picnum -= l; //Hack, for actors + + if (actor[i].dispicnum >= 0) + actor[i].dispicnum = t->picnum; + } +// else if (display_mirror == 1) +// t->cstat |= 4; + /* completemirror() already reverses the drawn frame, so the above isn't necessary. + * Even Polymost's and Polymer's mirror seems to function correctly this way. */ + +skip: + // Night vision goggles tsprite tinting. + // XXX: Currently, for the splitscreen mod, sprites will be pal6-colored iff the first + // player has nightvision on. We should pass stuff like "from which player is this view + // supposed to be" as parameters ("drawing context") instead of relying on globals. + if (!RR && g_player[screenpeek].ps->inv_amount[GET_HEATS] > 0 && g_player[screenpeek].ps->heat_on && + (A_CheckEnemySprite(pSprite) || A_CheckSpriteFlags(t->owner,SFLAG_NVG) || pSprite->picnum == APLAYER || pSprite->statnum == STAT_DUMMYPLAYER)) + { + t->pal = 6; + t->shade = 0; + } + + if (RR && !RRRA && pSprite->picnum == SBMOVE) + t->shade = -127; + + // Fake floor shadow, implemented by inserting a new tsprite. + if (pSprite->statnum == STAT_DUMMYPLAYER || A_CheckEnemySprite(pSprite) || A_CheckSpriteFlags(t->owner,SFLAG_SHADOW) || (pSprite->picnum == APLAYER && pSprite->owner >= 0)) + if ((!RR || (pSprite->cstat&48) == 0) && t->statnum != TSPR_TEMP && pSprite->picnum != EXPLOSION2 && (RR || pSprite->picnum != HANGLIGHT) && pSprite->picnum != DOMELITE && (RR || pSprite->picnum != HOTMEAT) + && (!RR || pSprite->picnum != TORNADO) && (!RR || pSprite->picnum != EXPLOSION3) && (!RR || RRRA || pSprite->picnum != SBMOVE)) + { + if (actor[i].dispicnum < 0) + { +#ifdef DEBUGGINGAIDS + // A negative actor[i].dispicnum used to mean 'no floor shadow please', but + // that was a bad hack since the value could propagate to sprite[].picnum. + Printf(TEXTCOLOR_RED "actor[%d].dispicnum = %d\n", i, actor[i].dispicnum); +#endif + actor[i].dispicnum=0; + continue; + } + + if (actor[i].flags & SFLAG_NOFLOORSHADOW) + continue; + + if (r_shadows && spritesortcnt < (maxspritesonscreen-2) +#ifdef POLYMER + && !(videoGetRenderMode() == REND_POLYMER && pr_lighting != 0) +#endif + ) + { + if (DEER && klabs(sector[sect].ceilingheinum - sector[sect].floorheinum) > 576) continue; + if (RRRA && sector[sect].lotag == 160) continue; + int const shadowZ = (DEER || (sector[sect].lotag & 0xff) > 2 || pSprite->statnum == STAT_PROJECTILE || + pSprite->statnum == STAT_MISC || pSprite->picnum == DRONE || (!RR && pSprite->picnum == COMMANDER)) + ? sector[sect].floorz + : actor[i].floorz; + + if ((pSprite->z-shadowZ) < ZOFFSET3 && g_player[screenpeek].ps->pos.z < shadowZ) + { + tspritetype *const tsprShadow = &tsprite[spritesortcnt]; + + *tsprShadow = *t; + tsprShadow->statnum = TSPR_TEMP; + tsprShadow->yrepeat = (t->yrepeat >> 3); + + if (t->yrepeat < 4) + t->yrepeat = 4; + + tsprShadow->shade = 127; + tsprShadow->cstat |= 2; + tsprShadow->z = shadowZ; + tsprShadow->pal = ud.shadow_pal; + + +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST) + { + if (hw_models && md_tilehasmodel(t->picnum,t->pal) >= 0) + { + tsprShadow->yrepeat = 0; + // 512:trans reverse + //1024:tell MD2SPRITE.C to use Z-buffer hacks to hide overdraw issues + tsprShadow->clipdist |= TSPR_FLAGS_MDHACK; + tsprShadow->cstat |= 512; + } + else + { + int const ii + = getangle(tsprShadow->x - g_player[screenpeek].ps->pos.x, tsprShadow->y - g_player[screenpeek].ps->pos.y); + + tsprShadow->x += sintable[(ii+2560)&2047]>>9; + tsprShadow->y += sintable[(ii+2048)&2047]>>9; + } + } +#endif + spritesortcnt++; + } + } + } + + if (DEER) + { + if (pSprite->picnum == 806) + t->picnum = 1023; + } + else switch (DYNAMICTILEMAP(pSprite->picnum)) + { + case LASERLINE__STATIC: + if (RR) break; + if (sector[t->sectnum].lotag == ST_2_UNDERWATER) t->pal = 8; + t->z = sprite[pSprite->owner].z-(3<<8); + if (g_tripbombLaserMode == 2 && g_player[screenpeek].ps->heat_on == 0) + t->yrepeat = 0; + fallthrough__; + case EXPLOSION2BOT__STATIC: + case GROWSPARK__STATIC: + case SHRINKEREXPLOSION__STATIC: + case FLOORFLAME__STATIC: + if (RR) break; + fallthrough__; + case FREEZEBLAST__STATIC: + case ATOMICHEALTH__STATIC: + case FIRELASER__STATIC: + case SHRINKSPARK__STATIC: + case CHAINGUN__STATIC: + case RPG__STATIC: + case EXPLOSION2__STATIC: + case EXPLOSION3__STATICRR: + case OWHIP__STATICRR: + case UWHIP__STATICRR: + case RPG2__STATICRR: + case RRTILE1790__STATICRR: +rrcoolexplosion1: + if (RR && !RRRA && (pSprite->picnum == RPG2 || pSprite->picnum == RRTILE1790)) break; + if (t->picnum == EXPLOSION2) + { + g_player[screenpeek].ps->visibility = -127; + //g_restorePalette = 1; // JBF 20040101: why? + if (RR) + t->pal = 0; + } + else if (RR && t->picnum == FIRELASER) + t->picnum = FIRELASER+(((int32_t) totalclock>>2)&5); + t->shade = -127; + t->clipdist |= TSPR_FLAGS_DRAW_LAST | TSPR_FLAGS_NO_SHADOW; + break; + case UFOBEAM__STATICRR: + case RRTILE3586__STATICRR: + case RRTILE3587__STATICRR: + t->cstat |= 32768; + pSprite->cstat |= 32768; + break; + case DESTRUCTO__STATICRR: + t->cstat |= 32768; + break; + case FIRE__STATIC: + case FIRE2__STATIC: + if (RR && pSprite->picnum == FIRE2) break; + t->cstat |= 128; + fallthrough__; + case BURNING__STATIC: + case BURNING2__STATIC: + if (RR && pSprite->picnum == BURNING2) break; + if (sprite[pSprite->owner].picnum != TREE1 && sprite[pSprite->owner].picnum != TREE2) + t->z = sector[t->sectnum].floorz; + t->shade = -127; + fallthrough__; + case SMALLSMOKE__STATIC: + if (RR) break; + t->clipdist |= TSPR_FLAGS_DRAW_LAST | TSPR_FLAGS_NO_SHADOW; + break; + case COOLEXPLOSION1__STATIC: + if (RR) goto rrcoolexplosion1; + t->shade = -127; + t->clipdist |= TSPR_FLAGS_DRAW_LAST | TSPR_FLAGS_NO_SHADOW; + t->picnum += (pSprite->shade>>1); + break; + case WALLLIGHT3__STATIC: + case WALLLIGHT1__STATIC: + if (!RR) break; + fallthrough__; + case RRTILE3668__STATICRR: + case RRTILE3795__STATICRR: + case RRTILE5035__STATICRR: + case RRTILE7505__STATICRR: + case RRTILE7506__STATICRR: + case RRTILE7533__STATICRR: + case RRTILE8216__STATICRR: + case RRTILE8218__STATICRR: + case RRTILE8220__STATICRR: + if (!RRRA) break; + fallthrough__; + case RRTILE1878__STATICRR: + case RRTILE1952__STATICRR: + case RRTILE1953__STATICRR: + case RRTILE1990__STATICRR: + case RRTILE2050__STATICRR: + case RRTILE2056__STATICRR: + case RRTILE2072__STATICRR: + case RRTILE2075__STATICRR: + case RRTILE2083__STATICRR: + case RRTILE2097__STATICRR: + case RRTILE2156__STATICRR: + case RRTILE2157__STATICRR: + case RRTILE2158__STATICRR: + case RRTILE2159__STATICRR: + case RRTILE2160__STATICRR: + case RRTILE2161__STATICRR: + case RRTILE2175__STATICRR: + case RRTILE2176__STATICRR: + case RRTILE2357__STATICRR: + case RRTILE2564__STATICRR: + case RRTILE2573__STATICRR: + case RRTILE2574__STATICRR: + case RRTILE2583__STATICRR: + case RRTILE2604__STATICRR: + case RRTILE2689__STATICRR: + case RRTILE2893__STATICRR: + case RRTILE2894__STATICRR: + case RRTILE2915__STATICRR: + case RRTILE2945__STATICRR: + case RRTILE2946__STATICRR: + case RRTILE2947__STATICRR: + case RRTILE2948__STATICRR: + case RRTILE2949__STATICRR: + case RRTILE2977__STATICRR: + case RRTILE2978__STATICRR: + case RRTILE3116__STATICRR: + case RRTILE3171__STATICRR: + case RRTILE3216__STATICRR: + case RRTILE3720__STATICRR: + t->shade = -127; + break; + case CHEER__STATICRR: + if (!RRRA) break; + if (t->picnum >= CHEER + 102 && t->picnum <= CHEER + 151) + t->shade = -127; + break; + case MINION__STATICRR: + if (!RRRA) break; + if (t->pal == 19) + t->shade = -127; + break; + case BIKER__STATICRR: + if (!RRRA) break; + if (t->picnum >= BIKER + 54 && t->picnum <= BIKER + 58) + t->shade = -127; + else if (t->picnum >= BIKER + 84 && t->picnum <= BIKER + 88) + t->shade = -127; + break; + case BILLYRAY__STATICRR: + case BILLYRAYSTAYPUT__STATICRR: + if (!RRRA) break; + if (t->picnum >= BILLYRAY + 5 && t->picnum <= BILLYRAY + 9) + t->shade = -127; + break; + case RRTILE2034__STATICRR: + t->picnum = RRTILE2034 + ((int32_t) totalclock & 1); + break; + case RRTILE2944__STATICRR: + t->shade = -127; + t->picnum = RRTILE2944 + (((int32_t) totalclock >> 2) & 4); + break; + case PLAYERONWATER__STATIC: +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(pSprite->picnum,pSprite->pal) >= 0 && !(spriteext[i].flags&SPREXT_NOTMD)) + { + frameOffset = 0; + t->cstat &= ~4; + } + else +#endif + frameOffset = getofs_viewtype_mirrored<5>(t->cstat, t->ang - oura); + + t->picnum = pSprite->picnum+frameOffset+((T1(i)<4)*5); + t->shade = sprite[pSprite->owner].shade; + + break; + + case MUD__STATICRR: + t->picnum = MUD+T2(i); + break; + case WATERSPLASH2__STATIC: + // WATERSPLASH_T2 + t->picnum = WATERSPLASH2+T2(i); + break; + case SHELL__STATIC: + t->picnum = pSprite->picnum+(T1(i)&1); + fallthrough__; + case SHOTGUNSHELL__STATIC: + t->cstat |= 12; + if (T1(i) > 2) t->cstat &= ~16; + else if (T1(i) > 1) t->cstat &= ~4; + break; + case FRAMEEFFECT1__STATIC: + if (pSprite->owner >= 0 && sprite[pSprite->owner].statnum < MAXSTATUS) + { + if (sprite[pSprite->owner].picnum == APLAYER) + if (ud.camerasprite == -1) + if (screenpeek == P_Get(pSprite->owner) && display_mirror == 0) + { + t->owner = -1; + break; + } + if ((sprite[pSprite->owner].cstat&32768) == 0) + { + if (!actor[pSprite->owner].dispicnum) + t->picnum = actor[i].t_data[1]; + else t->picnum = actor[pSprite->owner].dispicnum; + + if (RR && sprite[pSprite->owner].picnum == APLAYER) + t->picnum = SMALLSMOKE; + + if (!G_MaybeTakeOnFloorPal(t, sect)) + t->pal = sprite[pSprite->owner].pal; + + t->shade = sprite[pSprite->owner].shade; + t->ang = sprite[pSprite->owner].ang; + t->cstat = 2|sprite[pSprite->owner].cstat; + } + } + break; + + case CAMERA1__STATIC: + case RAT__STATIC: +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(pSprite->picnum,pSprite->pal) >= 0 && !(spriteext[i].flags&SPREXT_NOTMD)) + { + t->cstat &= ~4; + break; + } +#endif + frameOffset = getofs_viewtype_mirrored<5>(t->cstat, t->ang - oura); + t->picnum = pSprite->picnum+frameOffset; + break; + } + + actor[i].dispicnum = t->picnum; +#if 0 + // why? + if (sector[t->sectnum].floorpicnum == MIRROR) + t->xrepeat = t->yrepeat = 0; +#endif + } + +#ifdef DEBUGGINGAIDS + g_spriteStat.numonscreen = spritesortcnt; +#endif +} + +void G_InitTimer(int32_t ticspersec) +{ + if (g_timerTicsPerSecond != ticspersec) + { + timerUninit(); + timerInit(ticspersec); + g_timerTicsPerSecond = ticspersec; + } +} + + +static int32_t g_RTSPlaying; + +// Returns: started playing? +int G_StartRTS(int lumpNum, int localPlayer) +{ + if (!adult_lockout && SoundEnabled() && + RTS_IsInitialized() && g_RTSPlaying == 0 && (snd_speech & (localPlayer ? 1 : 4))) + { + auto sid = RTS_GetSoundID(lumpNum - 1); + if (sid != -1) + { + S_PlaySound(sid, CHAN_AUTO, CHANF_UI); + g_RTSPlaying = 7; + return 1; + } + } + + return 0; +} + +// Trying to sanitize the mess of options and the mess of variables the mess was stored in. (Did I say this was a total mess before...? >) ) +// Hopefully this is more comprehensible, at least it neatly stores everything useful in a single linear value... +bool GameInterface::validate_hud(int layout) +{ + if (layout <= (RR? 5: 6)) // Status bar with border + { + return !(ud.statusbarflags & STATUSBAR_NOSHRINK); + } + else if (layout <= 7) // Status bar fullscreen + { + return (!(ud.statusbarflags & STATUSBAR_NOFULL) || !(ud.statusbarflags & STATUSBAR_NOOVERLAY)); + } + else if (layout == 8) // Status bar overlay + { + return !(ud.statusbarflags & STATUSBAR_NOOVERLAY); + } + else if (layout == 9) // Fullscreen HUD + { + return (!(ud.statusbarflags & STATUSBAR_NOMINI) || !(ud.statusbarflags & STATUSBAR_NOMODERN)); + } + else if (layout == 10) + { + return !(ud.statusbarflags & STATUSBAR_NOMODERN); + } + else if (layout == 11) + { + return !(ud.statusbarflags & STATUSBAR_NONONE); + } + return false; +} + +void GameInterface::set_hud_layout(int layout) +{ + static const uint8_t screen_size_vals[] = { 60, 54, 48, 40, 32, 24, 16, 8, 8, 4, 4, 0 }; + static const uint8_t screen_size_vals_rr[] = { 56, 48, 40, 32, 24, 16, 12, 8, 8, 4, 4, 0 }; + if (validate_hud(layout)) + { + ud.screen_size = RR? screen_size_vals_rr[layout] : screen_size_vals[layout]; + ud.statusbarmode = layout >= 8; + ud.althud = layout >= 10; + G_UpdateScreenArea(); + } +} + +void GameInterface::set_hud_scale(int scale) +{ + ud.statusbarscale = clamp(scale, 36, 100); + G_UpdateScreenArea(); +} + +void G_HandleLocalKeys(void) +{ +// CONTROL_ProcessBinds(); + + if (DEER) + { + sub_53304(); + return; + } + + if (ud.recstat == 2) + { + ControlInfo noshareinfo; + CONTROL_GetInput(&noshareinfo); + } + + if (g_player[myconnectindex].gotvote == 0 && voting != -1 && voting != myconnectindex) + { + if (inputState.UnboundKeyPressed(sc_F1) || inputState.UnboundKeyPressed(sc_F2) || cl_autovote) + { + G_AddUserQuote(GStrings("VoteCast")); + Net_SendMapVote(inputState.UnboundKeyPressed(sc_F1) || cl_autovote ? cl_autovote-1 : 0); + inputState.ClearKeyStatus(sc_F1); + inputState.ClearKeyStatus(sc_F2); + } + } + + if (!ALT_IS_PRESSED && ud.overhead_on == 0 && (g_player[myconnectindex].ps->gm & MODE_TYPE) == 0) + { + if (buttonMap.ButtonDown(gamefunc_Enlarge_Screen)) + { + buttonMap.ClearButton(gamefunc_Enlarge_Screen); + + if (!SHIFTS_IS_PRESSED) + { + if (G_ChangeHudLayout(1)) + { + S_PlaySound(RR ? 341 : THUD, CHAN_AUTO, CHANF_UI); + } + } + else + { + hud_scale = hud_scale + 4; + } + + G_UpdateScreenArea(); + } + + if (buttonMap.ButtonDown(gamefunc_Shrink_Screen)) + { + buttonMap.ClearButton(gamefunc_Shrink_Screen); + + if (!SHIFTS_IS_PRESSED) + { + if (G_ChangeHudLayout(-1)) + { + S_PlaySound(RR ? 341 : THUD, CHAN_AUTO, CHANF_UI); + } + } + else + { + hud_scale = hud_scale - 4; + } + + G_UpdateScreenArea(); + } + } + + if (g_player[myconnectindex].ps->cheat_phase == 1 || (g_player[myconnectindex].ps->gm&(MODE_MENU|MODE_TYPE)) || System_WantGuiCapture()) + return; + + if (buttonMap.ButtonDown(gamefunc_See_Coop_View) && (GTFLAGS(GAMETYPE_COOPVIEW) || ud.recstat == 2)) + { + buttonMap.ClearButton(gamefunc_See_Coop_View); + screenpeek = connectpoint2[screenpeek]; + if (screenpeek == -1) screenpeek = 0; + g_restorePalette = -1; + } + + if ((g_netServer || ud.multimode > 1) && buttonMap.ButtonDown(gamefunc_Show_Opponents_Weapon)) + { + buttonMap.ClearButton(gamefunc_Show_Opponents_Weapon); + ud.config.ShowOpponentWeapons = ud.showweapons = 1-ud.showweapons; + P_DoQuote(QUOTE_WEAPON_MODE_OFF-ud.showweapons,g_player[screenpeek].ps); + } + + if (buttonMap.ButtonDown(gamefunc_Toggle_Crosshair)) + { + buttonMap.ClearButton(gamefunc_Toggle_Crosshair); + cl_crosshair = !cl_crosshair; + P_DoQuote(QUOTE_CROSSHAIR_OFF-cl_crosshair,g_player[screenpeek].ps); + } + + if (ud.overhead_on && buttonMap.ButtonDown(gamefunc_Map_Follow_Mode)) + { + buttonMap.ClearButton(gamefunc_Map_Follow_Mode); + ud.scrollmode = 1-ud.scrollmode; + if (ud.scrollmode) + { + ud.folx = g_player[screenpeek].ps->opos.x; + ud.foly = g_player[screenpeek].ps->opos.y; + ud.fola = fix16_to_int(g_player[screenpeek].ps->oq16ang); + } + P_DoQuote(QUOTE_MAP_FOLLOW_OFF+ud.scrollmode,g_player[myconnectindex].ps); + } + + if (inputState.UnboundKeyPressed(sc_ScrollLock)) + { + inputState.ClearKeyStatus(sc_ScrollLock); + + switch (ud.recstat) + { + case 0: + if (SHIFTS_IS_PRESSED) + G_OpenDemoWrite(); + break; + case 1: + G_CloseDemoWrite(); + break; + } + } + + if (ud.recstat == 2) + { + if (inputState.GetKeyStatus(sc_Space)) + { + inputState.ClearKeyStatus(sc_Space); + + g_demo_paused = !g_demo_paused; + g_demo_rewind = 0; + + if (g_demo_paused) + FX_StopAllSounds(); + } + + if (inputState.GetKeyStatus(sc_Tab)) + { + inputState.ClearKeyStatus(sc_Tab); + g_demo_showStats = !g_demo_showStats; + } + +#if 0 + if (inputState.GetKeyStatus(sc_kpad_Plus)) + { + G_InitTimer(240); + } + else if (inputState.GetKeyStatus(sc_kpad_Minus)) + { + G_InitTimer(60); + } + else if (g_timerTicsPerSecond != 120) + { + G_InitTimer(120); + } +#endif + + if (inputState.GetKeyStatus(sc_kpad_6)) + { + inputState.ClearKeyStatus(sc_kpad_6); + + int const fwdTics = (15 << (int)ALT_IS_PRESSED) << (2 * (int)SHIFTS_IS_PRESSED); + g_demo_goalCnt = g_demo_paused ? g_demo_cnt + 1 : g_demo_cnt + REALGAMETICSPERSEC * fwdTics; + g_demo_rewind = 0; + + if (g_demo_goalCnt > g_demo_totalCnt) + g_demo_goalCnt = 0; + else + Demo_PrepareWarp(); + } + else if (inputState.GetKeyStatus(sc_kpad_4)) + { + inputState.ClearKeyStatus(sc_kpad_4); + + int const rewindTics = (15 << (int)ALT_IS_PRESSED) << (2 * (int)SHIFTS_IS_PRESSED); + g_demo_goalCnt = g_demo_paused ? g_demo_cnt - 1 : g_demo_cnt - REALGAMETICSPERSEC * rewindTics; + g_demo_rewind = 1; + + if (g_demo_goalCnt <= 0) + g_demo_goalCnt = 1; + + Demo_PrepareWarp(); + } + } + + if (SHIFTS_IS_PRESSED || ALT_IS_PRESSED || WIN_IS_PRESSED) + { + int ridiculeNum = 0; + + // NOTE: sc_F1 .. sc_F10 are contiguous. sc_F11 is not sc_F10+1. + for (bssize_t j=sc_F1; j<=sc_F10; j++) + if (inputState.UnboundKeyPressed(j)) + { + inputState.ClearKeyStatus(j); + ridiculeNum = j - sc_F1 + 1; + break; + } + + if (ridiculeNum) + { + if (SHIFTS_IS_PRESSED) + { + G_AddUserQuote(*CombatMacros[ridiculeNum-1]); + Net_SendTaunt(ridiculeNum); + pus = NUMPAGES; + pub = NUMPAGES; + + return; + } + + // Not SHIFT -- that is, either some ALT or WIN. + if (G_StartRTS(ridiculeNum, 1)) + { + Net_SendRTS(ridiculeNum); + pus = NUMPAGES; + pub = NUMPAGES; + + return; + } + } + } + else + { + if (buttonMap.ButtonDown(gamefunc_Third_Person_View)) + { + buttonMap.ClearButton(gamefunc_Third_Person_View); + + if (!RRRA || (!g_player[myconnectindex].ps->on_motorcycle && !g_player[myconnectindex].ps->on_boat)) + { + g_player[myconnectindex].ps->over_shoulder_on = !g_player[myconnectindex].ps->over_shoulder_on; + + CAMERADIST = 0; + CAMERACLOCK = (int32_t) totalclock; + + P_DoQuote(QUOTE_VIEW_MODE_OFF + g_player[myconnectindex].ps->over_shoulder_on, g_player[myconnectindex].ps); + } + } + + if (ud.overhead_on != 0) + { + int const timerOffset = ((int) totalclock - nonsharedtimer); + nonsharedtimer += timerOffset; + + if (buttonMap.ButtonDown(gamefunc_Enlarge_Screen)) + g_player[myconnectindex].ps->zoom += mulscale6(timerOffset, max(g_player[myconnectindex].ps->zoom, 256)); + + if (buttonMap.ButtonDown(gamefunc_Shrink_Screen)) + g_player[myconnectindex].ps->zoom -= mulscale6(timerOffset, max(g_player[myconnectindex].ps->zoom, 256)); + + g_player[myconnectindex].ps->zoom = clamp(g_player[myconnectindex].ps->zoom, 48, 2048); + } + } + +#if 0 // fixme: We should not query Esc here, this needs to be done differently + if (I_EscapeTrigger() && ud.overhead_on && g_player[myconnectindex].ps->newowner == -1) + { + I_EscapeTriggerClear(); + ud.last_overhead = ud.overhead_on; + ud.overhead_on = 0; + ud.scrollmode = 0; + G_UpdateScreenArea(); + } +#endif + + if (buttonMap.ButtonDown(gamefunc_Map)) + { + buttonMap.ClearButton(gamefunc_Map); + if (ud.last_overhead != ud.overhead_on && ud.last_overhead) + { + ud.overhead_on = ud.last_overhead; + ud.last_overhead = 0; + } + else + { + ud.overhead_on++; + if (ud.overhead_on == 3) ud.overhead_on = 0; + ud.last_overhead = ud.overhead_on; + } + +#ifdef __ANDROID__ + if (ud.overhead_on == 1) + ud.scrollmode = 0; + else if (ud.overhead_on == 2) + { + ud.scrollmode = 1; + ud.folx = g_player[screenpeek].ps->opos.x; + ud.foly = g_player[screenpeek].ps->opos.y; + ud.fola = g_player[screenpeek].ps->oang; + } +#endif + g_restorePalette = 1; + G_UpdateScreenArea(); + } +} + +// Returns: +// 0: all OK +// -1: ID declaration was invalid: +static int32_t S_DefineMusic(const char *ID, const char *name) +{ + int32_t sel = MUS_FIRST_SPECIAL; + + Bassert(ID != NULL); + + if (!Bstrcmp(ID,"intro")) + { + // nothing + } + else if (!Bstrcmp(ID,"briefing")) + { + sel++; + } + else if (!Bstrcmp(ID,"loading")) + { + sel += 2; + } + else + { + sel = G_GetMusicIdx(ID); + if (sel < 0) + return -1; + } + mapList[sel].music = name; + return 0; +} + +static int parsedefinitions_game(scriptfile *, int); + +static void parsedefinitions_game_include(const char *fileName, scriptfile *pScript, const char *cmdtokptr, int const firstPass) +{ + scriptfile *included = scriptfile_fromfile(fileName); + + if (!included) + { + if (!Bstrcasecmp(cmdtokptr,"null") || pScript == NULL) // this is a bit overboard to prevent unused parameter warnings + { + // Printf("Warning: Failed including %s as module\n", fn); + } +/* + else + { + Printf("Warning: Failed including %s on line %s:%d\n", + fn, script->filename,scriptfile_getlinum(script,cmdtokptr)); + } +*/ + } + else + { + parsedefinitions_game(included, firstPass); + scriptfile_close(included); + } +} + +static void parsedefinitions_game_animsounds(scriptfile *pScript, const char * blockEnd, char const * fileName, dukeanim_t * animPtr) +{ + size_t numPairs = 0, allocSize = 4; + + animPtr->Sounds.Clear(); + + int defError = 1; + uint16_t lastFrameNum = 1; + + while (pScript->textptr < blockEnd) + { + int32_t frameNum; + int32_t soundNum; + + // HACK: we've reached the end of the list + // (hack because it relies on knowledge of + // how scriptfile_* preprocesses the text) + if (blockEnd - pScript->textptr == 1) + break; + + // would produce error when it encounters the closing '}' + // without the above hack + if (scriptfile_getnumber(pScript, &frameNum)) + break; + + defError = 1; + + if (scriptfile_getsymbol(pScript, &soundNum)) + break; + + // frame numbers start at 1 for us + if (frameNum <= 0) + { + Printf("Error: frame number must be greater zero on line %s:%d\n", pScript->filename, + scriptfile_getlinum(pScript, pScript->ltextptr)); + break; + } + + if (frameNum < lastFrameNum) + { + Printf("Error: frame numbers must be in (not necessarily strictly)" + " ascending order (line %s:%d)\n", + pScript->filename, scriptfile_getlinum(pScript, pScript->ltextptr)); + break; + } + + lastFrameNum = frameNum; + + if ((unsigned)soundNum >= MAXSOUNDS && soundNum != -1) + { + Printf("Error: sound number #%d invalid on line %s:%d\n", soundNum, pScript->filename, + scriptfile_getlinum(pScript, pScript->ltextptr)); + break; + } + + defError = 0; + + animsound_t sound; + sound.frame = frameNum; + sound.sound = soundNum; + animPtr->Sounds.Push(sound); + + ++numPairs; + } + + if (!defError) + { + // Printf("Defined sound sequence for hi-anim \"%s\" with %d frame/sound pairs\n", + // hardcoded_anim_tokens[animnum].text, numpairs); + } + else + { + Printf("Failed defining sound sequence for anim \"%s\".\n", fileName); + } + animPtr->Sounds.ShrinkToFit(); +} + +static int parsedefinitions_game(scriptfile *pScript, int firstPass) +{ + int token; + char *pToken; + + static const tokenlist tokens[] = + { + { "include", T_INCLUDE }, + { "#include", T_INCLUDE }, + { "includedefault", T_INCLUDEDEFAULT }, + { "#includedefault", T_INCLUDEDEFAULT }, + { "loadgrp", T_LOADGRP }, + { "cachesize", T_CACHESIZE }, + { "noautoload", T_NOAUTOLOAD }, + { "music", T_MUSIC }, + { "sound", T_SOUND }, + { "cutscene", T_CUTSCENE }, + { "animsounds", T_ANIMSOUNDS }, + { "renamefile", T_RENAMEFILE }, + { "globalgameflags", T_GLOBALGAMEFLAGS }, + }; + + static const tokenlist soundTokens[] = + { + { "id", T_ID }, + { "file", T_FILE }, + { "minpitch", T_MINPITCH }, + { "maxpitch", T_MAXPITCH }, + { "priority", T_PRIORITY }, + { "type", T_TYPE }, + { "distance", T_DISTANCE }, + { "volume", T_VOLUME }, + }; + + static const tokenlist animTokens [] = + { + { "delay", T_DELAY }, + { "aspect", T_ASPECT }, + { "sounds", T_SOUND }, + { "forcefilter", T_FORCEFILTER }, + { "forcenofilter", T_FORCENOFILTER }, + { "texturefilter", T_TEXTUREFILTER }, + }; + + do + { + token = getatoken(pScript, tokens, ARRAY_SIZE(tokens)); + pToken = pScript->ltextptr; + + switch (token) + { + case T_LOADGRP: + { + char *fileName; + + if (!scriptfile_getstring(pScript,&fileName) && firstPass) + { + fileSystem.AddAdditionalFile(fileName); + } + } + break; + case T_CACHESIZE: + { + int32_t cacheSize; + + if (scriptfile_getnumber(pScript, &cacheSize) || !firstPass) + break; + } + break; + case T_INCLUDE: + { + char *fileName; + + if (!scriptfile_getstring(pScript, &fileName)) + parsedefinitions_game_include(fileName, pScript, pToken, firstPass); + + break; + } + case T_INCLUDEDEFAULT: + { + parsedefinitions_game_include(G_DefaultDefFile(), pScript, pToken, firstPass); + break; + } + case T_NOAUTOLOAD: + if (firstPass) + gNoAutoLoad = 1; + break; + case T_MUSIC: + { + char *tokenPtr = pScript->ltextptr; + char *musicID = NULL; + char *fileName = NULL; + char *musicEnd; + + if (scriptfile_getbraces(pScript, &musicEnd)) + break; + + while (pScript->textptr < musicEnd) + { + switch (getatoken(pScript, soundTokens, ARRAY_SIZE(soundTokens))) + { + case T_ID: scriptfile_getstring(pScript, &musicID); break; + case T_FILE: scriptfile_getstring(pScript, &fileName); break; + } + } + + if (!firstPass) + { + if (musicID==NULL) + { + Printf("Error: missing ID for music definition near line %s:%d\n", + pScript->filename, scriptfile_getlinum(pScript,tokenPtr)); + break; + } + + if (fileName == NULL || fileSystem.FileExists(fileName)) + break; + + if (S_DefineMusic(musicID, fileName) == -1) + Printf("Error: invalid music ID on line %s:%d\n", pScript->filename, scriptfile_getlinum(pScript, tokenPtr)); + } + } + break; + + case T_CUTSCENE: + { + char *fileName = NULL; + + scriptfile_getstring(pScript, &fileName); + + char *animEnd; + + if (scriptfile_getbraces(pScript, &animEnd)) + break; + + if (!firstPass) + { + dukeanim_t *animPtr = Anim_Find(fileName); + + if (!animPtr) + { + animPtr = Anim_Create(fileName); + animPtr->framedelay = 10; + animPtr->frameflags = 0; + } + + int32_t temp; + + while (pScript->textptr < animEnd) + { + switch (getatoken(pScript, animTokens, ARRAY_SIZE(animTokens))) + { + case T_DELAY: + scriptfile_getnumber(pScript, &temp); + animPtr->framedelay = temp; + break; + case T_ASPECT: + { + double dtemp, dtemp2; + scriptfile_getdouble(pScript, &dtemp); + scriptfile_getdouble(pScript, &dtemp2); + animPtr->frameaspect1 = dtemp; + animPtr->frameaspect2 = dtemp2; + break; + } + case T_SOUND: + { + char *animSoundsEnd = NULL; + if (scriptfile_getbraces(pScript, &animSoundsEnd)) + break; + parsedefinitions_game_animsounds(pScript, animSoundsEnd, fileName, animPtr); + break; + } + case T_FORCEFILTER: + animPtr->frameflags |= CUTSCENE_FORCEFILTER; + break; + case T_FORCENOFILTER: + animPtr->frameflags |= CUTSCENE_FORCENOFILTER; + break; + case T_TEXTUREFILTER: + animPtr->frameflags |= CUTSCENE_TEXTUREFILTER; + break; + } + } + } + else + pScript->textptr = animEnd; + } + break; + case T_ANIMSOUNDS: + { + char *tokenPtr = pScript->ltextptr; + char *fileName = NULL; + + scriptfile_getstring(pScript, &fileName); + if (!fileName) + break; + + char *animSoundsEnd = NULL; + + if (scriptfile_getbraces(pScript, &animSoundsEnd)) + break; + + if (firstPass) + { + pScript->textptr = animSoundsEnd; + break; + } + + dukeanim_t *animPtr = Anim_Find(fileName); + + if (!animPtr) + { + Printf("Error: expected animation filename on line %s:%d\n", + pScript->filename, scriptfile_getlinum(pScript, tokenPtr)); + break; + } + + parsedefinitions_game_animsounds(pScript, animSoundsEnd, fileName, animPtr); + } + break; + + case T_SOUND: + { + char *tokenPtr = pScript->ltextptr; + char *fileName = NULL; + char *musicEnd; + + double volume = 1.0; + + int32_t soundNum = -1; + int32_t maxpitch = 0; + int32_t minpitch = 0; + int32_t priority = 0; + int32_t type = 0; + int32_t distance = 0; + + if (scriptfile_getbraces(pScript, &musicEnd)) + break; + + while (pScript->textptr < musicEnd) + { + switch (getatoken(pScript, soundTokens, ARRAY_SIZE(soundTokens))) + { + case T_ID: scriptfile_getsymbol(pScript, &soundNum); break; + case T_FILE: scriptfile_getstring(pScript, &fileName); break; + case T_MINPITCH: scriptfile_getsymbol(pScript, &minpitch); break; + case T_MAXPITCH: scriptfile_getsymbol(pScript, &maxpitch); break; + case T_PRIORITY: scriptfile_getsymbol(pScript, &priority); break; + case T_TYPE: scriptfile_getsymbol(pScript, &type); break; + case T_DISTANCE: scriptfile_getsymbol(pScript, &distance); break; + case T_VOLUME: scriptfile_getdouble(pScript, &volume); break; + } + } + + if (!firstPass) + { + if (soundNum==-1) + { + Printf("Error: missing ID for sound definition near line %s:%d\n", pScript->filename, scriptfile_getlinum(pScript,tokenPtr)); + break; + } + + if (fileName == NULL || fileSystem.FileExists(fileName)) + break; + + // maybe I should have just packed this into a sound_t and passed a reference... + if (S_DefineSound(soundNum, fileName, minpitch, maxpitch, priority, type, distance, volume) == -1) + Printf("Error: invalid sound ID on line %s:%d\n", pScript->filename, scriptfile_getlinum(pScript,tokenPtr)); + } + } + break; + case T_GLOBALGAMEFLAGS: scriptfile_getnumber(pScript, &duke3d_globalflags); break; + case T_EOF: return 0; + default: break; + } + } + while (1); + + return 0; +} + +int loaddefinitions_game(const char *fileName, int32_t firstPass) +{ + scriptfile *pScript = scriptfile_fromfile(fileName); + + if (pScript) + parsedefinitions_game(pScript, firstPass); + + if (userConfig.AddDefs) for (auto& m : *userConfig.AddDefs) + parsedefinitions_game_include(m, NULL, "null", firstPass); + + if (pScript) + scriptfile_close(pScript); + + scriptfile_clearsymbols(); + + return 0; +} + + + +static void G_FreeHashAnim(const char * /*string*/, intptr_t key) +{ + Xfree((void *)key); +} + +static void G_Cleanup(void) +{ + int32_t i; + + for (i=(MAXLEVELS*(MAXVOLUMES+1))-1; i>=0; i--) // +1 volume for "intro", "briefing" music + { + G_FreeMapState(i); + } + + for (i=MAXPLAYERS-1; i>=0; i--) + { + Xfree(g_player[i].ps); + Xfree(g_player[i].input); + } + + if (label != (char *)&sprite[0]) Xfree(label); + if (labelcode != (int32_t *)§or[0]) Xfree(labelcode); + if (labeltype != (int32_t*)&wall[0]) Xfree(labeltype); + Xfree(apScript); + Xfree(bitptr); + +// Xfree(MusicPtr); + + Gv_Clear(); + + hash_free(&h_gamevars); + hash_free(&h_labels); +} + +/* +=================== += += G_Startup += +=================== +*/ + +static void G_CompileScripts(void) +{ + label = (char *)&sprite[0]; // V8: 16384*44/64 = 11264 V7: 4096*44/64 = 2816 + labelcode = (int32_t *)§or[0]; // V8: 4096*40/4 = 40960 V7: 1024*40/4 = 10240 + labeltype = (int32_t *)&wall[0]; // V8: 16384*32/4 = 131072 V7: 8192*32/4 = 65536 + + C_Compile(G_ConFile()); + + if ((uint32_t)g_labelCnt > MAXSPRITES*sizeof(spritetype)/64) // see the arithmetic above for why + G_GameExit("Error: too many labels defined!"); + + { + char *newlabel; + int32_t *newlabelcode; + int32_t *newlabeltype; + + newlabel = (char *)Xmalloc(g_labelCnt << 6); + newlabelcode = (int32_t *)Xmalloc(g_labelCnt * sizeof(int32_t)); + newlabeltype = (int32_t *)Xmalloc(g_labelCnt * sizeof(int32_t)); + + Bmemcpy(newlabel, label, g_labelCnt*64); + Bmemcpy(newlabelcode, labelcode, g_labelCnt*sizeof(int32_t)); + Bmemcpy(newlabeltype, labeltype, g_labelCnt*sizeof(int32_t)); + + label = newlabel; + labelcode = newlabelcode; + labeltype = newlabeltype; + } + + Bmemset(sprite, 0, MAXSPRITES*sizeof(spritetype)); + Bmemset(sector, 0, MAXSECTORS*sizeof(sectortype)); + Bmemset(wall, 0, MAXWALLS*sizeof(walltype)); + + VM_OnEvent(EVENT_INIT); +} + +static inline void G_CheckGametype(void) +{ + m_coop = clamp(*m_coop, 0, g_gametypeCnt-1); + Printf("%s\n",g_gametypeNames[m_coop]); + if (g_gametypeFlags[m_coop] & GAMETYPE_ITEMRESPAWN) + ud.m_respawn_items = ud.m_respawn_inventory = 1; +} + +static void G_PostLoadPalette(void) +{ + //if (!(duke3d_globalflags & DUKE3D_NO_HARDCODED_FOGPALS)) + // paletteSetupDefaultFog(); +} + +#define SETFLAG(Tilenum, Flag) g_tile[Tilenum].flags |= Flag + +// Has to be after setting the dynamic names (e.g. SHARK). +static void A_InitEnemyFlags(void) +{ + if (DEER) + { + int DukeEnemies[] = { + DOGRUN, PIG, VIXEN, CHEER }; + + for (bssize_t i = ARRAY_SIZE(DukeEnemies) - 1; i >= 0; i--) + SETFLAG(DukeEnemies[i], SFLAG_HARDCODED_BADGUY|SFLAG_BADGUY_TILE|SFLAG_KILLCOUNT); + } + else if (RRRA) + { + int DukeEnemies[] = { + BOULDER, BOULDER1, EGG, RAT, TORNADO, BILLYCOCK, BILLYRAY, BILLYRAYSTAYPUT, + BRAYSNIPER, DOGRUN, LTH, HULKJUMP, BUBBASTAND, HULK, HULKSTAYPUT, HEN, + DRONE, PIG, RECON, MINION, MINIONSTAYPUT, UFO1, COOT, COOTSTAYPUT, SHARK, + VIXEN, SBSWIPE, BIKERB, BIKERBV2, BIKER, MAKEOUT, CHEERB, CHEER, CHEERSTAYPUT, + COOTPLAY, BILLYPLAY, MINIONBOAT, HULKBOAT, CHEERBOAT, RABBIT, MAMA }; + + int DukeEnemiesTile[] = { + BOULDER, BOULDER1, EGG, RAT, TORNADO, BILLYCOCK, BILLYRAY, BILLYRAYSTAYPUT, + BRAYSNIPER, DOGRUN, LTH, HULKJUMP, BUBBASTAND, HULK, HULKSTAYPUT, + DRONE, PIG, RECON, MINION, MINIONSTAYPUT, UFO1, COOT, COOTSTAYPUT, SHARK, + VIXEN, SBSWIPE, BIKERB, BIKERBV2, BIKER, MAKEOUT, CHEERB, CHEER, CHEERSTAYPUT, + COOTPLAY, BILLYPLAY, MINIONBOAT, HULKBOAT, CHEERBOAT, RABBIT, MAMA }; + + int KillCountEnemies[] = { + BOULDER, BOULDER1, EGG, RAT, TORNADO, BILLYCOCK, BILLYRAY, BILLYRAYSTAYPUT, + BRAYSNIPER, DOGRUN, LTH, HULKJUMP, BUBBASTAND, HULK, HULKSTAYPUT, + DRONE, PIG, RECON, MINION, MINIONSTAYPUT, UFO1, COOT, COOTSTAYPUT, SHARK, + VIXEN, SBSWIPE, BIKERB, BIKERBV2, BIKER, MAKEOUT, CHEERB, CHEER, CHEERSTAYPUT, + COOTPLAY, BILLYPLAY, MINIONBOAT, HULKBOAT, CHEERBOAT, RABBIT, MAMA, + ROCK, ROCK2 }; + + int SolidEnemies[] = { HULK, MAMA, BILLYPLAY, COOTPLAY, MAMACLOUD }; + int NoWaterDipEnemies[] = { DRONE }; + int NoCanSeeCheck[] = { + COOT, COOTSTAYPUT, VIXEN, BIKERB, BIKERBV2, CHEER, CHEERB, + CHEERSTAYPUT, MINIONBOAT, HULKBOAT, CHEERBOAT, RABBIT, COOTPLAY, + BILLYPLAY, MAKEOUT, MAMA }; + + for (bssize_t i = ARRAY_SIZE(DukeEnemies) - 1; i >= 0; i--) + SETFLAG(DukeEnemies[i], SFLAG_HARDCODED_BADGUY); + + for (bssize_t i = ARRAY_SIZE(DukeEnemiesTile) - 1; i >= 0; i--) + SETFLAG(DukeEnemiesTile[i], SFLAG_BADGUY_TILE); + + for (bssize_t i = ARRAY_SIZE(KillCountEnemies) - 1; i >= 0; i--) + SETFLAG(KillCountEnemies[i], SFLAG_KILLCOUNT); + + for (bssize_t i = ARRAY_SIZE(SolidEnemies) - 1; i >= 0; i--) + SETFLAG(SolidEnemies[i], SFLAG_NODAMAGEPUSH); + + for (bssize_t i = ARRAY_SIZE(NoWaterDipEnemies) - 1; i >= 0; i--) + SETFLAG(NoWaterDipEnemies[i], SFLAG_NOWATERDIP); + + for (bssize_t i = ARRAY_SIZE(NoCanSeeCheck) - 1; i >= 0; i--) + SETFLAG(NoCanSeeCheck[i], SFLAG_NOCANSEECHECK); + } + else if (RR) + { + int DukeEnemies[] = { + BOULDER, BOULDER1, EGG, RAT, TORNADO, BILLYCOCK, BILLYRAY, BILLYRAYSTAYPUT, + BRAYSNIPER, DOGRUN, LTH, HULKJUMP, BUBBASTAND, HULK, HULKSTAYPUT, HEN, + DRONE, PIG, RECON, SBMOVE, MINION, MINIONSTAYPUT, UFO1, UFO2, UFO3, UFO4, UFO5, + COOT, COOTSTAYPUT, SHARK, VIXEN }; + + int DukeEnemiesTile[] = { + BOULDER, BOULDER1, EGG, RAT, TORNADO, BILLYCOCK, BILLYRAY, BILLYRAYSTAYPUT, + BRAYSNIPER, DOGRUN, LTH, HULKJUMP, BUBBASTAND, HULK, HULKSTAYPUT, + DRONE, PIG, RECON, SBMOVE, MINION, MINIONSTAYPUT, UFO1, UFO2, UFO3, UFO4, UFO5, + COOT, COOTSTAYPUT, SHARK, VIXEN }; + + int KillCountEnemies[] = { + BOULDER, BOULDER1, EGG, RAT, TORNADO, BILLYCOCK, BILLYRAY, BILLYRAYSTAYPUT, + BRAYSNIPER, DOGRUN, LTH, HULKJUMP, BUBBASTAND, HULK, HULKSTAYPUT, + DRONE, PIG, RECON, SBMOVE, MINION, MINIONSTAYPUT, UFO1, UFO2, UFO3, UFO4, UFO5, + COOT, COOTSTAYPUT, SHARK, VIXEN }; + + int SolidEnemies[] = { HULK, SBMOVE }; + int NoWaterDipEnemies[] = { DRONE }; + int NoCanSeeCheck[] = { VIXEN }; + + for (bssize_t i = ARRAY_SIZE(DukeEnemies) - 1; i >= 0; i--) + SETFLAG(DukeEnemies[i], SFLAG_HARDCODED_BADGUY); + + for (bssize_t i = ARRAY_SIZE(DukeEnemiesTile) - 1; i >= 0; i--) + SETFLAG(DukeEnemiesTile[i], SFLAG_BADGUY_TILE); + + for (bssize_t i = ARRAY_SIZE(KillCountEnemies) - 1; i >= 0; i--) + SETFLAG(KillCountEnemies[i], SFLAG_KILLCOUNT); + + for (bssize_t i = ARRAY_SIZE(SolidEnemies) - 1; i >= 0; i--) + SETFLAG(SolidEnemies[i], SFLAG_NODAMAGEPUSH); + + for (bssize_t i = ARRAY_SIZE(NoWaterDipEnemies) - 1; i >= 0; i--) + SETFLAG(NoWaterDipEnemies[i], SFLAG_NOWATERDIP); + + for (bssize_t i = ARRAY_SIZE(NoCanSeeCheck) - 1; i >= 0; i--) + SETFLAG(NoCanSeeCheck[i], SFLAG_NOCANSEECHECK); + } + else + { + int DukeEnemies[] = { + SHARK, RECON, DRONE, + LIZTROOPONTOILET, LIZTROOPJUSTSIT, LIZTROOPSTAYPUT, LIZTROOPSHOOT, + LIZTROOPJETPACK, LIZTROOPDUCKING, LIZTROOPRUNNING, LIZTROOP, + OCTABRAIN, COMMANDER, COMMANDERSTAYPUT, PIGCOP, EGG, PIGCOPSTAYPUT, PIGCOPDIVE, + LIZMAN, LIZMANSPITTING, LIZMANFEEDING, LIZMANJUMP, ORGANTIC, + BOSS1, BOSS2, BOSS3, BOSS4, RAT, ROTATEGUN }; + + int SolidEnemies[] = { TANK, BOSS1, BOSS2, BOSS3, BOSS4, RECON, ROTATEGUN }; + int NoWaterDipEnemies[] = { OCTABRAIN, COMMANDER, DRONE }; + int GreenSlimeFoodEnemies[] = { LIZTROOP, LIZMAN, PIGCOP, NEWBEAST }; + + for (bssize_t i=GREENSLIME; i<=GREENSLIME+7; i++) + SETFLAG(i, SFLAG_HARDCODED_BADGUY|SFLAG_BADGUY_TILE); + + for (bssize_t i=ARRAY_SIZE(DukeEnemies)-1; i>=0; i--) + SETFLAG(DukeEnemies[i], SFLAG_HARDCODED_BADGUY|SFLAG_BADGUY_TILE); + + for (bssize_t i=ARRAY_SIZE(SolidEnemies)-1; i>=0; i--) + SETFLAG(SolidEnemies[i], SFLAG_NODAMAGEPUSH); + + for (bssize_t i=ARRAY_SIZE(NoWaterDipEnemies)-1; i>=0; i--) + SETFLAG(NoWaterDipEnemies[i], SFLAG_NOWATERDIP); + + for (bssize_t i=ARRAY_SIZE(GreenSlimeFoodEnemies)-1; i>=0; i--) + SETFLAG(GreenSlimeFoodEnemies[i], SFLAG_GREENSLIMEFOOD); + } +} +#undef SETFLAG + +void G_PostCreateGameState(void) +{ + Net_SendClientInfo(); + A_InitEnemyFlags(); +} + +void InitFonts(); + +static void G_Startup(void) +{ + int32_t i; + + timerInit(TICRATE); + timerSetCallback(gameTimerHandler); + + G_CompileScripts(); + + enginecompatibility_mode = ENGINECOMPATIBILITY_19961112; + + if (engineInit()) + G_FatalEngineError(); + + G_InitDynamicTiles(); + G_InitDynamicSounds(); + + // These depend on having the dynamic tile and/or sound mappings set up: + G_InitMultiPsky(CLOUDYOCEAN, MOONSKY1, BIGORBIT1, LA); + G_PostCreateGameState(); + if (g_netServer || ud.multimode > 1) G_CheckGametype(); + + if (userConfig.CommandMap.IsNotEmpty()) + { + FString startupMap; + if (VOLUMEONE) + { + Printf("The -map option is available in the registered version only!\n"); + } + else + { + startupMap = userConfig.CommandMap; + if (startupMap.IndexOfAny("/\\") < 0) startupMap.Insert(0, "/"); + DefaultExtension(startupMap, ".map"); + startupMap.Substitute("\\", "/"); + NormalizeFileName(startupMap); + + if (fileSystem.FileExists(startupMap)) + { + Printf("Using level: \"%s\".\n",startupMap.GetChars()); + } + else + { + Printf("Level \"%s\" not found.\n",startupMap.GetChars()); + boardfilename[0] = 0; + } + } + strncpy(boardfilename, startupMap, BMAX_PATH); + } + + for (i=0; i 1) + Printf("Multiplayer initialized.\n"); + + if (TileFiles.artLoadFiles("tiles%03i.art") < 0) + G_GameExit("Failed loading art."); + + InitFonts(); + + // Make the fullscreen nuke logo background non-fullbright. Has to be + // after dynamic tile remapping (from C_Compile) and loading tiles. + picanm[LOADSCREEN].sf |= PICANM_NOFULLBRIGHT_BIT; + +// Printf("Loading palette/lookups...\n"); + G_LoadLookups(); + TileFiles.PostLoadSetup(); + + if (DEER) + sub_54DE0(); + + screenpeek = myconnectindex; +} + +static void P_SetupMiscInputSettings(void) +{ + DukePlayer_t *ps = g_player[myconnectindex].ps; + + ps->aim_mode = in_mousemode; + ps->auto_aim = cl_autoaim; + ps->weaponswitch = cl_weaponswitch; +} + +void G_UpdatePlayerFromMenu(void) +{ + if (ud.recstat != 0) + return; + + if (numplayers > 1) + { + Net_SendClientInfo(); + if (sprite[g_player[myconnectindex].ps->i].picnum == APLAYER && sprite[g_player[myconnectindex].ps->i].pal != 1) + sprite[g_player[myconnectindex].ps->i].pal = g_player[myconnectindex].pcolor; + } + else + { + /*int32_t j = g_player[myconnectindex].ps->team;*/ + + P_SetupMiscInputSettings(); + g_player[myconnectindex].ps->palookup = g_player[myconnectindex].pcolor = G_CheckPlayerColor(playercolor); + + g_player[myconnectindex].pteam = playerteam; + + if (sprite[g_player[myconnectindex].ps->i].picnum == APLAYER && sprite[g_player[myconnectindex].ps->i].pal != 1) + sprite[g_player[myconnectindex].ps->i].pal = g_player[myconnectindex].pcolor; + } +} + +void G_BackToMenu(void) +{ + boardfilename[0] = 0; + if (ud.recstat == 1) G_CloseDemoWrite(); + ud.warp_on = 0; + g_player[myconnectindex].ps->gm = 0; + M_StartControlPanel(false); + M_SetMenu(NAME_Mainmenu); + inputState.keyFlushChars(); +} + +static int G_EndOfLevel(void) +{ + STAT_Update(ud.eog || (currentLevel->flags & MI_FORCEEOG)); + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); + P_UpdateScreenPal(g_player[myconnectindex].ps); + + if (g_player[myconnectindex].ps->gm&MODE_EOL) + { + G_CloseDemoWrite(); + + ready2send = 0; + + if (g_player[myconnectindex].ps->player_par > 0 && (g_player[myconnectindex].ps->player_par < ud.playerbest || ud.playerbest < 0) && + ud.display_bonus_screen == 1) + CONFIG_SetMapBestTime(g_loadedMapHack.md4, g_player[myconnectindex].ps->player_par); + + if (ud.display_bonus_screen == 1) + { + int32_t i = ud.screen_size; + ud.screen_size = 0; + G_UpdateScreenArea(); + ud.screen_size = i; + + if (!RRRA || (g_mostConcurrentPlayers > 1 && numplayers > 1)) + G_BonusScreen(0); + else + G_BonusScreenRRRA(0); + } + + // Clear potentially loaded per-map ART only after the bonus screens. + artClearMapArt(); + + if (ud.eog || (currentLevel->flags & MI_FORCEEOG)) + { + ud.eog = 0; + if ((!g_netServer && ud.multimode < 2)) + { + if (!VOLUMEALL) + G_DoOrderScreen(); + g_player[myconnectindex].ps->gm = 0; + return 2; + } + else + { + m_level_number = 0; + ud.level_number = 0; + } + } + } + + ud.display_bonus_screen = 1; + ready2send = 0; + + if (numplayers > 1) + g_player[myconnectindex].ps->gm = MODE_GAME; + + if (G_EnterLevel(g_player[myconnectindex].ps->gm)) + { + return 2; + } + + Net_WaitForEverybody(); + return 1; +} + +#if defined(_WIN32) && defined(DEBUGGINGAIDS) +// See FILENAME_CASE_CHECK in cache1d.c +static int32_t check_filename_casing(void) +{ + return !(g_player[myconnectindex].ps->gm&MODE_GAME); +} +#endif + +void G_MaybeAllocPlayer(int32_t pnum) +{ + if (g_player[pnum].ps == NULL) + g_player[pnum].ps = (DukePlayer_t *)Xcalloc(1, sizeof(DukePlayer_t)); + if (g_player[pnum].input == NULL) + g_player[pnum].input = (input_t *)Xcalloc(1, sizeof(input_t)); +} + +void app_loop(); + +// TODO: reorder (net)actor_t to eliminate slop and update assertion +EDUKE32_STATIC_ASSERT(sizeof(actor_t)%4 == 0); +EDUKE32_STATIC_ASSERT(sizeof(DukePlayer_t)%4 == 0); + +static const char* actions[] = { + "Move_Forward", + "Move_Backward", + "Turn_Left", + "Turn_Right", + "Strafe", + "Fire", + "Open", + "Run", + "Alt_Fire", // Duke3D", Blood + "Jump", + "Crouch", + "Look_Up", + "Look_Down", + "Look_Left", + "Look_Right", + "Strafe_Left", + "Strafe_Right", + "Aim_Up", + "Aim_Down", + "Weapon_1", + "Weapon_2", + "Weapon_3", + "Weapon_4", + "Weapon_5", + "Weapon_6", + "Weapon_7", + "Weapon_8", + "Weapon_9", + "Weapon_10", + "Inventory", + "Inventory_Left", + "Inventory_Right", + "Holo_Duke", // Duke3D", RR + "Jetpack", + "NightVision", + "MedKit", + "TurnAround", + "SendMessage", + "Map", + "Shrink_Screen", + "Enlarge_Screen", + "Center_View", + "Holster_Weapon", + "Show_Opponents_Weapon", + "Map_Follow_Mode", + "See_Coop_View", + "Mouse_Aiming", + "Toggle_Crosshair", + "Steroids", + "Quick_Kick", + "Next_Weapon", + "Previous_Weapon", + "Dpad_Select", + "Dpad_Aiming", + "Last_Weapon", + "Alt_Weapon", + "Third_Person_View", + "Show_DukeMatch_Scores", + "Toggle_Crouch", // This is the last one used by EDuke32. +}; + + +int GameInterface::app_main() +{ + buttonMap.SetButtons(actions, NUM_ACTIONS); + playing_rr = 1; + g_skillCnt = 4; + ud.multimode = 1; + ud.m_monsters_off = userConfig.nomonsters; + + g_movesPerPacket = 1; + bufferjitter = 1; + initsynccrc(); + + // This needs to happen before G_CheckCommandLine() because G_GameExit() + // accesses g_player[0]. + G_MaybeAllocPlayer(0); + + G_CheckCommandLine(); + + CONFIG_ReadSetup(); + + + hud_size.Callback(); + hud_scale.Callback(); + S_InitSound(); + + + if (RR) + { + g_cdTrack = -1; + } + + G_SetupCheats(); + + if (SHAREWARE) + g_Shareware = 1; + else + { + if (fileSystem.FileExists("DUKESW.BIN")) // JBF 20030810 + { + g_Shareware = 1; + } + } + + // gotta set the proper title after we compile the CONs if this is the full version + + if (g_scriptDebug) + Printf("CON debugging activated (level %d).\n",g_scriptDebug); + +#ifndef NETCODE_DISABLE + Net_InitNetwork(); +#endif + numplayers = 1; + g_mostConcurrentPlayers = ud.multimode; + + if (!g_fakeMultiMode) + { + connectpoint2[0] = -1; + } + else + { + for (bssize_t i=0; ipalette = BASEPAL; + + for (int i=1, j=numplayers; jteam = g_player[j].pteam = i; + g_player[j].ps->weaponswitch = 3; + g_player[j].ps->auto_aim = 0; + i = 1-i; + } + + Anim_Init(); + + const char *defsfile = G_DefFile(); + uint32_t stime = timerGetTicks(); + if (!loaddefinitionsfile(defsfile)) + { + uint32_t etime = timerGetTicks(); + Printf("Definitions file \"%s\" loaded in %d ms.\n", defsfile, etime-stime); + } + loaddefinitions_game(defsfile, FALSE); + + userConfig.AddDefs.reset(); + + enginePostInit(); + + G_PostLoadPalette(); + + tileDelete(MIRROR); + + skiptile = W_FORCEFIELD + 1; + + if (RR) + tileDelete(0); + if (RRRA) + tileDelete(13); + + if (numplayers == 1 && boardfilename[0] != 0) + { + m_level_number = 7; + ud.m_volume_number = 0; + ud.warp_on = 1; + } + + // getnames(); + + if (g_netServer || ud.multimode > 1) + { + if (ud.warp_on == 0) + { + ud.m_monsters_off = 1; + ud.m_player_skill = 0; + } + } + + g_mostConcurrentPlayers = ud.multimode; // XXX: redundant? + + ud.last_level = -1; + registerosdcommands(); + +#ifdef HAVE_CLIPSHAPE_FEATURE + int const clipMapError = engineLoadClipMaps(); + if (clipMapError > 0) + Printf("There was an error loading the sprite clipping map (status %d).\n", clipMapError); + + g_clipMapFiles.Reset(); +#endif + + videoInit(); + videoSetPalette(0, g_player[myconnectindex].ps->palette, 0); + + // check if the minifont will support lowercase letters (3136-3161) + // there is room for them in tiles012.art between "[\]^_." and "{|}~" + minitext_lowercase = 1; + + for (bssize_t i = MINIFONT + ('a'-'!'); minitext_lowercase && i < MINIFONT + ('z'-'!') + 1; ++i) + minitext_lowercase &= (int)tileCheck(i); + + /*if (RRRA) + playmve("REDINT.MVE"); still needs work on the audio side*/ + + //if (g_networkMode != NET_DEDICATED_SERVER) + { + Menu_Init(); + } + + FX_StopAllSounds(); + S_ClearSoundLocks(); + app_loop(); + return 0; +} + +void app_loop() +{ + auto &myplayer = g_player[myconnectindex].ps; + + if (DEER) + ghtrophy_loadbestscores(); + +MAIN_LOOP_RESTART: + totalclock = 0; + ototalclock = 0; + lockclock = 0; + + g_player[myconnectindex].ps->fta = 0; + for (int & q : user_quote_time) + q = 0; + + if (ud.warp_on == 1) + { + G_NewGame_EnterLevel(); + // may change ud.warp_on in an error condition + } + + if (ud.warp_on == 0) + { + if ((g_netServer || ud.multimode > 1) && boardfilename[0] != 0) + { + m_level_number = 7; + ud.m_volume_number = 0; + + if (ud.m_player_skill == 4) + ud.m_respawn_monsters = 1; + else ud.m_respawn_monsters = 0; + + for (bssize_t TRAVERSE_CONNECT(i)) + { + P_ResetWeapons(i); + P_ResetInventory(i); + } + + G_NewGame_EnterLevel(); + + Net_WaitForEverybody(); + } + else// if (g_networkMode != NET_DEDICATED_SERVER) + G_DisplayLogo(); + + //if (g_networkMode != NET_DEDICATED_SERVER) + { + M_StartControlPanel(false); + M_SetMenu(NAME_Mainmenu); + if (G_PlaybackDemo()) + { + FX_StopAllSounds(); + g_noLogoAnim = 1; + goto MAIN_LOOP_RESTART; + } + } + } + else G_UpdateScreenArea(); + +// G_GameExit(" "); /// + + ud.showweapons = ud.config.ShowOpponentWeapons; + P_SetupMiscInputSettings(); + g_player[myconnectindex].pteam = playerteam; + + if (g_gametypeFlags[ud.coop] & GAMETYPE_TDM) + g_player[myconnectindex].ps->palookup = g_player[myconnectindex].pcolor = G_GetTeamPalette(g_player[myconnectindex].pteam); + else + { + if (playercolor) g_player[myconnectindex].ps->palookup = g_player[myconnectindex].pcolor = G_CheckPlayerColor(playercolor); + else g_player[myconnectindex].ps->palookup = g_player[myconnectindex].pcolor; + } + + ud.warp_on = 0; + inputState.ClearKeyStatus(sc_Pause); // JBF: I hate the pause key + + do //main loop + { + handleevents(); + if (g_player[myconnectindex].ps->gm == MODE_DEMO) + { + M_ClearMenus(); + goto MAIN_LOOP_RESTART; + } + + Net_GetPackets(); + + // only allow binds to function if the player is actually in a game (not in a menu, typing, et cetera) or demo + inputState.SetBindsEnabled(!!(g_player[myconnectindex].ps->gm & (MODE_GAME|MODE_DEMO))); + +#if 0 +//#ifndef _WIN32 + // stdin -> OSD input for dedicated server + if (g_networkMode == NET_DEDICATED_SERVER) + { + } + else +#endif + { + G_HandleLocalKeys(); + } + + OSD_DispatchQueued(); + + char gameUpdate = false; + double const gameUpdateStartTime = timerGetHiTicks(); + + updatePauseStatus(); + + if (paused) + { + ototalclock = totalclock - TICSPERFRAME; + buttonMap.ResetButtonStates(); + } + else + { + while (((g_netClient || g_netServer) || !(g_player[myconnectindex].ps->gm & (MODE_MENU|MODE_DEMO))) && (int)(totalclock - ototalclock) >= TICSPERFRAME) + { + if (RRRA && g_player[myconnectindex].ps->on_motorcycle) + P_GetInputMotorcycle(myconnectindex); + else if (RRRA && g_player[myconnectindex].ps->on_boat) + P_GetInputBoat(myconnectindex); + else + P_GetInput(myconnectindex); + + // this is where we fill the input_t struct that is actually processed by P_ProcessInput() + auto const pPlayer = g_player[myconnectindex].ps; + auto const q16ang = fix16_to_int(pPlayer->q16ang); + auto & input = inputfifo[g_player[myconnectindex].movefifoend&(MOVEFIFOSIZ-1)][myconnectindex]; + + input = localInput; + input.fvel = mulscale9(localInput.fvel, sintable[(q16ang + 2560) & 2047]) + + mulscale9(localInput.svel, sintable[(q16ang + 2048) & 2047]) + + pPlayer->fric.x; + input.svel = mulscale9(localInput.fvel, sintable[(q16ang + 2048) & 2047]) + + mulscale9(localInput.svel, sintable[(q16ang + 1536) & 2047]) + + pPlayer->fric.y; + localInput = {}; + + g_player[myconnectindex].movefifoend++; + + ototalclock += TICSPERFRAME; + + if (paused == 0 && (!System_WantGuiCapture() || ud.recstat == 2 || (g_netServer || ud.multimode > 1)) && + (g_player[myconnectindex].ps->gm&MODE_GAME)) + { + G_MoveLoop(); + } + } + + gameUpdate = true; + g_gameUpdateTime = timerGetHiTicks()-gameUpdateStartTime; + if (g_gameUpdateAvgTime < 0.f) + g_gameUpdateAvgTime = g_gameUpdateTime; + g_gameUpdateAvgTime = ((GAMEUPDATEAVGTIMENUMSAMPLES-1.f)*g_gameUpdateAvgTime+g_gameUpdateTime)/((float) GAMEUPDATEAVGTIMENUMSAMPLES); + + G_DoCheats(); + } + + if (g_player[myconnectindex].ps->gm & (MODE_EOL|MODE_RESTART)) + { + switch (G_EndOfLevel()) + { + case 1: continue; + case 2: goto MAIN_LOOP_RESTART; + } + } + + /*if (g_networkMode == NET_DEDICATED_SERVER) + { + idle(); + } + else */if (G_FPSLimit()) + { + if (RRRA && g_player[myconnectindex].ps->on_motorcycle) + P_GetInputMotorcycle(myconnectindex); + else if (RRRA && g_player[myconnectindex].ps->on_boat) + P_GetInputBoat(myconnectindex); + else + P_GetInput(myconnectindex); + + int const smoothRatio = calc_smoothratio(totalclock, ototalclock); + + G_DrawRooms(screenpeek, smoothRatio); + if (videoGetRenderMode() >= REND_POLYMOST) + G_DrawBackground(); + G_DisplayRest(smoothRatio); + videoNextPage(); + + if (gameUpdate) + { + g_gameUpdateAndDrawTime = g_beforeSwapTime/* timerGetHiTicks()*/ - gameUpdateStartTime; + } + + if (DEER) + sub_5A02C(); + } + + if (g_player[myconnectindex].ps->gm&MODE_DEMO) + goto MAIN_LOOP_RESTART; + } + while (1); +} + +GAME_STATIC GAME_INLINE int32_t G_MoveLoop() +{ + int i; + + if (numplayers > 1) + while (predictfifoplc < g_player[myconnectindex].movefifoend) Net_DoPrediction(); + + Net_GetPackets(); + + if (numplayers < 2) bufferjitter = 0; + while (g_player[myconnectindex].movefifoend-movefifoplc > bufferjitter) + { + for(TRAVERSE_CONNECT(i)) + { + if (movefifoplc == g_player[i].movefifoend) break; + } + if (i >= 0) break; + if (G_DoMoveThings()) return 1; + } + + + return 0; +} + +int G_DoMoveThings(void) +{ + if (DEER) + sub_579A0(); + ud.camerasprite = -1; + lockclock += TICSPERFRAME; + + // Moved lower so it is restored correctly by demo diffs: + //if (g_earthquakeTime > 0) g_earthquakeTime--; + + if (g_RTSPlaying > 0) + g_RTSPlaying--; + + for (int & i : user_quote_time) + { + if (i) + { + if (--i > hud_messagetime) + i = hud_messagetime; + if (!i) pub = NUMPAGES; + } + } + + // Name display when aiming at opponents + if (cl_idplayers && (g_netServer || ud.multimode > 1) +#ifdef SPLITSCREEN_MOD_HACKS + && !g_fakeMultiMode +#endif + ) + { + hitdata_t hitData; + DukePlayer_t *const pPlayer = g_player[screenpeek].ps; + + for (bssize_t TRAVERSE_CONNECT(i)) + if (g_player[i].ps->holoduke_on != -1) + sprite[g_player[i].ps->holoduke_on].cstat ^= 256; + + hitscan((vec3_t *)pPlayer, pPlayer->cursectnum, sintable[(fix16_to_int(pPlayer->q16ang) + 512) & 2047], + sintable[fix16_to_int(pPlayer->q16ang) & 2047], fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) << 11, &hitData, + 0xffff0030); + + for (bssize_t TRAVERSE_CONNECT(i)) + if (g_player[i].ps->holoduke_on != -1) + sprite[g_player[i].ps->holoduke_on].cstat ^= 256; + + if ((hitData.sprite >= 0) && !(g_player[myconnectindex].ps->gm & MODE_MENU) && + sprite[hitData.sprite].picnum == APLAYER) + { + int const playerNum = P_Get(hitData.sprite); + + if (playerNum != screenpeek && g_player[playerNum].ps->dead_flag == 0) + { + if (pPlayer->fta == 0 || pPlayer->ftq == QUOTE_RESERVED3) + { + if (ldist(&sprite[pPlayer->i], &sprite[hitData.sprite]) < 9216) + { + quoteMgr.FormatQuote(QUOTE_RESERVED3, "%s", &g_player[playerNum].user_name[0]); + pPlayer->fta = 12, pPlayer->ftq = QUOTE_RESERVED3; + } + } + else if (pPlayer->fta > 2) pPlayer->fta -= 3; + } + } + } + + if (g_showShareware > 0) + { + g_showShareware--; + if (g_showShareware == 0) + { + pus = NUMPAGES; + pub = NUMPAGES; + } + } + + // Moved lower so it is restored correctly by diffs: +// everyothertime++; + + //if (g_netClient) // [75] The server should not overwrite its own randomseed + // randomseed = ticrandomseed; + + for (bssize_t TRAVERSE_CONNECT(i)) + Bmemcpy(g_player[i].input, &inputfifo[movefifoplc&(MOVEFIFOSIZ-1)][i], sizeof(input_t)); + + movefifoplc++; + + G_UpdateInterpolations(); + + /* + j = -1; + for (TRAVERSE_CONNECT(i)) + { + if (g_player[i].playerquitflag == 0 || TEST_SYNC_KEY(g_player[i].sync->bits,SK_GAMEQUIT) == 0) + { + j = i; + continue; + } + + G_CloseDemoWrite(); + + g_player[i].playerquitflag = 0; + } + */ + + Net_GetSyncStat(); + + g_moveThingsCount++; + + if (ud.recstat == 1) G_DemoRecord(); + + everyothertime++; + if (g_earthquakeTime > 0) g_earthquakeTime--; + + g_globalRandom = krand2(); + A_MoveDummyPlayers();//ST 13 + + for (bssize_t TRAVERSE_CONNECT(i)) + { + if (g_player[i].input->extbits&(1<<6)) + { + g_player[i].ps->team = g_player[i].pteam; + if (g_gametypeFlags[ud.coop] & GAMETYPE_TDM) + { + actor[g_player[i].ps->i].picnum = APLAYERTOP; + P_QuickKill(g_player[i].ps); + } + } + if (g_gametypeFlags[ud.coop] & GAMETYPE_TDM) + g_player[i].ps->palookup = g_player[i].pcolor = G_GetTeamPalette(g_player[i].ps->team); + + if (sprite[g_player[i].ps->i].pal != 1) + sprite[g_player[i].ps->i].pal = g_player[i].pcolor; + + if (!DEER) + P_HandleSharedKeys(i); + + P_ProcessInput(i); + if (!DEER) + P_CheckSectors(i); + } + + G_MoveWorld(); + + Net_CorrectPrediction(); + + //if (g_netServer) + // Net_SendServerUpdates(); + + if ((everyothertime&1) == 0) + { + if (DEER) + { + ghsound_ambientlooppoll(); + } + else + { + G_AnimateWalls(); + A_MoveCyclers(); + } + + //if (g_netServer && (everyothertime % 10) == 0) + //{ + // Net_SendMapUpdate(); + //} + } + + //if (g_netClient) //Slave + // Net_SendClientUpdate(); + + if (RR && ud.recstat == 0 && ud.multimode < 2 && g_torchCnt) + G_DoTorch(); + + return 0; +} + +void A_SpawnWallGlass(int spriteNum, int wallNum, int glassCnt) +{ + if (wallNum < 0) + { + for (bssize_t j = glassCnt - 1; j >= 0; --j) + { + int const a = SA(spriteNum) - 256 + (krand2() & 511) + 1024; + int32_t const r1 = krand2(), r2 = krand2(); + A_InsertSprite(SECT(spriteNum), SX(spriteNum), SY(spriteNum), SZ(spriteNum), GLASSPIECES + (j % 3), -32, 36, 36, a, + 32 + (r2 & 63), 1024 - (r1 & 1023), spriteNum, 5); + } + return; + } + + vec2_t v1 = { wall[wallNum].x, wall[wallNum].y }; + vec2_t v = { wall[wall[wallNum].point2].x - v1.x, wall[wall[wallNum].point2].y - v1.y }; + + v1.x -= ksgn(v.y); + v1.y += ksgn(v.x); + + v.x = tabledivide32_noinline(v.x, glassCnt+1); + v.y = tabledivide32_noinline(v.y, glassCnt+1); + + int16_t sect = -1; + + for (bsize_t j = glassCnt; j > 0; --j) + { + v1.x += v.x; + v1.y += v.y; + + updatesector(v1.x,v1.y,§); + if (sect >= 0) + { + int z = sector[sect].floorz - (krand2() & (klabs(sector[sect].ceilingz - sector[sect].floorz))); + + if (z < -ZOFFSET5 || z > ZOFFSET5) + z = SZ(spriteNum) - ZOFFSET5 + (krand2() & ((64 << 8) - 1)); + + int32_t const r1 = krand2(), r2 = krand2(); + A_InsertSprite(SECT(spriteNum), v1.x, v1.y, z, GLASSPIECES + (j % 3), -32, 36, 36, SA(spriteNum) - 1024, 32 + (r2 & 63), + -(r1 & 1023), spriteNum, 5); + } + } +} + +void A_SpawnWallPopcorn(int spriteNum, int wallNum, int glassCnt) +{ + if (wallNum < 0) + { + for (bssize_t j = glassCnt - 1; j >= 0; --j) + { + int const a = SA(spriteNum) - 256 + (krand2() & 511) + 1024; + int32_t const r1 = krand2(), r2 = krand2(); + A_InsertSprite(SECT(spriteNum), SX(spriteNum), SY(spriteNum), SZ(spriteNum), POPCORN, -32, 36, 36, a, + 32 + (r2 & 63), 1024 - (r1 & 1023), spriteNum, 5); + } + return; + } + + vec2_t v1 = { wall[wallNum].x, wall[wallNum].y }; + vec2_t v = { wall[wall[wallNum].point2].x - v1.x, wall[wall[wallNum].point2].y - v1.y }; + + v1.x -= ksgn(v.y); + v1.y += ksgn(v.x); + + v.x = tabledivide32_noinline(v.x, glassCnt+1); + v.y = tabledivide32_noinline(v.y, glassCnt+1); + + int16_t sect = -1; + + for (bsize_t j = glassCnt; j > 0; --j) + { + v1.x += v.x; + v1.y += v.y; + + updatesector(v1.x,v1.y,§); + if (sect >= 0) + { + int z = sector[sect].floorz - (krand2() & (klabs(sector[sect].ceilingz - sector[sect].floorz))); + + if (z < -ZOFFSET5 || z > ZOFFSET5) + z = SZ(spriteNum) - ZOFFSET5 + (krand2() & ((64 << 8) - 1)); + + int32_t const r1 = krand2(), r2 = krand2(); + A_InsertSprite(SECT(spriteNum), v1.x, v1.y, z, POPCORN, -32, 36, 36, SA(spriteNum) - 1024, 32 + (r2 & 63), + -(r1 & 1023), spriteNum, 5); + } + } +} + +void A_SpawnGlass(int spriteNum, int glassCnt) +{ + for (; glassCnt>0; glassCnt--) + { + int const a = krand2()&2047; + int const z = SZ(spriteNum)-((krand2()&16)<<8); + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(); + int const k + = A_InsertSprite(SECT(spriteNum), SX(spriteNum), SY(spriteNum), z, GLASSPIECES + (glassCnt % 3), + r3 & 15, 36, 36, a, 32 + (r2 & 63), -512 - (r1 & 2047), spriteNum, 5); + sprite[k].pal = sprite[spriteNum].pal; + } +} + +void A_SpawnCeilingGlass(int spriteNum, int sectNum, int glassCnt) +{ + int const startWall = sector[sectNum].wallptr; + int const endWall = startWall+sector[sectNum].wallnum; + + for (bssize_t wallNum = startWall; wallNum < (endWall - 1); wallNum++) + { + vec2_t v1 = { wall[wallNum].x, wall[wallNum].y }; + vec2_t v = { tabledivide32_noinline(wall[wallNum + 1].x - v1.x, glassCnt + 1), + tabledivide32_noinline(wall[wallNum + 1].y - v1.y, glassCnt + 1) }; + + for (bsize_t j = glassCnt; j > 0; j--) + { + v1.x += v.x; + v1.y += v.y; + int const a = krand2()&2047; + int const z = sector[sectNum].ceilingz+((krand2()&15)<<8); + A_InsertSprite(sectNum, v1.x, v1.y, z, GLASSPIECES + (j % 3), -32, 36, 36, + a, (krand2() & 31), 0, spriteNum, 5); + } + } +} + +void A_SpawnRandomGlass(int spriteNum, int wallNum, int glassCnt) +{ + if (wallNum < 0) + { + for (bssize_t j = glassCnt - 1; j >= 0; j--) + { + int const a = krand2() & 2047; + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(); + int const k + = A_InsertSprite(SECT(spriteNum), SX(spriteNum), SY(spriteNum), SZ(spriteNum) - (r3 & (63 << 8)), GLASSPIECES + (j % 3), + -32, 36, 36, a, 32 + (r2 & 63), 1024 - (r1 & 2047), spriteNum, 5); + sprite[k].pal = krand2() & 15; + } + return; + } + + vec2_t v1 = { wall[wallNum].x, wall[wallNum].y }; + vec2_t v = { tabledivide32_noinline(wall[wall[wallNum].point2].x - wall[wallNum].x, glassCnt + 1), + tabledivide32_noinline(wall[wall[wallNum].point2].y - wall[wallNum].y, glassCnt + 1) }; + int16_t sectNum = sprite[spriteNum].sectnum; + + for (bsize_t j = glassCnt; j > 0; j--) + { + v1.x += v.x; + v1.y += v.y; + + updatesector(v1.x, v1.y, §Num); + + int z = sector[sectNum].floorz - (krand2() & (klabs(sector[sectNum].ceilingz - sector[sectNum].floorz))); + + if (z < -ZOFFSET5 || z > ZOFFSET5) + z = SZ(spriteNum) - ZOFFSET5 + (krand2() & ((64 << 8) - 1)); + + int32_t const r1 = krand2(), r2 = krand2(); + int const k = A_InsertSprite(SECT(spriteNum), v1.x, v1.y, z, GLASSPIECES + (j % 3), -32, 36, 36, SA(spriteNum) - 1024, + 32 + (r2 & 63), -(r1 & 2047), spriteNum, 5); + sprite[k].pal = krand2() & 7; + } +} + +void GameInterface::FreeGameData() +{ + G_SetFog(0); + G_Cleanup(); +} + +void GameInterface::UpdateScreenSize() +{ + G_UpdateScreenArea(); +} + +::GameInterface* CreateInterface() +{ + return new GameInterface; +} + +END_DUKE_NS diff --git a/source/duke/src/game.h b/source/duke/src/game.h new file mode 100644 index 000000000..ec2adcdad --- /dev/null +++ b/source/duke/src/game.h @@ -0,0 +1,429 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#pragma once + +#ifndef ONLY_USERDEFS +#include "premap.h" // XXX +#endif + +#include "fix16.h" +#include "gamedefs.h" +#include "gamedef.h" +#include "net.h" +#include "mmulti.h" +#include "palette.h" +#include "cmdlib.h" + +BEGIN_DUKE_NS + +#ifndef ONLY_USERDEFS + +// Compile game-side legacy Room over Room code? +#define LEGACY_ROR 1 + +enum GametypeFlags_t { + GAMETYPE_COOP = 0x00000001, + GAMETYPE_WEAPSTAY = 0x00000002, + GAMETYPE_FRAGBAR = 0x00000004, + GAMETYPE_SCORESHEET = 0x00000008, + GAMETYPE_DMSWITCHES = 0x00000010, + GAMETYPE_COOPSPAWN = 0x00000020, + GAMETYPE_ACCESSCARDSPRITES = 0x00000040, + GAMETYPE_COOPVIEW = 0x00000080, + GAMETYPE_COOPSOUND = 0x00000100, + GAMETYPE_OTHERPLAYERSINMAP = 0x00000200, + GAMETYPE_ITEMRESPAWN = 0x00000400, + GAMETYPE_MARKEROPTION = 0x00000800, + GAMETYPE_PLAYERSFRIENDLY = 0x00001000, + GAMETYPE_FIXEDRESPAWN = 0x00002000, + GAMETYPE_ACCESSATSTART = 0x00004000, + GAMETYPE_PRESERVEINVENTORYDEATH = 0x00008000, + GAMETYPE_TDM = 0x00010000, + GAMETYPE_TDMSPAWN = 0x00020000 +}; + +// logo control +enum LogoFlags_t { + LOGO_ENABLED = 0x00000001, + LOGO_PLAYANIM = 0x00000002, + LOGO_PLAYMUSIC = 0x00000004, + LOGO_3DRSCREEN = 0x00000008, + LOGO_TITLESCREEN = 0x00000010, + LOGO_DUKENUKEM = 0x00000020, + LOGO_THREEDEE = 0x00000040, + LOGO_PLUTOPAKSPRITE = 0x00000080, + LOGO_SHAREWARESCREENS = 0x00000100, + LOGO_TENSCREEN = 0x00000200, + LOGO_STOPANIMSOUNDS = 0x00000400, + LOGO_NOE4CUTSCENE = 0x00000800, + LOGO_NOE1BONUSSCENE = 0x00001000, + LOGO_NOE2BONUSSCENE = 0x00002000, + LOGO_NOE3BONUSSCENE = 0x00004000, + LOGO_NOE4BONUSSCENE = 0x00008000, + LOGO_NOE1ENDSCREEN = 0x00010000, + LOGO_NOE2ENDSCREEN = 0x00020000, + LOGO_NOE3RADLOGO = 0x00040000, + LOGO_NODUKETEAMTEXT = 0x00080000, + LOGO_NODUKETEAMPIC = 0x00100000, + LOGO_STOPMISCSOUNDS = 0x00200000, + LOGO_NOGAMETITLE = 0x00400000, + LOGO_NOTITLEBAR = 0x00800000, + LOGO_HIDEEPISODE = 0x01000000, + LOGO_NOHELP = 0x02000000, + LOGO_NOCREDITS = 0x04000000, +}; + +enum { + STATUSBAR_NONONE = 0x00000001, + STATUSBAR_NOMINI = 0x00000002, + STATUSBAR_NOFULL = 0x00000004, + STATUSBAR_NOSHRINK = 0x00000008, + STATUSBAR_NOFRAGBAR = 0x00000010, + STATUSBAR_NOOVERLAY = 0x00000020, + STATUSBAR_NOMODERN = 0x00000040, +}; + +void A_DeleteSprite(int spriteNum); + +//static inline int32_t G_GetLogoFlags(void) +//{ +// return 255; +//} + +# define CAMERA(Membname) (ud.camera ## Membname) +# define CAMERADIST g_cameraDistance +# define CAMERACLOCK g_cameraClock + +#endif + +#define MAXSAVEGAMENAMESTRUCT 32 +#define MAXSAVEGAMENAME (MAXSAVEGAMENAMESTRUCT-1) +#define MAXPWLOCKOUT 128 +#define MAXRTSNAME 128 + +#define MAX_RETURN_VALUES 6 + +typedef struct { + vec3_t camerapos; + int32_t const_visibility,uw_framerate; + int32_t camera_time,folfvel,folavel,folx,foly,fola; + int32_t reccnt; + + int32_t statusbarscale,weaponswitch; // JBF 20031125 + int32_t statusbarmode; + int32_t noexits,automsg; + int32_t althud; + int32_t statusbarflags, statusbarrange; + + int32_t entered_name,screen_tilting; + int32_t coop,screen_size,lockout,crosshair; + int32_t playerai,angleinterpolation; + + int32_t respawn_monsters,respawn_items,respawn_inventory,recstat,monsters_off,brightness; + int32_t m_respawn_items,m_respawn_monsters,m_respawn_inventory,m_recstat,m_monsters_off; + int32_t ffire,m_player_skill,m_level_number,m_volume_number,multimode; + int32_t player_skill,level_number,volume_number,marker; + int32_t music_episode, music_level; + + int32_t playerbest; + + //int32_t returnvar[MAX_RETURN_VALUES-1]; + + uint32_t userbytever; + + fix16_t cameraq16ang, cameraq16horiz; + int16_t camerasect; + int16_t pause_on,from_bonus; + int16_t camerasprite,last_camsprite; + int16_t last_level,secretlevel; + + int8_t menutitle_pal, slidebar_palselected, slidebar_paldisabled; + + struct { + int32_t AutoAim; + int32_t ShowOpponentWeapons; + } config; + + char overhead_on,last_overhead,showweapons; + char god,warp_on,cashman,eog; + char scrollmode,noclip; + char display_bonus_screen; + char show_level_text; + + uint8_t user_map; + uint8_t screenfade, menubackground; + uint8_t shadow_pal; +} user_defs; + +extern user_defs ud; + +#ifndef ONLY_USERDEFS + +// this is checked against http://eduke32.com/VERSION +extern const char *s_buildDate; + +extern char boardfilename[BMAX_PATH]; +#define USERMAPMUSICFAKEVOLUME MAXVOLUMES +#define USERMAPMUSICFAKELEVEL (MAXLEVELS-1) +#define USERMAPMUSICFAKESLOT ((USERMAPMUSICFAKEVOLUME * MAXLEVELS) + USERMAPMUSICFAKELEVEL) + +static inline int G_HaveUserMap(void) +{ + return (boardfilename[0] != 0 && ud.level_number == 7 && ud.volume_number == 0); +} + +static inline int Menu_HaveUserMap(void) +{ + return (boardfilename[0] != 0 && m_level_number == 7 && ud.m_volume_number == 0); +} + +extern const char *defaultrtsfilename[GAMECOUNT]; +extern const char *G_DefaultRtsFile(void); + +#ifdef LEGACY_ROR +extern char ror_protectedsectors[MAXSECTORS]; +#endif + + +extern int32_t g_Debug; +extern int32_t g_Shareware; +extern int32_t g_cameraClock; +extern int32_t g_cameraDistance; +extern int32_t g_crosshairSum; +extern int32_t g_doQuickSave; +extern int32_t g_levelTextTime; +extern int32_t g_quitDeadline; +extern int32_t g_restorePalette; +extern int32_t tempwallptr; +extern int32_t ticrandomseed; +extern int32_t vote_map; +extern int32_t voting; + +//extern int8_t cheatbuf[MAXCHEATLEN],cheatbuflen; + +int32_t A_CheckInventorySprite(spritetype *s); +int32_t A_InsertSprite(int16_t whatsect, int32_t s_x, int32_t s_y, int32_t s_z, int16_t s_pn, int8_t s_s, uint8_t s_xr, + uint8_t s_yr, int16_t s_a, int16_t s_ve, int16_t s_zv, int16_t s_ow, int16_t s_ss); +int A_Spawn(int spriteNum,int tileNum); +int G_DoMoveThings(void); +//int32_t G_EndOfLevel(void); + +#ifdef YAX_ENABLE +void Yax_SetBunchZs(int32_t sectnum, int32_t cf, int32_t daz); +#else +#define Yax_SetBunchZs(sectnum, cf, daz) +#endif + +void G_PostCreateGameState(void); + +void A_SpawnCeilingGlass(int spriteNum,int sectNum,int glassCnt); +void A_SpawnGlass(int spriteNum,int glassCnt); +void A_SpawnRandomGlass(int spriteNum,int wallNum,int glassCnt); +void A_SpawnWallGlass(int spriteNum,int wallnum,int glassCnt); +void A_SpawnWallPopcorn(int spriteNum,int wallnum,int glassCnt); +void G_AddUserQuote(const char *daquote); +void G_BackToMenu(void); +void G_DumpDebugInfo(void); + +const char* G_PrintYourTime(void); +const char* G_PrintParTime(void); +const char* G_PrintDesignerTime(void); +const char* G_PrintBestTime(void); +void G_BonusScreen(int32_t bonusonly); +void G_BonusScreenRRRA(int32_t bonusonly); +//void G_CheatGetInv(void); +void G_DisplayRest(int32_t smoothratio); +void G_DoSpriteAnimations(int32_t ourx, int32_t oury, int32_t ourz, int32_t oura, int32_t smoothratio); +void G_DrawBackground(void); +void G_DrawFrags(void); +void G_HandleMirror(int32_t x, int32_t y, int32_t z, fix16_t a, fix16_t horiz, int32_t smoothratio); +void G_DrawRooms(int32_t playerNum,int32_t smoothratio); +void G_DrawTXDigiNumZ(int32_t starttile,int32_t x,int32_t y,int32_t n,int32_t s,int32_t pal,int32_t cs,int32_t x1,int32_t y1,int32_t x2,int32_t y2,int32_t z); +void G_GameExit(const char *msg) ATTRIBUTE((noreturn)); +void G_GameQuit(void); +void G_HandleLocalKeys(void); +void G_HandleSpecialKeys(void); +void G_PrintGameQuotes(int32_t snum); +//void G_SE40(int32_t smoothratio); +void G_UpdatePlayerFromMenu(void); +void P_DoQuote(int32_t q,DukePlayer_t *p); +void P_SetGamePalette(DukePlayer_t* player, uint32_t palid, ESetPalFlags flags); +void G_OnMotorcycle(DukePlayer_t *pPlayer, int spriteNum); +void G_OffMotorcycle(DukePlayer_t *pPlayer); +void G_OnBoat(DukePlayer_t *pPlayer, int spriteNum); +void G_OffBoat(DukePlayer_t *pPlayer); + +// Cstat protection mask for (currently) spawned MASKWALL* sprites. +// TODO: look at more cases of cstat=(cstat&PROTECTED)|ADDED in A_Spawn()? +// 2048+(32+16)+8+4 +#define SPAWN_PROTECT_CSTAT_MASK (CSTAT_SPRITE_NOSHADE|CSTAT_SPRITE_ALIGNMENT_SLAB|CSTAT_SPRITE_XFLIP|CSTAT_SPRITE_YFLIP); + +void fadepal(int32_t r,int32_t g,int32_t b,int32_t start,int32_t end,int32_t step); +//void fadepaltile(int32_t r,int32_t g,int32_t b,int32_t start,int32_t end,int32_t step,int32_t tile); +void G_InitTimer(int32_t ticspersec); + +inline int32_t G_GetTeamPalette(int32_t team) +{ + int8_t pal[] = { 3, 10, 11, 12 }; + + if ((unsigned)team >= ARRAY_SIZE(pal)) + return 0; + + return pal[team]; +} + +#define A_CheckSpriteFlags(spriteNum, iType) (((g_tile[sprite[spriteNum].picnum].flags^actor[spriteNum].flags) & iType) != 0) +// (unsigned)iPicnum check: AMC TC Rusty Nails, bayonet MG alt. fire, iPicnum == -1 (via aplWeaponShoots) +#define A_CheckSpriteTileFlags(iPicnum, iType) (((unsigned)iPicnum < MAXTILES) && (g_tile[iPicnum].flags & iType) != 0) +#define S_StopSound(num) S_StopEnvSound(num, -1) + +extern int G_StartRTS(int lumpNum, int localPlayer); + +extern void G_MaybeAllocPlayer(int32_t pnum); + +static inline void G_HandleAsync(void) +{ + handleevents(); + Net_GetPackets(); +} + +static inline int32_t calc_smoothratio(ClockTicks totalclk, ClockTicks ototalclk) +{ + if (!(((!g_netServer && ud.multimode < 2) && ((g_player[myconnectindex].ps->gm & MODE_MENU) == 0)) || + (g_netServer || ud.multimode > 1) || + ud.recstat == 2) || + paused) + { + return 65536; + } + + return CalcSmoothRatio(totalclk, ototalclk, REALGAMETICSPERSEC); +} + +// sector effector lotags +enum +{ + SE_0_ROTATING_SECTOR = 0, + SE_1_PIVOT = 1, + SE_2_EARTHQUAKE = 2, + SE_3_RANDOM_LIGHTS_AFTER_SHOT_OUT = 3, + SE_4_RANDOM_LIGHTS = 4, + SE_5 = 5, + SE_6_SUBWAY = 6, + // ^^ potentially incomplete substitution in code + // vv almost surely complete substitution + SE_7_TELEPORT = 7, + SE_8_UP_OPEN_DOOR_LIGHTS = 8, + SE_9_DOWN_OPEN_DOOR_LIGHTS = 9, + SE_10_DOOR_AUTO_CLOSE = 10, + SE_11_SWINGING_DOOR = 11, + SE_12_LIGHT_SWITCH = 12, + SE_13_EXPLOSIVE = 13, + SE_14_SUBWAY_CAR = 14, + SE_15_SLIDING_DOOR = 15, + SE_16_REACTOR = 16, + SE_17_WARP_ELEVATOR = 17, + SE_18_INCREMENTAL_SECTOR_RISE_FALL = 18, + SE_19_EXPLOSION_LOWERS_CEILING = 19, + SE_20_STRETCH_BRIDGE = 20, + SE_21_DROP_FLOOR = 21, + SE_22_TEETH_DOOR = 22, + SE_23_ONE_WAY_TELEPORT = 23, + SE_24_CONVEYOR = 24, + SE_25_PISTON = 25, + SE_26 = 26, + SE_27_DEMO_CAM = 27, + SE_28_LIGHTNING = 28, + SE_29_WAVES = 29, + SE_30_TWO_WAY_TRAIN = 30, + SE_31_FLOOR_RISE_FALL = 31, + SE_32_CEILING_RISE_FALL = 32, + SE_33_QUAKE_DEBRIS = 33, + SE_34 = 34, // XXX + SE_35 = 35, // XXX + SE_36_PROJ_SHOOTER = 36, + SE_49_POINT_LIGHT = 49, + SE_50_SPOT_LIGHT = 50, + SE_130 = 130, + SE_131 = 131, +}; + +// sector lotags +enum +{ + ST_0_NO_EFFECT = 0, + ST_1_ABOVE_WATER = 1, + ST_2_UNDERWATER = 2, + ST_3 = 3, + // ^^^ maybe not complete substitution in code + ST_9_SLIDING_ST_DOOR = 9, + ST_15_WARP_ELEVATOR = 15, + ST_16_PLATFORM_DOWN = 16, + ST_17_PLATFORM_UP = 17, + ST_18_ELEVATOR_DOWN = 18, + ST_19_ELEVATOR_UP = 19, + ST_20_CEILING_DOOR = 20, + ST_21_FLOOR_DOOR = 21, + ST_22_SPLITTING_DOOR = 22, + ST_23_SWINGING_DOOR = 23, + ST_25_SLIDING_DOOR = 25, + ST_26_SPLITTING_ST_DOOR = 26, + ST_27_STRETCH_BRIDGE = 27, + ST_28_DROP_FLOOR = 28, + ST_29_TEETH_DOOR = 29, + ST_30_ROTATE_RISE_BRIDGE = 30, + ST_31_TWO_WAY_TRAIN = 31, + // left: ST 32767, 65534, 65535 +}; + + +static inline void G_NewGame_EnterLevel(void) +{ + G_NewGame(ud.m_volume_number, m_level_number, ud.m_player_skill); + + if (G_EnterLevel(MODE_GAME)) + G_BackToMenu(); +} + +static inline int G_GetMusicIdx(const char *str) +{ + int32_t lev, ep; + signed char b1, b2; + + int numMatches = sscanf(str, "%c%d%c%d", &b1,&ep, &b2,&lev); + + if (numMatches != 4 || Btoupper(b1) != 'E' || Btoupper(b2) != 'L') + return -1; + + if ((unsigned)--lev >= MAXLEVELS || (unsigned)--ep >= MAXVOLUMES) + return -2; + + return (ep * MAXLEVELS) + lev; +} + +extern void G_PrintCurrentMusic(void); + + +#endif + +END_DUKE_NS diff --git a/source/duke/src/gamedef.cpp b/source/duke/src/gamedef.cpp new file mode 100644 index 000000000..ed43c9240 --- /dev/null +++ b/source/duke/src/gamedef.cpp @@ -0,0 +1,2793 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! + +#include "duke3d.h" +#include "namesdyn.h" +#include "gamedef.h" +#include "gameexec.h" +#include "savegame.h" +#include "common.h" +#include "common_game.h" +#include "cheats.h" +#include "m_argv.h" + +#include "osd.h" +#include "m_crc32.h" +#include "printf.h" +#include "menu/menu.h" +#include "stringtable.h" +#include "mapinfo.h" + +BEGIN_DUKE_NS + +#define LINE_NUMBER (g_lineNumber << 12) + +int32_t g_scriptVersion = 14; // 13 = 1.3D-style CON files, 14 = 1.4/1.5 style CON files + +char g_scriptFileName[BMAX_PATH] = "(none)"; // file we're currently compiling + +int32_t g_totalLines, g_lineNumber; +uint32_t g_scriptcrc; +char g_szBuf[1024]; + +static char g_szCurrentBlockName[256] = "(none)", g_szLastBlockName[256] = "NULL"; +static int32_t g_checkingIfElse, g_processingState, g_lastKeyword = -1; + +// The pointer to the start of the case table in a switch statement. +// First entry is 'default' code. +static intptr_t *g_caseScriptPtr; +static int32_t g_labelsOnly = 0; +static int32_t g_numBraces = 0; + +static int32_t C_ParseCommand(int32_t loop); +static int32_t C_SetScriptSize(int32_t size); + +static intptr_t apScriptGameEventEnd[MAXEVENTS]; +static intptr_t g_parsingActorPtr; +static intptr_t g_scriptEventOffset; +static char *textptr; + +int32_t g_errorCnt,g_warningCnt; + +static char *C_GetLabelType(int32_t type) +{ + int32_t i; + char x[64]; + + const char *LabelTypeText[] = + { + "define", + "state", + "actor", + "action", + "ai", + "move" + }; + + x[0] = 0; + for (i=0; i<6; i++) + { + if (!(type & (1<"; +} + +char *bitptr; // pointer to bitmap of which bytecode positions contain pointers +#define BITPTR_SET(x) (bitptr[(x)>>3] |= (1<<((x)&7))) +#define BITPTR_CLEAR(x) (bitptr[(x)>>3] &= ~(1<<((x)&7))) +#define BITPTR_IS_POINTER(x) (bitptr[(x)>>3] & (1<<((x) &7))) + +hashtable_t h_gamevars = { MAXGAMEVARS >> 1, NULL }; +hashtable_t h_labels = { 11264>>1, NULL }; + +static hashtable_t h_keywords = { CON_END>>1, NULL };; + +static hashtable_t * const tables[] = { + &h_labels, &h_keywords, &h_gamevars +}; + +static hashtable_t * const tables_free [] = { + &h_labels, &h_keywords +}; + +#define STRUCT_HASH_SETUP(table, labels) do { for (i=0; labels[i].lId >= 0; i++) hash_add(&table, labels[i].name, i, 0); } while (0) + +void C_InitHashes() +{ + for (auto table : tables) + hash_init(table); + + for (auto table : inttables) + inthash_init(table); + + for (auto &varvar : varvartable) + inthash_add(&h_varvar, varvar.x, varvar.y, 0); + + //inithashnames(); + initsoundhashnames(); + + for (tokenmap_t const & keyword : vm_keywords) + hash_add(&h_keywords, keyword.token, keyword.val, 0); +} + +#undef STRUCT_HASH_SETUP + +// "magic" number for { and }, overrides line number in compiled code for later detection +#define IFELSE_MAGIC 31337 +static int32_t g_skipBranch; + +static int32_t C_SetScriptSize(int32_t newsize) +{ + intptr_t const oscript = (intptr_t)apScript; + intptr_t *newscript; + intptr_t i, j; + int32_t osize = g_scriptSize; + char *scriptptrs; + char *newbitptr; + + scriptptrs = (char *)Xcalloc(1, g_scriptSize * sizeof(uint8_t)); + + for (i=g_scriptSize-1; i>=0; i--) + { + if (BITPTR_IS_POINTER(i)) + { + if (EDUKE32_PREDICT_FALSE((intptr_t)apScript[i] < (intptr_t)&apScript[0] || (intptr_t)apScript[i] >= (intptr_t)&apScript[g_scriptSize])) + { + g_errorCnt++; + buildprint("Internal compiler error at ", i, " (0x", hex(i), ")\n"); + VM_ScriptInfo(&apScript[i], 16); + } + + scriptptrs[i] = 1; + apScript[i] -= (intptr_t)&apScript[0]; + } + else scriptptrs[i] = 0; + } + + G_Util_PtrToIdx2(&g_tile[0].execPtr, MAXTILES, sizeof(tiledata_t), apScript, P2I_FWD_NON0); + G_Util_PtrToIdx2(&g_tile[0].loadPtr, MAXTILES, sizeof(tiledata_t), apScript, P2I_FWD_NON0); + + newscript = (intptr_t *)Xrealloc(apScript, newsize * sizeof(intptr_t)); + newbitptr = (char *)Xcalloc(1,(((newsize+7)>>3)+1) * sizeof(uint8_t)); + + if (newsize >= osize) + { + Bmemset(&newscript[0]+osize,0,(newsize-osize) * sizeof(uint8_t)); + Bmemcpy(newbitptr,bitptr,sizeof(uint8_t) *((osize+7)>>3)); + } + else + Bmemcpy(newbitptr,bitptr,sizeof(uint8_t) *((newsize+7)>>3)); + + Xfree(bitptr); + bitptr = newbitptr; + if (apScript != newscript) + { + buildprint("Relocating compiled code from to 0x", hex((intptr_t)apScript), " to 0x", hex((intptr_t)newscript), "\n"); + apScript = newscript; + } + + g_scriptSize = newsize; + g_scriptPtr = apScript + (intptr_t)g_scriptPtr - oscript; + + if (g_caseScriptPtr) + g_caseScriptPtr = apScript + (intptr_t)g_caseScriptPtr - oscript; + + for (i=(((newsize>=osize)?osize:newsize))-1; i>=0; i--) + if (scriptptrs[i]) + { + j = (intptr_t)apScript[i]+(intptr_t)&apScript[0]; + apScript[i] = j; + } + + G_Util_PtrToIdx2(&g_tile[0].execPtr, MAXTILES, sizeof(tiledata_t), apScript, P2I_BACK_NON0); + G_Util_PtrToIdx2(&g_tile[0].loadPtr, MAXTILES, sizeof(tiledata_t), apScript, P2I_BACK_NON0); + + Xfree(scriptptrs); + return 0; +} + +static inline int32_t ispecial(const char c) +{ + return (c == ' ' || c == 0x0d || c == '(' || c == ')' || + c == ',' || c == ';' || (c == 0x0a /*&& ++g_lineNumber*/)); +} + +static inline void C_NextLine(void) +{ + while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) + textptr++; +} + +static inline void C_SkipSpace(void) +{ + while (*textptr == ' ' || *textptr == '\t') + textptr++; +} + +static int32_t g_gotComment = 0; + +static int32_t C_SkipComments(void) +{ + g_gotComment = 0; + do + { + switch (*textptr) + { + case '\n': + g_lineNumber++; + fallthrough__; + case ' ': + case '\t': + case '\r': + case 0x1a: + textptr++; + break; + case '/': + switch (textptr[1]) + { + case '/': // C++ style comment + if (!(g_errorCnt || g_warningCnt) && g_scriptDebug > 1) + Printf("%s:%d: debug: got comment.\n",g_scriptFileName,g_lineNumber); + C_NextLine(); + g_gotComment = 1; + continue; + case '*': // beginning of a C style comment + if (!(g_errorCnt || g_warningCnt) && g_scriptDebug > 1) + Printf("%s:%d: debug: got start of comment block.\n",g_scriptFileName,g_lineNumber); + do + { + if (*textptr == '\n') + g_lineNumber++; + textptr++; + } + while (*textptr && (textptr[0] != '*' || textptr[1] != '/')); + + if (EDUKE32_PREDICT_FALSE(!*textptr)) + { + if (!(g_errorCnt || g_warningCnt) && g_scriptDebug) + Printf("%s:%d: debug: EOF in comment!\n",g_scriptFileName,g_lineNumber); + C_ReportError(-1); + Printf("%s:%d: error: found `/*' with no `*/'.\n",g_scriptFileName,g_lineNumber); + g_parsingActorPtr = g_processingState = g_numBraces = 0; + g_errorCnt++; + continue; + } + + if (!(g_errorCnt || g_warningCnt) && g_scriptDebug > 1) + Printf("%s:%d: debug: got end of comment block.\n",g_scriptFileName,g_lineNumber); + + textptr+=2; + g_gotComment = 1; + continue; + default: + C_ReportError(-1); + Printf("%s:%d: error: malformed comment.\n", g_scriptFileName, g_lineNumber); + C_NextLine(); + g_errorCnt++; + continue; + } + break; + + default: + if (ispecial(*textptr)) + { + textptr++; + continue; + } + fallthrough__; + case 0: // EOF + return ((g_scriptPtr-apScript) > (g_scriptSize-32)) ? C_SetScriptSize(g_scriptSize<<1) : 0; + } + } + while (1); +} + +static inline int GetDefID(char const *label) { return hash_find(&h_gamevars, label); } + +#define LAST_LABEL (label+(g_labelCnt<<6)) +static inline int32_t isaltok(const char c) +{ + return (isalnum(c) || c == '{' || c == '}' || c == '/' || c == '\\' || c == '*' || c == '-' || c == '_' || + c == '.'); +} + +static inline int32_t C_IsLabelChar(const char c, int32_t const i) +{ + return (isalnum(c) || c == '_' || c == '*' || c == '?' || (i > 0 && (c == '+' || c == '-' || c == '.'))); +} + +static inline int32_t C_GetLabelNameID(const memberlabel_t *pLabel, hashtable_t const * const table, const char *psz) +{ + // find the label psz in the table pLabel. + // returns the ID for the label, or -1 + + int32_t l = hash_findcase(table, psz); + return (l >= 0) ? pLabel[l].lId : -1; +} + +static inline int32_t C_GetLabelNameOffset(hashtable_t const * const table, const char *psz) +{ + // find the label psz in the table pLabel. + // returns the offset in the array for the label, or -1 + + return hash_findcase(table, psz); +} + +static void C_GetNextLabelName(void) +{ + int32_t i = 0; + + C_SkipComments(); + +// while (ispecial(*textptr) == 0 && *textptr!='['&& *textptr!=']' && *textptr!='\t' && *textptr!='\n' && *textptr!='\r') + while (C_IsLabelChar(*textptr, i)) + label[(g_labelCnt<<6)+(i++)] = *(textptr++); + + label[(g_labelCnt<<6)+i] = 0; + + if (!(g_errorCnt|g_warningCnt) && g_scriptDebug > 1) + Printf("%s:%d: debug: label `%s'.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6)); +} + +static inline void scriptWriteValue(int32_t const value) +{ + BITPTR_CLEAR(g_scriptPtr-apScript); + *g_scriptPtr++ = value; +} + +// addresses passed to these functions must be within the block of memory pointed to by apScript +static inline void scriptWriteAtOffset(int32_t const value, intptr_t * const addr) +{ + BITPTR_CLEAR(addr-apScript); + *(addr) = value; +} + +static inline void scriptWritePointer(intptr_t const value, intptr_t * const addr) +{ + BITPTR_SET(addr-apScript); + *(addr) = value; +} + +static int32_t C_GetKeyword(void) +{ + int32_t i; + char *temptextptr; + + C_SkipComments(); + + temptextptr = textptr; + + if (*temptextptr == 0) // EOF + return -2; + + while (isaltok(*temptextptr) == 0) + { + temptextptr++; + if (*temptextptr == 0) + return 0; + } + + i = 0; + while (isaltok(*temptextptr)) + tempbuf[i++] = *(temptextptr++); + tempbuf[i] = 0; + + return hash_find(&h_keywords,tempbuf); +} + +static int32_t C_GetNextKeyword(void) //Returns its code # +{ + int32_t i, l; + + C_SkipComments(); + + if (*textptr == 0) // EOF + return -2; + + l = 0; + while (isaltok(*(textptr+l))) + { + tempbuf[l] = textptr[l]; + l++; + } + tempbuf[l] = 0; + + if (EDUKE32_PREDICT_TRUE((i = hash_find(&h_keywords,tempbuf)) >= 0)) + { + if (i == CON_LEFTBRACE || i == CON_RIGHTBRACE || i == CON_NULLOP) + scriptWriteValue(i | (VM_IFELSE_MAGIC<<12)); + else scriptWriteValue(i | LINE_NUMBER); + + textptr += l; + + if (!(g_errorCnt || g_warningCnt) && g_scriptDebug) + Printf("%s:%d: debug: keyword `%s'.\n", g_scriptFileName, g_lineNumber, tempbuf); + return i; + } + + textptr += l; + g_errorCnt++; + + if (EDUKE32_PREDICT_FALSE((tempbuf[0] == '{' || tempbuf[0] == '}') && tempbuf[1] != 0)) + { + C_ReportError(-1); + Printf("%s:%d: error: expected whitespace between `%c' and `%s'.\n",g_scriptFileName,g_lineNumber,tempbuf[0],tempbuf+1); + } + else C_ReportError(ERROR_EXPECTEDKEYWORD); + + return -1; +} + +static int32_t parse_decimal_number(void) // (textptr) +{ + // decimal constants -- this is finicky business + int64_t num = strtoll(textptr, NULL, 10); // assume long long to be int64_t + + if (EDUKE32_PREDICT_TRUE(num >= INT32_MIN && num <= INT32_MAX)) + { + // all OK + } + else if (EDUKE32_PREDICT_FALSE(num > INT32_MAX && num <= UINT32_MAX)) + { + // Number interpreted as uint32, but packed as int32 (on 32-bit archs) + // (CON code in the wild exists that does this). Note that such conversion + // is implementation-defined (C99 6.3.1.3) but GCC does the 'expected' thing. +#if 0 + Printf("%s:%d: warning: number greater than INT32_MAX converted to a negative one.\n", + g_szScriptFileName,g_lineNumber); + g_numCompilerWarnings++; +#endif + } + else + { + // out of range, this is arguably worse + + Printf("%s:%d: warning: number out of the range of a 32-bit integer encountered.\n", + g_scriptFileName,g_lineNumber); + g_warningCnt++; + } + + return (int32_t)num; +} + +static int32_t parse_hex_constant(const char *hexnum) +{ + uint64_t x; + sscanf(hexnum, "%" PRIx64 "", &x); + + if (EDUKE32_PREDICT_FALSE(x > UINT32_MAX)) + { + Printf(g_scriptFileName, ":", g_lineNumber, ": warning: number 0x", hex(x), " truncated to 32 bits.\n"); + g_warningCnt++; + } + + return x; +} + +static void C_GetNextVarType(int32_t type) +{ + int32_t id = 0; + int32_t flags = 0; + + auto varptr = g_scriptPtr; + + C_SkipComments(); + + if (!type && !g_labelsOnly && (isdigit(*textptr) || ((*textptr == '-') && (isdigit(*(textptr+1)))))) + { + scriptWriteValue(GV_FLAG_CONSTANT); + + if (tolower(textptr[1])=='x') // hex constants + scriptWriteValue(parse_hex_constant(textptr+2)); + else + scriptWriteValue(parse_decimal_number()); + + if (!(g_errorCnt || g_warningCnt) && g_scriptDebug) + Printf("%s:%d: debug: constant %ld in place of gamevar.\n", g_scriptFileName, g_lineNumber, (long)(g_scriptPtr[-1])); +#if 1 + while (!ispecial(*textptr) && *textptr != ']') textptr++; +#else + C_GetNextLabelName(); +#endif + return; + } + else if (*textptr == '-'/* && !isdigit(*(textptr+1))*/) + { + if (EDUKE32_PREDICT_FALSE(type)) + { + g_errorCnt++; + C_ReportError(ERROR_SYNTAXERROR); + C_GetNextLabelName(); + return; + } + + if (!(g_errorCnt || g_warningCnt) && g_scriptDebug) + Printf("%s:%d: debug: flagging gamevar as negative.\n", g_scriptFileName, g_lineNumber); //,Batol(textptr)); + + flags = GV_FLAG_NEGATIVE; + textptr++; + } + + C_GetNextLabelName(); + + if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,LAST_LABEL)>=0)) + { + g_errorCnt++; + C_ReportError(ERROR_ISAKEYWORD); + return; + } + + C_SkipComments(); + + id=GetDefID(LAST_LABEL); + if (id<0) //gamevar not found + { + if (EDUKE32_PREDICT_TRUE(!type && !g_labelsOnly)) + { + //try looking for a define instead + Bstrcpy(tempbuf,LAST_LABEL); + id = hash_find(&h_labels,tempbuf); + + if (EDUKE32_PREDICT_TRUE(id>=0 && labeltype[id] & LABEL_DEFINE)) + { + if (!(g_errorCnt || g_warningCnt) && g_scriptDebug) + Printf("%s:%d: debug: label `%s' in place of gamevar.\n",g_scriptFileName,g_lineNumber,label+(id<<6)); + + scriptWriteValue(GV_FLAG_CONSTANT); + scriptWriteValue(labelcode[id]); + return; + } + } + + g_errorCnt++; + C_ReportError(ERROR_NOTAGAMEVAR); + return; + } + + if (EDUKE32_PREDICT_FALSE(type == GAMEVAR_READONLY && aGameVars[id].flags & GAMEVAR_READONLY)) + { + g_errorCnt++; + C_ReportError(ERROR_VARREADONLY); + return; + } + else if (EDUKE32_PREDICT_FALSE(aGameVars[id].flags & type)) + { + g_errorCnt++; + C_ReportError(ERROR_VARTYPEMISMATCH); + return; + } + + if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt) + Printf("%s:%d: debug: gamevar `%s'.\n",g_scriptFileName,g_lineNumber,LAST_LABEL); + + scriptWriteValue(id|flags); +} + +#define C_GetNextVar() C_GetNextVarType(0) + +static FORCE_INLINE void C_GetManyVarsType(int32_t type, int num) +{ + for (; num>0; --num) + C_GetNextVarType(type); +} + +#define C_GetManyVars(num) C_GetManyVarsType(0,num) + +// returns: +// -1 on EOF or wrong type or error +// 0 if literal value +// LABEL_* (>0) if that type and matched +// +// *g_scriptPtr will contain the value OR 0 if wrong type or error +static int32_t C_GetNextValue(int32_t type) +{ + C_SkipComments(); + + if (*textptr == 0) // EOF + return -1; + + int32_t l = 0; + + while (isaltok(*(textptr+l))) + { + tempbuf[l] = textptr[l]; + l++; + } + tempbuf[l] = 0; + + if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,tempbuf /*label+(g_numLabels<<6)*/)>=0)) + { + g_errorCnt++; + C_ReportError(ERROR_ISAKEYWORD); + textptr+=l; + } + + int32_t i = hash_find(&h_labels,tempbuf); + + if (i>=0) + { + if (EDUKE32_PREDICT_TRUE(labeltype[i] & type)) + { + if (!(g_errorCnt || g_warningCnt) && g_scriptDebug > 1) + { + char *gl = C_GetLabelType(labeltype[i]); + Printf("%s:%d: debug: %s label `%s'.\n",g_scriptFileName,g_lineNumber,gl,label+(i<<6)); + Xfree(gl); + } + + BITPTR_CLEAR(g_scriptPtr-apScript); + *(g_scriptPtr++) = labelcode[i]; + + textptr += l; + return labeltype[i]; + } + + BITPTR_CLEAR(g_scriptPtr-apScript); + *(g_scriptPtr++) = 0; + textptr += l; + char *el = C_GetLabelType(type); + char *gl = C_GetLabelType(labeltype[i]); + C_ReportError(-1); + Printf("%s:%d: warning: expected %s, found %s.\n",g_scriptFileName,g_lineNumber,el,gl); + g_warningCnt++; + Xfree(el); + Xfree(gl); + return -1; // valid label name, but wrong type + } + + if (EDUKE32_PREDICT_FALSE(isdigit(*textptr) == 0 && *textptr != '-')) + { + C_ReportError(ERROR_PARAMUNDEFINED); + g_errorCnt++; + BITPTR_CLEAR(g_scriptPtr-apScript); + *g_scriptPtr = 0; + g_scriptPtr++; + textptr+=l; + if (!l) textptr++; + return -1; // error! + } + + if (EDUKE32_PREDICT_FALSE(isdigit(*textptr) && g_labelsOnly)) + { + C_ReportError(WARNING_LABELSONLY); + g_warningCnt++; + } + + i = l-1; + do + { + // FIXME: check for 0-9 A-F for hex + if (textptr[0] == '0' && textptr[1] == 'x') break; // kill the warning for hex + if (EDUKE32_PREDICT_FALSE(!isdigit(textptr[i--]))) + { + C_ReportError(-1); + Printf("%s:%d: warning: invalid character `%c' in definition!\n",g_scriptFileName,g_lineNumber,textptr[i+1]); + g_warningCnt++; + break; + } + } + while (i > 0); + + BITPTR_CLEAR(g_scriptPtr-apScript); + + if (textptr[0] == '0' && tolower(textptr[1])=='x') + *g_scriptPtr = parse_hex_constant(textptr+2); + else + *g_scriptPtr = parse_decimal_number(); + + if (!(g_errorCnt || g_warningCnt) && g_scriptDebug > 1) + Printf("%s:%d: debug: constant %ld.\n", + g_scriptFileName,g_lineNumber,(long)*g_scriptPtr); + + g_scriptPtr++; + + textptr += l; + + return 0; // literal value +} + +static int32_t C_CheckMalformedBranch(intptr_t lastScriptPtr) +{ + switch (C_GetKeyword()) + { + case CON_RIGHTBRACE: + case CON_ENDA: + case CON_ENDS: + case CON_ELSE: + g_scriptPtr = lastScriptPtr + &apScript[0]; + g_skipBranch = 1; + C_ReportError(-1); + g_warningCnt++; + Printf("%s:%d: warning: malformed `%s' branch\n",g_scriptFileName,g_lineNumber, + VM_GetKeywordForID(*(g_scriptPtr) & VM_INSTMASK)); + return 1; + } + return 0; +} + +static int32_t C_CheckEmptyBranch(int32_t tw, intptr_t lastScriptPtr) +{ + // ifrnd and the others actually do something when the condition is executed + if ((Bstrncmp(VM_GetKeywordForID(tw), "if", 2) && tw != CON_ELSE) || + tw == CON_IFRND || tw == CON_IFHITWEAPON || tw == CON_IFCANSEE || tw == CON_IFCANSEETARGET || + tw == CON_IFPDISTL || tw == CON_IFPDISTG || tw == CON_IFGOTWEAPONCE) + { + g_skipBranch = 0; + return 0; + } + + if ((*(g_scriptPtr) & VM_INSTMASK) != CON_NULLOP || *(g_scriptPtr)>>12 != IFELSE_MAGIC) + g_skipBranch = 0; + + if (EDUKE32_PREDICT_FALSE(g_skipBranch)) + { + C_ReportError(-1); + g_warningCnt++; + g_scriptPtr = lastScriptPtr + &apScript[0]; + Printf("%s:%d: warning: empty `%s' branch\n",g_scriptFileName,g_lineNumber, + VM_GetKeywordForID(*(g_scriptPtr) & VM_INSTMASK)); + *(g_scriptPtr) = (CON_NULLOP + (IFELSE_MAGIC<<12)); + return 1; + } + return 0; +} + +static void C_Include(const char *confile) +{ + auto fp = fileSystem.OpenFileReader(confile); + + if (!fp.isOpen()) + { + g_errorCnt++; + Printf("%s:%d: error: could not find file `%s'.\n",g_scriptFileName,g_lineNumber,confile); + return; + } + + int32_t j = fp.GetLength(); + + char *mptr = (char *)Xmalloc(j+1); + + Printf("Including: %s (%d bytes)\n",confile, j); + + fp.Read(mptr, j); + fp.Close(); + g_scriptcrc = Bcrc32(mptr, j, g_scriptcrc); + mptr[j] = 0; + + if (*textptr == '"') // skip past the closing quote if it's there so we don't screw up the next line + textptr++; + + char *origtptr = textptr; + char parentScriptFileName[255]; + + Bstrcpy(parentScriptFileName, g_scriptFileName); + Bstrcpy(g_scriptFileName, confile); + + int32_t temp_ScriptLineNumber = g_lineNumber; + g_lineNumber = 1; + + int32_t temp_ifelse_check = g_checkingIfElse; + g_checkingIfElse = 0; + + textptr = mptr; + + C_SkipComments(); + C_ParseCommand(1); + + Bstrcpy(g_scriptFileName, parentScriptFileName); + + g_totalLines += g_lineNumber; + g_lineNumber = temp_ScriptLineNumber; + g_checkingIfElse = temp_ifelse_check; + + textptr = origtptr; + + Xfree(mptr); +} + +void G_DoGameStartup(const int32_t *params) +{ + int j = 0; + + ud.const_visibility = params[j++]; + g_impactDamage = params[j++]; + g_player[0].ps->max_shield_amount = params[j++]; + g_player[0].ps->max_player_health = g_player[0].ps->max_shield_amount; + g_maxPlayerHealth = g_player[0].ps->max_player_health; + g_startArmorAmount = params[j++]; + g_actorRespawnTime = params[j++]; + g_itemRespawnTime = params[j++]; + g_playerFriction = params[j++]; + g_spriteGravity = params[j++]; + g_rpgRadius = params[j++]; + g_pipebombRadius = params[j++]; + g_shrinkerRadius = params[j++]; + g_tripbombRadius = params[j++]; + g_morterRadius = params[j++]; + g_bouncemineRadius = params[j++]; + g_seenineRadius = params[j++]; + + g_player[0].ps->max_ammo_amount[1] = params[j++]; + g_player[0].ps->max_ammo_amount[2] = params[j++]; + g_player[0].ps->max_ammo_amount[3] = params[j++]; + g_player[0].ps->max_ammo_amount[4] = params[j++]; + g_player[0].ps->max_ammo_amount[5] = params[j++]; + g_player[0].ps->max_ammo_amount[6] = params[j++]; + g_player[0].ps->max_ammo_amount[7] = params[j++]; + g_player[0].ps->max_ammo_amount[8] = params[j++]; + g_player[0].ps->max_ammo_amount[9] = params[j++]; + g_player[0].ps->max_ammo_amount[11] = params[j++]; + + if (RR) + g_player[0].ps->max_ammo_amount[12] = params[j++]; + + g_damageCameras = params[j++]; + g_numFreezeBounces = params[j++]; + g_freezerSelfDamage = params[j++]; + g_deleteQueueSize = clamp(params[j++], 0, 1024); + g_tripbombLaserMode = params[j++]; + + if (RRRA) + { + g_player[0].ps->max_ammo_amount[13] = params[j++]; + g_player[0].ps->max_ammo_amount[14] = params[j++]; + g_player[0].ps->max_ammo_amount[16] = params[j++]; + } +} + +void C_DefineMusic(int volumeNum, int levelNum, const char *fileName) +{ + Bassert((unsigned)volumeNum < MAXVOLUMES+1); + Bassert((unsigned)levelNum < MAXLEVELS); + + mapList[(MAXLEVELS*volumeNum)+levelNum].music = fileName; +} + +void C_DefineVolumeFlags(int32_t vol, int32_t flags) +{ + Bassert((unsigned)vol < MAXVOLUMES); + + gVolumeFlags[vol] = flags; +} + +int32_t C_AllocQuote(int32_t qnum) +{ + Bassert((unsigned)qnum < MAXQUOTES); + return 1; +} + +void C_InitQuotes(void) +{ +#if 0 // if we want to keep this it must be done differently. This does not play nice with text substitution. + auto openkeys = Bindings.GetKeysForCommand("+open"); + if (openkeys.Size()) + { + auto OpenGameFunc = C_NameKeys(openkeys.Data(), 1); + quoteMgr.Substitute(QUOTE_DEAD, "SPACE", OpenGameFunc); + quoteMgr.Substitute(QUOTE_DEAD, "OPEN", OpenGameFunc); + quoteMgr.Substitute(QUOTE_DEAD, "USE", OpenGameFunc); + } +#endif + + g_numObituaries = 48; + for (bssize_t i = g_numObituaries - 1; i >= 0; i--) + { + quoteMgr.FormatQuote(i + OBITQUOTEINDEX, "$TXT_OBITUARY%d", i + 1); + } + + g_numSelfObituaries = 6; + for (bssize_t i = g_numSelfObituaries - 1; i >= 0; i--) + { + quoteMgr.FormatQuote(i + SUICIDEQUOTEINDEX, "$TXT_SELFOBIT%d", i + 1); + } +} + +static inline void C_BitOrNextValue(int32_t *valptr) +{ + C_GetNextValue(LABEL_DEFINE); + g_scriptPtr--; + *valptr |= *g_scriptPtr; +} + +static inline void C_FinishBitOr(int32_t value) +{ + BITPTR_CLEAR(g_scriptPtr-apScript); + *g_scriptPtr++ = value; +} + +static void scriptUpdateOpcodeForVariableType(intptr_t *ins) +{ + int opcode = -1; + + if (opcode != -1) + { + if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt) + { + Printf("%s:%d: %s -> %s for var %s\n", g_scriptFileName, g_lineNumber, + VM_GetKeywordForID(*ins & VM_INSTMASK), VM_GetKeywordForID(opcode), aGameVars[ins[1] & (MAXGAMEVARS-1)].szLabel); + } + + scriptWriteAtOffset(opcode | LINE_NUMBER, ins); + } +} + +static int32_t C_ParseCommand(int32_t loop) +{ + int32_t i, j=0, k=0, tw; + TArray buffer; + + do + { + if (EDUKE32_PREDICT_FALSE(g_errorCnt > 63 || (*textptr == '\0') || (*(textptr+1) == '\0') || C_SkipComments())) + return 1; + + if (EDUKE32_PREDICT_FALSE(g_scriptDebug)) + C_ReportError(-1); + + switch ((g_lastKeyword = tw = C_GetNextKeyword())) + { + default: + case -1: + case -2: + return 1; //End + case CON_STATE: + if (!g_parsingActorPtr && g_processingState == 0) + { + C_GetNextLabelName(); + g_scriptPtr--; + labelcode[g_labelCnt] = g_scriptPtr-apScript; + labeltype[g_labelCnt] = LABEL_STATE; + + g_processingState = 1; + Bsprintf(g_szCurrentBlockName,"%s",label+(g_labelCnt<<6)); + + if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,label+(g_labelCnt<<6))>=0)) + { + g_errorCnt++; + C_ReportError(ERROR_ISAKEYWORD); + continue; + } + + hash_add(&h_labels,label+(g_labelCnt<<6),g_labelCnt,0); + g_labelCnt++; + continue; + } + + C_GetNextLabelName(); + + if (EDUKE32_PREDICT_FALSE((j = hash_find(&h_labels,label+(g_labelCnt<<6))) < 0)) + { + C_ReportError(-1); + Printf("%s:%d: error: state `%s' not found.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6)); + g_errorCnt++; + g_scriptPtr++; + continue; + } + + if (EDUKE32_PREDICT_FALSE((labeltype[j] & LABEL_STATE) != LABEL_STATE)) + { + char *gl = (char *) C_GetLabelType(labeltype[j]); + C_ReportError(-1); + Printf("%s:%d: warning: expected state, found %s.\n", g_scriptFileName, g_lineNumber, gl); + g_warningCnt++; + Xfree(gl); + *(g_scriptPtr-1) = CON_NULLOP; // get rid of the state, leaving a nullop to satisfy if conditions + BITPTR_CLEAR(g_scriptPtr-apScript-1); + continue; // valid label name, but wrong type + } + + if (!(g_errorCnt || g_warningCnt) && g_scriptDebug > 1) + Printf("%s:%d: debug: state label `%s'.\n", g_scriptFileName, g_lineNumber, label+(j<<6)); + *g_scriptPtr = (intptr_t) (apScript+labelcode[j]); + + // 'state' type labels are always script addresses, as far as I can see + BITPTR_SET(g_scriptPtr-apScript); + + g_scriptPtr++; + continue; + + case CON_ENDS: + if (EDUKE32_PREDICT_FALSE(g_processingState == 0)) + { + C_ReportError(-1); + Printf("%s:%d: error: found `ends' without open `state'.\n",g_scriptFileName,g_lineNumber); + g_errorCnt++; + } + // else + { + if (EDUKE32_PREDICT_FALSE(g_numBraces > 0)) + { + C_ReportError(ERROR_OPENBRACKET); + g_errorCnt++; + } + else if (EDUKE32_PREDICT_FALSE(g_numBraces < 0)) + { + C_ReportError(ERROR_CLOSEBRACKET); + g_errorCnt++; + } + + g_processingState = 0; + Bsprintf(g_szCurrentBlockName,"(none)"); + } + continue; + + case CON_GAMEVAR: + { + // syntax: gamevar + // defines var1 and sets initial value. + // flags are used to define usage + // (see top of this files for flags) + + if (EDUKE32_PREDICT_FALSE(isdigit(*textptr) || (*textptr == '-'))) + { + g_errorCnt++; + C_ReportError(ERROR_SYNTAXERROR); + C_NextLine(); + continue; + } + + g_scriptPtr--; + + C_GetNextLabelName(); + + if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords, LAST_LABEL)>=0)) + { + g_warningCnt++; + C_ReportError(WARNING_VARMASKSKEYWORD); + hash_delete(&h_keywords, LAST_LABEL); + } + + int32_t defaultValue = 0; + int32_t varFlags = 0; + + if (C_GetKeyword() == -1) + { + C_GetNextValue(LABEL_DEFINE); // get initial value + defaultValue = *(--g_scriptPtr); + + j = 0; + + while (C_GetKeyword() == -1) + C_BitOrNextValue(&j); + + C_FinishBitOr(j); + varFlags = *(--g_scriptPtr); + + if (EDUKE32_PREDICT_FALSE((*(g_scriptPtr)&GAMEVAR_USER_MASK)==(GAMEVAR_PERPLAYER|GAMEVAR_PERACTOR))) + { + g_warningCnt++; + varFlags ^= GAMEVAR_PERPLAYER; + C_ReportError(WARNING_BADGAMEVAR); + } + } + + Gv_NewVar(LAST_LABEL, defaultValue, varFlags); + continue; + } + + case CON_DEFINE: + { + C_GetNextLabelName(); + + if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,label+(g_labelCnt<<6))>=0)) + { + g_errorCnt++; + C_ReportError(ERROR_ISAKEYWORD); + continue; + } + + C_GetNextValue(LABEL_DEFINE); + + i = hash_find(&h_labels,label+(g_labelCnt<<6)); + if (i>=0) + { + // if (i >= g_numDefaultLabels) + + if (EDUKE32_PREDICT_FALSE(labelcode[i] != *(g_scriptPtr-1))) + { + g_warningCnt++; + Printf("%s:%d: warning: ignored redefinition of `%s' to %d (old: %d).\n",g_scriptFileName, + g_lineNumber,label+(g_labelCnt<<6), (int32_t)(*(g_scriptPtr-1)), labelcode[i]); + } + } + else + { + hash_add(&h_labels,label+(g_labelCnt<<6),g_labelCnt,0); + labeltype[g_labelCnt] = LABEL_DEFINE; + labelcode[g_labelCnt++] = *(g_scriptPtr-1); + //if (*(g_scriptPtr-1) >= 0 && *(g_scriptPtr-1) < MAXTILES && g_dynamicTileMapping) + // G_ProcessDynamicTileMapping(label+((g_labelCnt-1)<<6),*(g_scriptPtr-1)); + } + g_scriptPtr -= 2; + continue; + } + + case CON_PALFROM: + for (j=3; j>=0; j--) + { + if (C_GetKeyword() == -1) + C_GetNextValue(LABEL_DEFINE); + else break; + } + + while (j>-1) + { + BITPTR_CLEAR(g_scriptPtr-apScript); + *g_scriptPtr++ = 0; + j--; + } + continue; + + case CON_MOVE: + if (g_parsingActorPtr || g_processingState) + { + if (EDUKE32_PREDICT_FALSE((C_GetNextValue(LABEL_MOVE|LABEL_DEFINE) == 0) && (*(g_scriptPtr-1) != 0) && (*(g_scriptPtr-1) != 1))) + { + C_ReportError(-1); + BITPTR_CLEAR(g_scriptPtr-apScript-1); + *(g_scriptPtr-1) = 0; + Printf("%s:%d: warning: expected a move, found a constant.\n",g_scriptFileName,g_lineNumber); + g_warningCnt++; + } + + j = 0; + while (C_GetKeyword() == -1) + C_BitOrNextValue(&j); + + C_FinishBitOr(j); + } + else + { + g_scriptPtr--; + C_GetNextLabelName(); + // Check to see it's already defined + + if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,label+(g_labelCnt<<6))>=0)) + { + g_errorCnt++; + C_ReportError(ERROR_ISAKEYWORD); + continue; + } + + if (EDUKE32_PREDICT_FALSE((i = hash_find(&h_labels,label+(g_labelCnt<<6))) >= 0)) + { + g_warningCnt++; + Printf("%s:%d: warning: duplicate move `%s' ignored.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6)); + } + else + { + hash_add(&h_labels,label+(g_labelCnt<<6),g_labelCnt,0); + labeltype[g_labelCnt] = LABEL_MOVE; + labelcode[g_labelCnt++] = g_scriptPtr-apScript; + } + + for (j=1; j>=0; j--) + { + if (C_GetKeyword() != -1) break; + C_GetNextValue(LABEL_DEFINE); + } + + for (k=j; k>=0; k--) + { + BITPTR_CLEAR(g_scriptPtr-apScript); + *g_scriptPtr = 0; + g_scriptPtr++; + } + } + continue; + + case CON_MUSIC: + { + // NOTE: this doesn't get stored in the PCode... + + // music 1 stalker.mid dethtoll.mid streets.mid watrwld1.mid snake1.mid + // thecall.mid ahgeez.mid dethtoll.mid streets.mid watrwld1.mid snake1.mid + g_scriptPtr--; + C_GetNextValue(LABEL_DEFINE); // Volume Number (0/4) + g_scriptPtr--; + + k = *g_scriptPtr-1; // 0-based volume number. -1 or MAXVOLUMES: "special" + if (k == -1) + k = MAXVOLUMES; + + if (EDUKE32_PREDICT_FALSE((unsigned)k >= MAXVOLUMES+1)) // if it's not background or special music + { + g_errorCnt++; + C_ReportError(-1); + Printf("%s:%d: error: volume number must be between 0 and MAXVOLUMES+1=%d.\n", + g_scriptFileName, g_lineNumber, MAXVOLUMES+1); + continue; + + } + + i = 0; + // get the file name... + while (C_GetKeyword() == -1) + { + C_SkipComments(); + + j = 0; + tempbuf[j] = '/'; + while (isaltok(*(textptr+j))) + { + tempbuf[j+1] = textptr[j]; + j++; + } + tempbuf[j+1] = '\0'; + + C_DefineMusic(k, i, tempbuf); + + textptr += j; + + if (i >= MAXLEVELS) + break; + i++; + } + } + continue; + + case CON_INCLUDE: + g_scriptPtr--; + + C_SkipComments(); + while (isaltok(*textptr) == 0) + { + textptr++; + if (*textptr == 0) break; + } + + j = 0; + while (isaltok(*textptr)) + { + tempbuf[j] = *(textptr++); + j++; + } + tempbuf[j] = '\0'; + + C_Include(tempbuf); + continue; + + case CON_AI: + if (g_parsingActorPtr || g_processingState) + { + C_GetNextValue(LABEL_AI); + } + else + { + g_scriptPtr--; + C_GetNextLabelName(); + + if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,label+(g_labelCnt<<6))>=0)) + { + g_errorCnt++; + C_ReportError(ERROR_ISAKEYWORD); + continue; + } + + i = hash_find(&h_labels,label+(g_labelCnt<<6)); + if (EDUKE32_PREDICT_FALSE(i>=0)) + { + g_warningCnt++; + Printf("%s:%d: warning: duplicate ai `%s' ignored.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6)); + } + else + { + labeltype[g_labelCnt] = LABEL_AI; + hash_add(&h_labels,label+(g_labelCnt<<6),g_labelCnt,0); + labelcode[g_labelCnt++] = g_scriptPtr-apScript; + } + + for (j=0; j<3; j++) + { + if (C_GetKeyword() != -1) break; + if (j == 1) + C_GetNextValue(LABEL_ACTION); + else if (j == 2) + { + if (EDUKE32_PREDICT_FALSE((C_GetNextValue(LABEL_MOVE|LABEL_DEFINE) == 0) && + (*(g_scriptPtr-1) != 0) && (*(g_scriptPtr-1) != 1))) + { + C_ReportError(-1); + BITPTR_CLEAR(g_scriptPtr-apScript-1); + *(g_scriptPtr-1) = 0; + Printf("%s:%d: warning: expected a move, found a constant.\n",g_scriptFileName,g_lineNumber); + g_warningCnt++; + } + + k = 0; + while (C_GetKeyword() == -1) + C_BitOrNextValue(&k); + + C_FinishBitOr(k); + j = 666; + break; + } + } + + if (j == 666) + continue; + + for (k=j; k<3; k++) + { + BITPTR_CLEAR(g_scriptPtr-apScript); + *g_scriptPtr = 0; + g_scriptPtr++; + } + } + continue; + + case CON_ACTION: + if (g_parsingActorPtr || g_processingState) + { + C_GetNextValue(LABEL_ACTION); + } + else + { + g_scriptPtr--; + C_GetNextLabelName(); + // Check to see it's already defined + + if (EDUKE32_PREDICT_FALSE(hash_find(&h_keywords,label+(g_labelCnt<<6))>=0)) + { + g_errorCnt++; + C_ReportError(ERROR_ISAKEYWORD); + continue; + } + + i = hash_find(&h_labels,label+(g_labelCnt<<6)); + if (EDUKE32_PREDICT_FALSE(i>=0)) + { + g_warningCnt++; + Printf("%s:%d: warning: duplicate action `%s' ignored.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6)); + } + else + { + labeltype[g_labelCnt] = LABEL_ACTION; + labelcode[g_labelCnt] = g_scriptPtr-apScript; + hash_add(&h_labels,label+(g_labelCnt<<6),g_labelCnt,0); + g_labelCnt++; + } + + for (j=ACTION_PARAM_COUNT-1; j>=0; j--) + { + if (C_GetKeyword() != -1) break; + C_GetNextValue(LABEL_DEFINE); + } + for (k=j; k>=0; k--) + { + BITPTR_CLEAR(g_scriptPtr-apScript); + *(g_scriptPtr++) = 0; + } + } + continue; + + case CON_ACTOR: + case CON_USERACTOR: + if (EDUKE32_PREDICT_FALSE(g_processingState || g_parsingActorPtr)) + { + C_ReportError(ERROR_FOUNDWITHIN); + g_errorCnt++; + } + + g_numBraces = 0; + g_scriptPtr--; + g_parsingActorPtr = g_scriptPtr - apScript; + + if (tw == CON_USERACTOR) + { + C_GetNextValue(LABEL_DEFINE); + g_scriptPtr--; + } + + // save the actor name w/o consuming it + C_SkipComments(); + j = 0; + while (isaltok(*(textptr+j))) + { + g_szCurrentBlockName[j] = textptr[j]; + j++; + } + g_szCurrentBlockName[j] = 0; + + j = hash_find(&h_labels, g_szCurrentBlockName); + + if (j != -1) + labeltype[j] |= LABEL_ACTOR; + + if (tw == CON_USERACTOR) + { + j = *g_scriptPtr; + + if (EDUKE32_PREDICT_FALSE(j >= 3)) + { + C_ReportError(-1); + Printf("%s:%d: warning: invalid useractor type. Must be 0, 1, 2" + " (notenemy, enemy, enemystayput).\n", + g_scriptFileName,g_lineNumber); + g_warningCnt++; + j = 0; + } + } + + C_GetNextValue(LABEL_ACTOR); + g_scriptPtr--; + + if (EDUKE32_PREDICT_FALSE((unsigned)*g_scriptPtr >= MAXTILES)) + { + C_ReportError(ERROR_EXCEEDSMAXTILES); + g_errorCnt++; + continue; + } + + g_tile[*g_scriptPtr].execPtr = apScript + g_parsingActorPtr; + + if (tw == CON_USERACTOR) + { + if (j & 1) + g_tile[*g_scriptPtr].flags |= SFLAG_BADGUY; + + if (j & 2) + g_tile[*g_scriptPtr].flags |= (SFLAG_BADGUY|SFLAG_BADGUYSTAYPUT); + } + + for (j=0; j<4; j++) + { + BITPTR_CLEAR(g_parsingActorPtr+j); + *((apScript+j)+g_parsingActorPtr) = 0; + if (j == 3) + { + j = 0; + while (C_GetKeyword() == -1) + C_BitOrNextValue(&j); + + C_FinishBitOr(j); + break; + } + else + { + if (C_GetKeyword() != -1) + { + for (i=4-j; i; i--) + { + BITPTR_CLEAR(g_scriptPtr-apScript); + *(g_scriptPtr++) = 0; + } + break; + } + switch (j) + { + case 0: + C_GetNextValue(LABEL_DEFINE); + break; + case 1: + C_GetNextValue(LABEL_ACTION); + break; + case 2: + // XXX: LABEL_MOVE|LABEL_DEFINE, what is this shit? compatibility? + // yep, it sure is :( + if (EDUKE32_PREDICT_FALSE((C_GetNextValue(LABEL_MOVE|LABEL_DEFINE) == 0) && (*(g_scriptPtr-1) != 0) && (*(g_scriptPtr-1) != 1))) + { + C_ReportError(-1); + BITPTR_CLEAR(g_scriptPtr-apScript-1); + *(g_scriptPtr-1) = 0; + Printf("%s:%d: warning: expected a move, found a constant.\n",g_scriptFileName,g_lineNumber); + g_warningCnt++; + } + break; + } + if (*(g_scriptPtr-1) >= (intptr_t)&apScript[0] && *(g_scriptPtr-1) < (intptr_t)&apScript[g_scriptSize]) + BITPTR_SET(g_parsingActorPtr+j); + else BITPTR_CLEAR(g_parsingActorPtr+j); + *((apScript+j)+g_parsingActorPtr) = *(g_scriptPtr-1); + } + } + g_checkingIfElse = 0; + continue; + + case CON_ONEVENT: + if (EDUKE32_PREDICT_FALSE(g_processingState || g_parsingActorPtr)) + { + C_ReportError(ERROR_FOUNDWITHIN); + g_errorCnt++; + } + + g_numBraces = 0; + g_scriptPtr--; + g_scriptEventOffset = g_parsingActorPtr = g_scriptPtr - apScript; + + C_SkipComments(); + j = 0; + while (isaltok(*(textptr+j))) + { + g_szCurrentBlockName[j] = textptr[j]; + j++; + } + g_szCurrentBlockName[j] = 0; + // g_labelsOnly = 1; + C_GetNextValue(LABEL_DEFINE); + g_labelsOnly = 0; + g_scriptPtr--; + j= *g_scriptPtr; // type of event + g_currentEvent = j; + //Bsprintf(g_szBuf,"Adding Event for %d at %lX",j, g_parsingEventPtr); + //AddLog(g_szBuf); + if (EDUKE32_PREDICT_FALSE((unsigned)j > MAXEVENTS-1)) + { + Printf("%s:%d: error: invalid event ID.\n",g_scriptFileName,g_lineNumber); + g_errorCnt++; + continue; + } + // if event has already been declared then store previous script location + apScriptEvents[j] = g_scriptEventOffset; + + g_checkingIfElse = 0; + + continue; + + case CON_CSTAT: + C_GetNextValue(LABEL_DEFINE); + + if (EDUKE32_PREDICT_FALSE(*(g_scriptPtr-1) == 32767)) + { + *(g_scriptPtr-1) = 32768; + C_ReportError(-1); + Printf("%s:%d: warning: tried to set cstat 32767, using 32768 instead.\n",g_scriptFileName,g_lineNumber); + g_warningCnt++; + } + else if (EDUKE32_PREDICT_FALSE((*(g_scriptPtr-1) & 48) == 48)) + { + i = *(g_scriptPtr-1); + *(g_scriptPtr-1) ^= 48; + C_ReportError(-1); + Printf("%s:%d: warning: tried to set cstat %d, using %d instead.\n",g_scriptFileName,g_lineNumber,i,(int32_t)(*(g_scriptPtr-1))); + g_warningCnt++; + } + continue; + + case CON_HITRADIUS: + C_GetNextValue(LABEL_DEFINE); + C_GetNextValue(LABEL_DEFINE); + C_GetNextValue(LABEL_DEFINE); + fallthrough__; + case CON_ADDAMMO: + case CON_ADDWEAPON: + case CON_SIZETO: + case CON_SIZEAT: + case CON_DEBRIS: + case CON_ADDINVENTORY: + case CON_GUTS: + C_GetNextValue(LABEL_DEFINE); + fallthrough__; + case CON_STRENGTH: + case CON_SHOOT: + case CON_ADDPHEALTH: + case CON_SPAWN: + case CON_COUNT: + case CON_ENDOFGAME: + case CON_SPRITEPAL: + case CON_CACTOR: + case CON_MONEY: + case CON_ADDKILLS: + case CON_DEBUG: + case CON_ADDSTRENGTH: + case CON_CSTATOR: + case CON_MAIL: + case CON_PAPER: + case CON_SLEEPTIME: + case CON_CLIPDIST: + case CON_ISDRUNK: + case CON_ISEAT: + case CON_NEWPIC: + case CON_LOTSOFGLASS: + case CON_QUOTE: + case CON_SOUND: + case CON_GLOBALSOUND: + case CON_SOUNDONCE: + case CON_STOPSOUND: + C_GetNextValue(LABEL_DEFINE); + continue; + + case CON_ELSE: + { + if (EDUKE32_PREDICT_FALSE(!g_checkingIfElse)) + { + g_scriptPtr--; + intptr_t *tempscrptr = g_scriptPtr; + g_warningCnt++; + C_ReportError(-1); + + Printf("%s:%d: warning: found `else' with no `if'.\n", g_scriptFileName, g_lineNumber); + + if (C_GetKeyword() == CON_LEFTBRACE) + { + C_GetNextKeyword(); + g_numBraces++; + + C_ParseCommand(1); + } + else C_ParseCommand(0); + + g_scriptPtr = tempscrptr; + + continue; + } + + intptr_t const lastScriptPtr = g_scriptPtr - apScript - 1; + + g_skipBranch = 0; + g_checkingIfElse--; + + if (C_CheckMalformedBranch(lastScriptPtr)) + continue; + + intptr_t const offset = (unsigned) (g_scriptPtr-apScript); + + g_scriptPtr++; //Leave a spot for the fail location + + if (!g_gotComment) + C_ParseCommand(0); + + if (C_CheckEmptyBranch(tw, lastScriptPtr)) + continue; + + intptr_t *tempscrptr = (intptr_t *) apScript+offset; + *tempscrptr = (intptr_t) g_scriptPtr; + BITPTR_SET(tempscrptr-apScript); + + continue; + } + case CON_ADDLOGVAR: + g_labelsOnly = 1; + C_GetNextVar(); + g_labelsOnly = 0; + continue; + case CON_ADDVAR: + case CON_SETVAR: +setvar: + { + auto ins = &g_scriptPtr[-1]; + + C_GetNextVarType(GAMEVAR_READONLY); + C_GetNextValue(LABEL_DEFINE); + // replace instructions with special versions for specific var types + scriptUpdateOpcodeForVariableType(ins); + continue; + } + case CON_ADDVARVAR: + case CON_SETVARVAR: + { +//setvarvar: + auto ins = &g_scriptPtr[-1]; + auto tptr = textptr; + int const lnum = g_lineNumber; + + C_GetNextVarType(GAMEVAR_READONLY); + C_GetNextVar(); + + int const opcode = inthash_find(&h_varvar, *ins & VM_INSTMASK); + + if (ins[2] == GV_FLAG_CONSTANT && opcode != -1) + { + if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt) + { + Printf("%s:%d: %s -> %s\n", g_scriptFileName, g_lineNumber, + VM_GetKeywordForID(*ins & VM_INSTMASK), VM_GetKeywordForID(opcode)); + } + + tw = opcode; + scriptWriteAtOffset(opcode | LINE_NUMBER, ins); + g_scriptPtr = &ins[1]; + textptr = tptr; + g_lineNumber = lnum; + goto setvar; + } + + continue; + } + + case CON_IFVARVARE: + case CON_IFVARVARG: + case CON_IFVARVARL: + { + auto const ins = &g_scriptPtr[-1]; + auto const lastScriptPtr = &g_scriptPtr[-1] - apScript; + auto const lasttextptr = textptr; + int const lnum = g_lineNumber; + + g_skipBranch = false; + + C_GetNextVar(); + auto const var = g_scriptPtr; + C_GetNextVar(); + + if (*var == GV_FLAG_CONSTANT) + { + int const opcode = inthash_find(&h_varvar, tw); + + if (opcode != -1) + { + if (g_scriptDebug > 1 && !g_errorCnt && !g_warningCnt) + { + Printf("%s:%d: replacing %s with %s\n", g_scriptFileName, g_lineNumber, + VM_GetKeywordForID(*ins & VM_INSTMASK), VM_GetKeywordForID(opcode)); + } + + scriptWriteAtOffset(opcode | LINE_NUMBER, ins); + tw = opcode; + g_scriptPtr = &ins[1]; + textptr = lasttextptr; + g_lineNumber = lnum; + goto ifvar; + } + } + + if (C_CheckMalformedBranch(lastScriptPtr)) + continue; + + auto const offset = g_scriptPtr - apScript; + g_scriptPtr++; // Leave a spot for the fail location + + C_ParseCommand(0); + + if (C_CheckEmptyBranch(tw, lastScriptPtr)) + continue; + + auto const tempscrptr = apScript + offset; + scriptWritePointer((intptr_t)g_scriptPtr, tempscrptr); + continue; + } + + case CON_IFVARE: + case CON_IFVARG: + case CON_IFVARL: + { +ifvar: + auto const ins = &g_scriptPtr[-1]; + auto const lastScriptPtr = &g_scriptPtr[-1] - apScript; + + g_skipBranch = false; + + C_GetNextVar(); + C_GetNextValue(LABEL_DEFINE); + + if (C_CheckMalformedBranch(lastScriptPtr)) + continue; + + scriptUpdateOpcodeForVariableType(ins); + + auto const offset = g_scriptPtr - apScript; + g_scriptPtr++; //Leave a spot for the fail location + + C_ParseCommand(0); + + if (C_CheckEmptyBranch(tw, lastScriptPtr)) + continue; + + auto const tempscrptr = apScript + offset; + scriptWritePointer((intptr_t)g_scriptPtr, tempscrptr); + + j = C_GetKeyword(); + + if (j == CON_ELSE) + g_checkingIfElse++; + + continue; + } + + case CON_IFRND: + case CON_IFPDISTL: + case CON_IFPDISTG: + case CON_IFWASWEAPON: + case CON_IFACTIONCOUNT: + case CON_IFCOUNT: + case CON_IFACTOR: + case CON_IFSTRENGTH: + case CON_IFSPAWNEDBY: + case CON_IFGAPZL: + case CON_IFFLOORDISTL: + case CON_IFCEILINGDISTL: + case CON_IFPHEALTHL: + case CON_IFSPRITEPAL: + case CON_IFGOTWEAPONCE: + case CON_IFANGDIFFL: + case CON_IFACTORHEALTHG: + case CON_IFACTORHEALTHL: + case CON_IFSOUNDID: + case CON_IFSOUNDDIST: + case CON_IFAI: + case CON_IFACTION: + case CON_IFMOVE: + case CON_IFP: + case CON_IFPINVENTORY: + { + intptr_t offset; + intptr_t lastScriptPtr = (g_scriptPtr-&apScript[0]-1); + + g_skipBranch = 0; + + switch (tw) + { + case CON_IFAI: + C_GetNextValue(LABEL_AI); + break; + case CON_IFACTION: + C_GetNextValue(LABEL_ACTION); + break; + case CON_IFMOVE: + if (EDUKE32_PREDICT_FALSE((C_GetNextValue(LABEL_MOVE|LABEL_DEFINE) == 0) && (*(g_scriptPtr-1) != 0) && (*(g_scriptPtr-1) != 1))) + { + C_ReportError(-1); + *(g_scriptPtr-1) = 0; + Printf("%s:%d: warning: expected a move, found a constant.\n",g_scriptFileName,g_lineNumber); + g_warningCnt++; + } + break; + case CON_IFPINVENTORY: + C_GetNextValue(LABEL_DEFINE); + C_GetNextValue(LABEL_DEFINE); + break; + case CON_IFP: + j = 0; + do + C_BitOrNextValue(&j); + while (C_GetKeyword() == -1); + C_FinishBitOr(j); + break; + default: + C_GetNextValue(LABEL_DEFINE); + break; + } + + if (C_CheckMalformedBranch(lastScriptPtr)) + continue; + + intptr_t *tempscrptr = g_scriptPtr; + offset = (unsigned)(tempscrptr-apScript); + + g_scriptPtr++; //Leave a spot for the fail location + + C_ParseCommand(0); + + if (C_CheckEmptyBranch(tw, lastScriptPtr)) + continue; + + tempscrptr = (intptr_t *)apScript+offset; + *tempscrptr = (intptr_t) g_scriptPtr; + BITPTR_SET(tempscrptr-apScript); + + j = C_GetKeyword(); + + if (j == CON_ELSE || j == CON_LEFTBRACE) + g_checkingIfElse++; + + continue; + } + + case CON_IFONWATER: + case CON_IFINWATER: + case CON_IFACTORNOTSTAYPUT: + case CON_IFCANSEE: + case CON_IFHITWEAPON: + case CON_IFSQUISHED: + case CON_IFDEAD: + case CON_IFCANSHOOTTARGET: + case CON_IFHITSPACE: + case CON_IFOUTSIDE: + case CON_IFMULTIPLAYER: + case CON_IFINSPACE: + case CON_IFBULLETNEAR: + case CON_IFRESPAWN: + case CON_IFINOUTERSPACE: + case CON_IFNOTMOVING: + case CON_IFAWAYFROMWALL: + case CON_IFCANSEETARGET: + case CON_IFNOSOUNDS: + case CON_IFNOCOVER: + case CON_IFHITTRUCK: + case CON_IFTIPCOW: + case CON_IFONMUD: + case CON_IFCOOP: + case CON_IFMOTOFAST: + case CON_IFWIND: + case CON_IFONMOTO: + case CON_IFONBOAT: + case CON_IFSIZEDOWN: + case CON_IFFINDNEWSPOT: + case CON_IFPUPWIND: + { + intptr_t offset; + intptr_t lastScriptPtr = (g_scriptPtr-&apScript[0]-1); + + g_skipBranch = 0; + + if (C_CheckMalformedBranch(lastScriptPtr)) + continue; + + intptr_t *tempscrptr = g_scriptPtr; + offset = (unsigned)(tempscrptr-apScript); + + g_scriptPtr++; //Leave a spot for the fail location + + C_ParseCommand(0); + + if (C_CheckEmptyBranch(tw, lastScriptPtr)) + continue; + + tempscrptr = (intptr_t *)apScript+offset; + *tempscrptr = (intptr_t) g_scriptPtr; + BITPTR_SET(tempscrptr-apScript); + + j = C_GetKeyword(); + + if (j == CON_ELSE || j == CON_LEFTBRACE) + g_checkingIfElse++; + + continue; + } + + case CON_LEFTBRACE: + if (EDUKE32_PREDICT_FALSE(!(g_processingState || g_parsingActorPtr || g_scriptEventOffset))) + { + g_errorCnt++; + C_ReportError(ERROR_SYNTAXERROR); + } + g_numBraces++; + + C_ParseCommand(1); + continue; + + case CON_RIGHTBRACE: + g_numBraces--; + + if ((*(g_scriptPtr-2)>>12) == (IFELSE_MAGIC) && + ((*(g_scriptPtr-2) & VM_INSTMASK) == CON_LEFTBRACE)) // rewrite "{ }" into "nullop" + { + // Printf("%s:%d: rewriting empty braces '{ }' as 'nullop' from right\n",g_szScriptFileName,g_lineNumber); + *(g_scriptPtr-2) = CON_NULLOP + (IFELSE_MAGIC<<12); + g_scriptPtr -= 2; + + if (C_GetKeyword() != CON_ELSE && (*(g_scriptPtr-2) & VM_INSTMASK) != CON_ELSE) + g_skipBranch = 1; + else g_skipBranch = 0; + + j = C_GetKeyword(); + + if (g_checkingIfElse && j != CON_ELSE) + g_checkingIfElse--; + + return 1; + } + + if (EDUKE32_PREDICT_FALSE(g_numBraces < 0)) + { + C_ReportError(-1); + Printf("%s:%d: error: found more `}' than `{'.\n",g_scriptFileName,g_lineNumber); + g_errorCnt++; + } + + if (g_checkingIfElse && j != CON_ELSE) + g_checkingIfElse--; + + return 1; + + case CON_BETANAME: + g_scriptPtr--; + j = 0; + C_NextLine(); + continue; + + case CON_DEFINEVOLUMENAME: + g_scriptPtr--; + + C_GetNextValue(LABEL_DEFINE); + g_scriptPtr--; + j = *g_scriptPtr; + + C_SkipSpace(); + + if (EDUKE32_PREDICT_FALSE((unsigned)j > MAXVOLUMES-1)) + { + Printf("%s:%d: error: volume number exceeds maximum volume count.\n", + g_scriptFileName,g_lineNumber); + g_errorCnt++; + C_NextLine(); + continue; + } + + i = strcspn(textptr, "\r\n"); + gVolumeNames[j] = FStringTable::MakeMacro(textptr, i); + textptr+=i; + g_volumeCnt = j+1; + continue; + + case CON_DEFINESKILLNAME: + g_scriptPtr--; + + C_GetNextValue(LABEL_DEFINE); + g_scriptPtr--; + j = *g_scriptPtr; + + C_SkipSpace(); + + if (EDUKE32_PREDICT_FALSE((unsigned)j >= MAXSKILLS)) + { + Printf("%s:%d: error: skill number exceeds maximum skill count %d.\n", + g_scriptFileName,g_lineNumber, MAXSKILLS); + g_errorCnt++; + C_NextLine(); + continue; + } + + i = strcspn(textptr, "\r\n"); + gSkillNames[j] = FStringTable::MakeMacro(textptr, i); + textptr+=i; + + for (i=0; i MAXVOLUMES-1)) + { + Printf("%s:%d: error: volume number exceeds maximum volume count.\n",g_scriptFileName,g_lineNumber); + g_errorCnt++; + C_NextLine(); + continue; + } + if (EDUKE32_PREDICT_FALSE((unsigned)k > MAXLEVELS-1)) + { + Printf("%s:%d: error: level number exceeds maximum number of levels per episode.\n",g_scriptFileName,g_lineNumber); + g_errorCnt++; + C_NextLine(); + continue; + } + + i = 0; + + tempbuf[i] = '/'; + + while (*textptr != ' ' && *textptr != '\t' && *textptr != 0x0a) + { + tempbuf[i+1] = *textptr; + textptr++,i++; + if (EDUKE32_PREDICT_FALSE(i >= BMAX_PATH)) + { + Printf("%s:%d: error: level file name exceeds limit of %d characters.\n",g_scriptFileName,g_lineNumber,BMAX_PATH); + g_errorCnt++; + C_SkipSpace(); + break; + } + } + tempbuf[i+1] = '\0'; + + mapList[j *MAXLEVELS+k].SetFileName(tempbuf); + + C_SkipComments(); + + mapList[j *MAXLEVELS+k].parTime = + (((*(textptr+0)-'0')*10+(*(textptr+1)-'0'))*60)+ + (((*(textptr+3)-'0')*10+(*(textptr+4)-'0'))); + + textptr += 5; + C_SkipSpace(); + + // cheap hack, 0.99 doesn't have the 3D Realms time + if (*(textptr+2) == ':') + { + mapList[j *MAXLEVELS+k].designerTime = + (((*(textptr+0)-'0')*10+(*(textptr+1)-'0'))*60)+ + (((*(textptr+3)-'0')*10+(*(textptr+4)-'0'))); + + textptr += 5; + C_SkipSpace(); + } + else if (g_scriptVersion == 10) g_scriptVersion = 9; + + i = 0; + + while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) + { + tempbuf[i] = *textptr; + textptr++,i++; + if (EDUKE32_PREDICT_FALSE(i >= 32)) + { + Printf("%s:%d: warning: truncating level name to %d characters.\n", + g_scriptFileName,g_lineNumber,32); + g_warningCnt++; + C_NextLine(); + break; + } + } + + tempbuf[i] = '\0'; + + mapList[j *MAXLEVELS+k].name = tempbuf; + + continue; + + case CON_DEFINEQUOTE: + { + g_scriptPtr--; + + C_GetNextValue(LABEL_DEFINE); + + k = *(g_scriptPtr-1); + + if (EDUKE32_PREDICT_FALSE((unsigned)k >= MAXQUOTES)) + { + Printf("%s:%d: error: quote number exceeds limit of %d.\n",g_scriptFileName,g_lineNumber,MAXQUOTES); + g_errorCnt++; + } + else + { + C_AllocQuote(k); + } + + g_scriptPtr--; + + i = 0; + + C_SkipSpace(); + + buffer.Clear(); + while (*textptr != 0x0a && *textptr != 0x0d && *textptr != 0) + { + buffer.Push(*textptr); + textptr++; + } + buffer.Push(0); + quoteMgr.InitializeQuote(k, buffer.Data(), true); + continue; + } + case CON_DEFINESOUND: + { + int ps, pe, vo, pr, m; + + g_scriptPtr--; + C_GetNextValue(LABEL_DEFINE); + + // Ideally we could keep the value of i from C_GetNextValue() instead of having to hash_find() again. + // This depends on tempbuf remaining in place after C_GetNextValue(): + j = hash_find(&h_labels, tempbuf); + + k = g_scriptPtr[-1]; + if ((unsigned)k >= MAXSOUNDS - 1) + { + Printf("%s:%d: error: sound index exceeds limit of %d.\n", g_scriptFileName, g_lineNumber, MAXSOUNDS - 1); + g_errorCnt++; + k = MAXSOUNDS - 1; + } + /*else if (g_sounds[k].filename != NULL) + { + Printf("%s:%d: warning: sound %d already defined (%s)\n", g_scriptFileName, g_lineNumber, k, g_sounds[k].filename); + g_warningCnt++; + }*/ + + g_scriptPtr--; + i = 0; + C_SkipComments(); + + buffer.Clear(); + + if (*textptr == '\"') + { + textptr++; + while (*textptr && *textptr != '\"') + { + buffer.Push(*textptr++); + } + textptr++; + } + else while (*textptr != ' ' && *textptr != '\t' && *textptr != '\r' && *textptr != '\n') + { + buffer.Push(*textptr++); + } + buffer.Push(0); + + C_GetNextValue(LABEL_DEFINE); + ps = g_scriptPtr[-1]; + C_GetNextValue(LABEL_DEFINE); + pe = g_scriptPtr[-1]; + C_GetNextValue(LABEL_DEFINE); + pr = g_scriptPtr[-1]; + + C_GetNextValue(LABEL_DEFINE); + m = g_scriptPtr[-1]; + + C_GetNextValue(LABEL_DEFINE); + vo = g_scriptPtr[-1]; + g_scriptPtr -= 5; + + int res = S_DefineSound(k, buffer.Data(), ps, pe, pr, m, vo, 1.f); + + continue; + } + + case CON_ENDEVENT: + + if (EDUKE32_PREDICT_FALSE(!g_scriptEventOffset)) + { + C_ReportError(-1); + Printf("%s:%d: error: found `endevent' without open `onevent'.\n",g_scriptFileName,g_lineNumber); + g_errorCnt++; + } + if (EDUKE32_PREDICT_FALSE(g_numBraces != 0)) + { + C_ReportError(g_numBraces > 0 ? ERROR_OPENBRACKET : ERROR_CLOSEBRACKET); + g_errorCnt++; + } + + g_scriptEventOffset = g_parsingActorPtr = 0; + g_currentEvent = -1; + Bsprintf(g_szCurrentBlockName,"(none)"); + continue; + + case CON_ENDA: + if (EDUKE32_PREDICT_FALSE(!g_parsingActorPtr || g_scriptEventOffset)) + { + C_ReportError(-1); + Printf("%s:%d: error: found `enda' without open `actor'.\n",g_scriptFileName,g_lineNumber); + g_errorCnt++; + g_scriptEventOffset = 0; + } + if (EDUKE32_PREDICT_FALSE(g_numBraces != 0)) + { + C_ReportError(g_numBraces > 0 ? ERROR_OPENBRACKET : ERROR_CLOSEBRACKET); + g_errorCnt++; + } + g_parsingActorPtr = 0; + Bsprintf(g_szCurrentBlockName,"(none)"); + continue; + + case CON_BREAK: + continue; + + case CON_FALL: + case CON_TIP: + // case 21: + case CON_KILLIT: + case CON_RESETACTIONCOUNT: + case CON_PSTOMP: + case CON_RESETPLAYER: + case CON_RESETCOUNT: + case CON_WACKPLAYER: + case CON_OPERATE: + case CON_RESPAWNHITAG: + case CON_GETLASTPAL: + case CON_PKICK: + case CON_MIKESND: + case CON_TOSSWEAPON: + case CON_DESTROYIT: + case CON_LARRYBIRD: + case CON_STRAFELEFT: + case CON_STRAFERIGHT: + case CON_SLAPPLAYER: + case CON_TEARITUP: + case CON_SMACKBUBBA: + case CON_SOUNDTAGONCE: + case CON_SOUNDTAG: + case CON_SMACKSPRITE: + case CON_FAKEBUBBA: + case CON_MAMATRIGGER: + case CON_MAMASPAWN: + case CON_MAMAQUAKE: + case CON_MAMAEND: + case CON_GARYBANJO: + case CON_MOTOLOOPSND: + case CON_RNDMOVE: + case CON_LEAVETRAX: + case CON_LEAVEDROPPINGS: + case CON_DEPLOYBIAS: + continue; + + case CON_NULLOP: + if (EDUKE32_PREDICT_FALSE(C_GetKeyword() != CON_ELSE)) + { + C_ReportError(-1); + g_warningCnt++; + Printf("%s:%d: warning: `nullop' found without `else'\n",g_scriptFileName,g_lineNumber); + g_scriptPtr--; + g_skipBranch = 1; + } + continue; + + case CON_GAMESTARTUP: + { + int32_t params[34]; + + g_scriptPtr--; + for (j = 0; j < 34; j++) + { + C_GetNextValue(LABEL_DEFINE); + g_scriptPtr--; + params[j] = *g_scriptPtr; + + if (j != 29 && j != 30) continue; + + if (C_GetKeyword() != -1) + { + /*if (j == 12) + g_scriptVersion = 10; + else if (j == 21) + g_scriptVersion = 11; + else if (j == 25) + g_scriptVersion = 13; + else if (j == 29) + g_scriptVersion = 14;*/ + break; + } + /*else + g_scriptVersion = 16;*/ + } + + /* + v1.3d v1.5 + DEFAULTVISIBILITY DEFAULTVISIBILITY + GENERICIMPACTDAMAGE GENERICIMPACTDAMAGE + MAXPLAYERHEALTH MAXPLAYERHEALTH + STARTARMORHEALTH STARTARMORHEALTH + RESPAWNACTORTIME RESPAWNACTORTIME + RESPAWNITEMTIME RESPAWNITEMTIME + RUNNINGSPEED RUNNINGSPEED + RPGBLASTRADIUS GRAVITATIONALCONSTANT + PIPEBOMBRADIUS RPGBLASTRADIUS + SHRINKERBLASTRADIUS PIPEBOMBRADIUS + TRIPBOMBBLASTRADIUS SHRINKERBLASTRADIUS + MORTERBLASTRADIUS TRIPBOMBBLASTRADIUS + BOUNCEMINEBLASTRADIUS MORTERBLASTRADIUS + SEENINEBLASTRADIUS BOUNCEMINEBLASTRADIUS + MAXPISTOLAMMO SEENINEBLASTRADIUS + MAXSHOTGUNAMMO MAXPISTOLAMMO + MAXCHAINGUNAMMO MAXSHOTGUNAMMO + MAXRPGAMMO MAXCHAINGUNAMMO + MAXHANDBOMBAMMO MAXRPGAMMO + MAXSHRINKERAMMO MAXHANDBOMBAMMO + MAXDEVISTATORAMMO MAXSHRINKERAMMO + MAXTRIPBOMBAMMO MAXDEVISTATORAMMO + MAXFREEZEAMMO MAXTRIPBOMBAMMO + CAMERASDESTRUCTABLE MAXFREEZEAMMO + NUMFREEZEBOUNCES MAXGROWAMMO + FREEZERHURTOWNER CAMERASDESTRUCTABLE + NUMFREEZEBOUNCES + FREEZERHURTOWNER + QSIZE + TRIPBOMBLASERMODE + */ + + G_DoGameStartup(params); + } + continue; + } + } + while (loop); + + return 0; +} + +static char const * C_ScriptVersionString(int32_t version) +{ + switch (version) + { + case 9: + return ", v0.99 compatibility mode"; + case 10: + return ", v1.0 compatibility mode"; + case 11: + return ", v1.1 compatibility mode"; + case 13: + return ", v1.3D compatibility mode"; + default: + return ""; + } +} + +void C_PrintStats(void) +{ + Printf("%d/%d labels\n", g_labelCnt, + (int32_t) min((MAXSECTORS * sizeof(sectortype)/sizeof(int32_t)), + MAXSPRITES * sizeof(spritetype)/(1<<6))); + + int i, j; + + for (i=MAXTILES-1, j=0; i>=0; i--) + { + if (g_tile[i].execPtr) + j++; + } + if (j) Printf("%d actors", j); + + Printf("\n"); +} + +void C_Compile(const char *fileName) +{ + Bmemset(apScriptEvents, 0, sizeof(apScriptEvents)); + Bmemset(apScriptGameEventEnd, 0, sizeof(apScriptGameEventEnd)); + + for (int i=0; i> 3) + 1) * sizeof(uint8_t)); + // Printf("script: %d, bitptr: %d\n",script,bitptr); + + g_labelCnt = 0; + g_defaultLabelCnt = 0; + g_scriptPtr = apScript + 3; // move permits constants 0 and 1; moveptr[1] would be script[2] (reachable?) + g_warningCnt = 0; + g_errorCnt = 0; + g_lineNumber = 1; + g_totalLines = 0; + + Bstrcpy(g_scriptFileName, fileName); + + C_ParseCommand(1); + + if (userConfig.AddCons) for (FString & m : *userConfig.AddCons.get()) + { + C_Include(m); + } + userConfig.AddCons.reset(); + + if (g_errorCnt > 63) + Printf("fatal error: too many errors: Aborted\n"); + + //*script = (intptr_t) g_scriptPtr; + + DO_FREE_AND_NULL(mptr); + + if (g_warningCnt || g_errorCnt) + Printf("Found %d warning(s), %d error(s).\n", g_warningCnt, g_errorCnt); + + if (g_errorCnt) + { + Bsprintf(buf, "Error compiling CON files."); + G_GameExit(buf); + } + + g_totalLines += g_lineNumber; + + C_SetScriptSize(g_scriptPtr-apScript+8); + + Printf("Script compiled in %dms, %ld bytes%s\n", timerGetTicks() - startcompiletime, + (unsigned long)(g_scriptPtr-apScript), C_ScriptVersionString(g_scriptVersion)); + + for (auto *i : tables_free) + hash_free(i); + + //freehashnames(); + freesoundhashnames(); + + if (g_scriptDebug) + C_PrintStats(); + + C_InitQuotes(); +} + +void C_ReportError(int32_t iError) +{ + if (Bstrcmp(g_szCurrentBlockName,g_szLastBlockName)) + { + if (g_scriptEventOffset || g_processingState || g_parsingActorPtr) + Printf("%s: In %s `%s':\n",g_scriptFileName,g_scriptEventOffset?"event":g_parsingActorPtr?"actor":"state",g_szCurrentBlockName); + else Printf("%s: At top level:\n",g_scriptFileName); + Bstrcpy(g_szLastBlockName,g_szCurrentBlockName); + } + switch (iError) + { + case ERROR_CLOSEBRACKET: + Printf("%s:%d: error: found more `}' than `{' before `%s'.\n",g_scriptFileName,g_lineNumber,tempbuf); + break; + case ERROR_EXCEEDSMAXTILES: + Printf("%s:%d: error: `%s' value exceeds MAXTILES. Maximum is %d.\n",g_scriptFileName,g_lineNumber,tempbuf,MAXTILES-1); + break; + case ERROR_EXPECTEDKEYWORD: + Printf("%s:%d: error: expected a keyword but found `%s'.\n",g_scriptFileName,g_lineNumber,tempbuf); + break; + case ERROR_FOUNDWITHIN: + Printf("%s:%d: error: found `%s' within %s.\n",g_scriptFileName,g_lineNumber,tempbuf,g_parsingActorPtr?"an actor":"a state"); + break; + case ERROR_ISAKEYWORD: + Printf("%s:%d: error: symbol `%s' is a keyword.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6)); + break; + case ERROR_OPENBRACKET: + Printf("%s:%d: error: found more `{' than `}' before `%s'.\n",g_scriptFileName,g_lineNumber,tempbuf); + break; + case ERROR_NOTAGAMEVAR: + Printf("%s:%d: error: symbol `%s' is not a variable.\n",g_scriptFileName,g_lineNumber,LAST_LABEL); + break; + case ERROR_PARAMUNDEFINED: + Printf("%s:%d: error: parameter `%s' is undefined.\n",g_scriptFileName,g_lineNumber,tempbuf); + break; + case ERROR_SYNTAXERROR: + Printf("%s:%d: error: syntax error.\n",g_scriptFileName,g_lineNumber); + break; + case ERROR_VARREADONLY: + Printf("%s:%d: error: variable `%s' is read-only.\n",g_scriptFileName,g_lineNumber,LAST_LABEL); + break; + case ERROR_VARTYPEMISMATCH: + Printf("%s:%d: error: variable `%s' is of the wrong type.\n",g_scriptFileName,g_lineNumber,LAST_LABEL); + break; + case WARNING_BADGAMEVAR: + Printf("%s:%d: warning: variable `%s' should be either per-player OR per-actor, not both.\n",g_scriptFileName,g_lineNumber,LAST_LABEL); + break; + case WARNING_DUPLICATEDEFINITION: + Printf("%s:%d: warning: duplicate definition `%s' ignored.\n",g_scriptFileName,g_lineNumber,LAST_LABEL); + break; + case WARNING_LABELSONLY: + Printf("%s:%d: warning: expected a label, found a constant.\n",g_scriptFileName,g_lineNumber); + break; + case WARNING_VARMASKSKEYWORD: + Printf("%s:%d: warning: variable `%s' masks keyword.\n", g_scriptFileName, g_lineNumber, LAST_LABEL); + break; + } +} + +END_DUKE_NS diff --git a/source/duke/src/gamedef.h b/source/duke/src/gamedef.h new file mode 100644 index 000000000..22b5d28a2 --- /dev/null +++ b/source/duke/src/gamedef.h @@ -0,0 +1,354 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef gamedef_h_ +#define gamedef_h_ + +#include "actors.h" +#include "build.h" // hashtable_t +#include "cheats.h" +#include "common.h" // tokenlist +#include "player.h" // projectile_t + +BEGIN_DUKE_NS + +enum +{ + LABEL_ANY = -1, + LABEL_DEFINE = 1, + LABEL_STATE = 2, + LABEL_ACTOR = 4, + LABEL_ACTION = 8, + LABEL_AI = 16, + LABEL_MOVE = 32, + LABEL_EVENT = 0x40, +}; + +#define LABEL_HASPARM2 1 +#define LABEL_ISSTRING 2 + +// "magic" number for { and }, overrides line number in compiled code for later detection +#define VM_IFELSE_MAGIC 31337 +#define VM_INSTMASK 0xfff +#define VM_DECODE_LINE_NUMBER(xxx) ((int)((xxx) >> 12)) + +#define C_CUSTOMERROR(Text, ...) \ + do \ + { \ + C_ReportError(-1); \ + Printf("%s:%d: error: " Text "\n", g_scriptFileName, g_lineNumber, ##__VA_ARGS__); \ + g_errorCnt++; \ + } while (0) + +#define C_CUSTOMWARNING(Text, ...) \ + do \ + { \ + C_ReportError(-1); \ + Printf("%s:%d: warning: " Text "\n", g_scriptFileName, g_lineNumber, ##__VA_ARGS__); \ + g_warningCnt++; \ + } while (0) + +extern intptr_t const * insptr; +extern void VM_ScriptInfo(intptr_t const *ptr, int range); + +extern hashtable_t h_gamevars; +extern hashtable_t h_labels; + +extern int32_t g_aimAngleVarID; // var ID of "AUTOAIMANGLE" +extern int32_t g_angRangeVarID; // var ID of "ANGRANGE" +extern int32_t g_returnVarID; // var ID of "RETURN" +extern int32_t g_weaponVarID; // var ID of "WEAPON" +extern int32_t g_worksLikeVarID; // var ID of "WORKSLIKE" +extern int32_t g_zRangeVarID; // var ID of "ZRANGE" + +#include "events_defs.h" +extern intptr_t apScriptEvents[MAXEVENTS]; + +extern char g_scriptFileName[BMAX_PATH]; + +extern const uint32_t CheatFunctionFlags[]; +extern const uint8_t CheatFunctionIDs[]; + +extern int32_t g_errorCnt; +extern int32_t g_lineNumber; +extern int32_t g_scriptVersion; +extern int32_t g_totalLines; +extern int32_t g_warningCnt; +extern uint32_t g_scriptcrc; +extern int32_t otherp; + +extern intptr_t *g_scriptPtr; + +typedef struct +{ + const char *name; + int lId, flags, maxParm2; +} memberlabel_t; + +extern const memberlabel_t ActorLabels[]; +extern const memberlabel_t InputLabels[]; +extern const memberlabel_t PalDataLabels[]; +extern const memberlabel_t PlayerLabels[]; +extern const memberlabel_t ProjectileLabels[]; +extern const memberlabel_t SectorLabels[]; +extern const memberlabel_t TileDataLabels[]; +extern const memberlabel_t TsprLabels[]; +extern const memberlabel_t UserdefsLabels[]; +extern const memberlabel_t WallLabels[]; + +int32_t C_AllocQuote(int32_t qnum); +void C_InitQuotes(void); + +extern int32_t g_numProjectiles; + +typedef struct { + int spriteNum; + int playerNum; + int playerDist; + int flags; + + union { + spritetype * pSprite; + uspritetype *pUSprite; + }; + + int32_t * pData; + DukePlayer_t *pPlayer; + actor_t * pActor; +} vmstate_t; + +extern vmstate_t vm; + +void G_DoGameStartup(const int32_t *params); +void C_DefineMusic(int volumeNum, int levelNum, const char *fileName); + +void C_DefineVolumeFlags(int32_t vol, int32_t flags); +void C_UndefineVolume(int32_t vol); +void C_UndefineSkill(int32_t skill); +void C_UndefineLevel(int32_t vol, int32_t lev); +void C_ReportError(int32_t iError); +void C_Compile(const char *filenam); + +extern int32_t g_errorLineNum; +extern int32_t g_tw; + +typedef struct { + const char* token; + int32_t val; +} tokenmap_t; + +extern char const * VM_GetKeywordForID(int32_t id); + +enum ScriptError_t +{ + ERROR_CLOSEBRACKET, + ERROR_EXCEEDSMAXTILES, + ERROR_EXPECTEDKEYWORD, + ERROR_FOUNDWITHIN, + ERROR_ISAKEYWORD, + ERROR_OPENBRACKET, + ERROR_NOTAGAMEVAR, + ERROR_PARAMUNDEFINED, + ERROR_SYNTAXERROR, + ERROR_VARREADONLY, + ERROR_VARTYPEMISMATCH, + WARNING_BADGAMEVAR, + WARNING_DUPLICATEDEFINITION, + WARNING_LABELSONLY, + WARNING_VARMASKSKEYWORD, +}; + +enum ScriptKeywords_t +{ + CON_ELSE, // 0 + CON_ACTOR, // 1 + CON_ADDAMMO, // 2 + CON_IFRND, // 3 + CON_ENDA, // 4 + CON_IFCANSEE, // 5 + CON_IFHITWEAPON, // 6 + CON_ACTION, // 7 + CON_IFPDISTL, // 8 + CON_IFPDISTG, // 9 + CON_DEFINELEVELNAME, // 10 + CON_STRENGTH, // 11 + CON_BREAK, // 12 + CON_SHOOT, // 13 + CON_PALFROM, // 14 + CON_SOUND, // 15 + CON_FALL, // 16 + CON_STATE, // 17 + CON_ENDS, // 18 + CON_DEFINE, // 19 + CON_COMMENT, // 20 deprecated + CON_IFAI, // 21 + CON_KILLIT, // 22 + CON_ADDWEAPON, // 23 + CON_AI, // 24 + CON_ADDPHEALTH, // 25 + CON_IFDEAD, // 26 + CON_IFSQUISHED, // 27 + CON_SIZETO, // 28 + CON_LEFTBRACE, // 29 + CON_RIGHTBRACE, // 30 + CON_SPAWN, // 31 + CON_MOVE, // 32 + CON_IFWASWEAPON, // 33 + CON_IFACTION, // 34 + CON_IFACTIONCOUNT, // 35 + CON_RESETACTIONCOUNT, // 36 + CON_DEBRIS, // 37 + CON_PSTOMP, // 38 + CON_BLOCKCOMMENT, // 39 deprecated + CON_CSTAT, // 40 + CON_IFMOVE, // 41 + CON_RESETPLAYER, // 42 + CON_IFONWATER, // 43 + CON_IFINWATER, // 44 + CON_IFCANSHOOTTARGET, // 45 + CON_IFCOUNT, // 46 + CON_RESETCOUNT, // 47 + CON_ADDINVENTORY, // 48 + CON_IFACTORNOTSTAYPUT, // 49 + CON_HITRADIUS, // 50 + CON_IFP, // 51 + CON_COUNT, // 52 + CON_IFACTOR, // 53 + CON_MUSIC, // 54 + CON_INCLUDE, // 55 + CON_IFSTRENGTH, // 56 + CON_DEFINESOUND, // 57 + CON_GUTS, // 58 + CON_IFSPAWNEDBY, // 59 + CON_GAMESTARTUP, // 60 + CON_WACKPLAYER, // 61 + CON_IFGAPZL, // 62 + CON_IFHITSPACE, // 63 + CON_IFOUTSIDE, // 64 + CON_IFMULTIPLAYER, // 65 + CON_OPERATE, // 66 + CON_IFINSPACE, // 67 + CON_DEBUG, // 68 + CON_ENDOFGAME, // 69 + CON_IFBULLETNEAR, // 70 + CON_IFRESPAWN, // 71 + CON_IFFLOORDISTL, // 72 + CON_IFCEILINGDISTL, // 73 + CON_SPRITEPAL, // 74 + CON_IFPINVENTORY, // 75 + CON_BETANAME, // 76 + CON_CACTOR, // 77 + CON_IFPHEALTHL, // 78 + CON_DEFINEQUOTE, // 79 + CON_QUOTE, // 80 + CON_IFINOUTERSPACE, // 81 + CON_IFNOTMOVING, // 82 + CON_RESPAWNHITAG, // 83 + CON_TIP, // 84 + CON_IFSPRITEPAL, // 85 + CON_MONEY, // 86 + CON_SOUNDONCE, // 87 + CON_ADDKILLS, // 88 + CON_STOPSOUND, // 89 + CON_IFAWAYFROMWALL, // 90 + CON_IFCANSEETARGET, // 91 + CON_GLOBALSOUND, // 92 + CON_LOTSOFGLASS, // 93 + CON_IFGOTWEAPONCE, // 94 + CON_GETLASTPAL, // 95 + CON_PKICK, // 96 + CON_MIKESND, // 97 + CON_USERACTOR, // 98 + CON_SIZEAT, // 99 + CON_ADDSTRENGTH, // 100 + CON_CSTATOR, // 101 + CON_MAIL, // 102 + CON_PAPER, // 103 + CON_TOSSWEAPON, // 104 + CON_SLEEPTIME, // 105 + CON_NULLOP, // 106 + CON_DEFINEVOLUMENAME, // 107 + CON_DEFINESKILLNAME, // 108 + CON_IFNOSOUNDS, // 109 + CON_CLIPDIST, // 110 + CON_IFANGDIFFL, // 111 + CON_IFNOCOVER, // 112 + CON_IFHITTRUCK, // 113 + CON_IFTIPCOW, // 114 + CON_ISDRUNK, // 115 + CON_ISEAT, // 116 + CON_DESTROYIT, // 117 + CON_LARRYBIRD, // 118 + CON_STRAFELEFT, // 119 + CON_STRAFERIGHT, // 120 + CON_IFACTORHEALTHG, // 121 + CON_IFACTORHEALTHL, // 122 + CON_SLAPPLAYER, // 123 + CON_IFPDRUNK, // 124 + CON_TEARITUP, // 125 + CON_SMACKBUBBA, // 126 + CON_SOUNDTAGONCE, // 127 + CON_SOUNDTAG, // 128 + CON_IFSOUNDID, // 129 + CON_IFSOUNDDIST, // 130 + CON_IFONMUD, // 131 + CON_IFCOOP, // 132 + CON_IFMOTOFAST, // 133 + CON_IFWIND, // 134 + CON_SMACKSPRITE, // 135 + CON_IFONMOTO, // 136 + CON_IFONBOAT, // 137 + CON_FAKEBUBBA, // 138 + CON_MAMATRIGGER, // 139 + CON_MAMASPAWN, // 140 + CON_MAMAQUAKE, // 141 + CON_MAMAEND, // 142 + CON_NEWPIC, // 143 + CON_GARYBANJO, // 144 + CON_MOTOLOOPSND, // 145 + CON_IFSIZEDOWN, // 146 + CON_RNDMOVE, // 147 + CON_GAMEVAR, // 148 + CON_IFVARL, // 149 + CON_IFVARG, // 150 + CON_SETVARVAR, // 151 + CON_SETVAR, // 152 + CON_ADDVARVAR, // 153 + CON_ADDVAR, // 154 + CON_IFVARVARL, // 155 + CON_IFVARVARG, // 156 + CON_ADDLOGVAR, // 157 + CON_ONEVENT, // 158 + CON_ENDEVENT, // 159 + CON_IFVARE, // 160 + CON_IFVARVARE, // 161 + CON_IFFINDNEWSPOT, // 162 + CON_LEAVETRAX, // 163 + CON_LEAVEDROPPINGS, // 164 + CON_DEPLOYBIAS, // 165 + CON_IFPUPWIND, // 166 + CON_END +}; + +END_DUKE_NS + +#endif // gamedef_h_ diff --git a/source/duke/src/gamedefs.h b/source/duke/src/gamedefs.h new file mode 100644 index 000000000..e69de29bb diff --git a/source/duke/src/gameexec.cpp b/source/duke/src/gameexec.cpp new file mode 100644 index 000000000..c3c2f7037 --- /dev/null +++ b/source/duke/src/gameexec.cpp @@ -0,0 +1,2988 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! + +#include "compat.h" + +#include "duke3d.h" + +#include "anim.h" + +#include "menus.h" +#include "osdcmds.h" +#include "savegame.h" +#include "gamecvars.h" +#include "version.h" + +#include "debugbreak.h" + +BEGIN_DUKE_NS + +#if KRANDDEBUG +# define GAMEEXEC_INLINE +# define GAMEEXEC_STATIC +#else +# define GAMEEXEC_INLINE inline +# define GAMEEXEC_STATIC static +#endif + +vmstate_t vm; + +enum vmflags_t +{ + VM_RETURN = 0x00000001, + VM_KILL = 0x00000002, + VM_NOEXECUTE = 0x00000004, + VM_SAFEDELETE = 0x00000008 +}; + +int32_t g_tw; +int32_t g_currentEvent = -1; +int32_t g_errorLineNum; + +intptr_t const *insptr; + +int32_t g_returnVarID = -1; // var ID of "RETURN" +int32_t g_weaponVarID = -1; // var ID of "WEAPON" +int32_t g_worksLikeVarID = -1; // var ID of "WORKSLIKE" +int32_t g_zRangeVarID = -1; // var ID of "ZRANGE" +int32_t g_angRangeVarID = -1; // var ID of "ANGRANGE" +int32_t g_aimAngleVarID = -1; // var ID of "AUTOAIMANGLE" + +// for timing events and actors +uint32_t g_actorCalls[MAXTILES]; +double g_actorTotalMs[MAXTILES], g_actorMinMs[MAXTILES], g_actorMaxMs[MAXTILES]; + +GAMEEXEC_STATIC void VM_Execute(native_t loop); + +#define VM_CONDITIONAL(xxx) \ + { \ + if ((xxx) || ((insptr = (intptr_t *)*(insptr + 1)) && (((*insptr) & VM_INSTMASK) == CON_ELSE))) \ + { \ + insptr += 2; \ + VM_Execute(0); \ + } \ + } + +void VM_ScriptInfo(intptr_t const *ptr, int range) +{ + if (!apScript || (!vm.pSprite && !vm.pPlayer)) + return; + + if (ptr) + { + Printf("\n"); + + for (auto pScript = max(ptr - (range >> 1), apScript), + p_end = min(ptr + (range >> 1), apScript + g_scriptSize); + pScript < p_end; + ++pScript) + { + Printf("%5d: %3d: ", (int32_t)(pScript - apScript), (int32_t)(pScript - ptr)); + + if (*pScript >> 12 && (*pScript & VM_INSTMASK) < CON_END) + Printf("%5d %s\n", (int32_t)(*pScript >> 12), VM_GetKeywordForID(*pScript & VM_INSTMASK)); + else + Printf("%d\n", (int32_t)*pScript); + } + + Printf("\n"); + } + + if (ptr == insptr) + { + if (vm.pUSprite) + Printf("current actor: %d (%d)\n", vm.spriteNum, vm.pUSprite->picnum); + + Printf("g_errorLineNum: %d, g_tw: %d\n", g_errorLineNum, g_tw); + } +} + +static void VM_DeleteSprite(int const spriteNum, int const playerNum) +{ + if (EDUKE32_PREDICT_FALSE((unsigned) spriteNum >= MAXSPRITES)) + return; + + // if player was set to squish, first stop that... + if (EDUKE32_PREDICT_FALSE(playerNum >= 0 && g_player[playerNum].ps->actorsqu == spriteNum)) + g_player[playerNum].ps->actorsqu = -1; + + A_DeleteSprite(spriteNum); +} + +intptr_t apScriptEvents[MAXEVENTS]; +static uspritetype dummy_sprite; +static actor_t dummy_actor; + +static inline void VM_DummySprite(void) +{ + vm.pUSprite = &dummy_sprite; + vm.pActor = &dummy_actor; + vm.pData = &dummy_actor.t_data[0]; +} + +// verification that the event actually exists happens elsewhere +static FORCE_INLINE int32_t VM_EventInlineInternal__(int const eventNum, int const spriteNum, int const playerNum, + int const playerDist = -1, int32_t returnValue = 0) +{ + vmstate_t const newVMstate = { spriteNum, playerNum, playerDist, 0, + &sprite[spriteNum&(MAXSPRITES-1)], + &actor[spriteNum&(MAXSPRITES-1)].t_data[0], + g_player[playerNum&(MAXPLAYERS-1)].ps, + &actor[spriteNum&(MAXSPRITES-1)] }; + + auto &globalReturn = aGameVars[g_returnVarID].global; + + struct + { + vmstate_t vm; + intptr_t globalReturn; + int eventNum; + intptr_t const *insptr; + } const saved = { vm, globalReturn, g_currentEvent, insptr }; + + vm = newVMstate; + g_currentEvent = eventNum; + insptr = apScript + apScriptEvents[eventNum]; + globalReturn = returnValue; + + double const t = timerGetHiTicks(); + + if ((unsigned)spriteNum >= MAXSPRITES) + VM_DummySprite(); + + if ((unsigned)playerNum >= (unsigned)g_mostConcurrentPlayers) + vm.pPlayer = g_player[0].ps; + + VM_Execute(true); + + if (vm.flags & VM_KILL) + VM_DeleteSprite(vm.spriteNum, vm.playerNum); + + // restoring these needs to happen after VM_DeleteSprite() due to event recursion + returnValue = globalReturn; + + vm = saved.vm; + globalReturn = saved.globalReturn; + g_currentEvent = saved.eventNum; + insptr = saved.insptr; + + return returnValue; +} + +// the idea here is that the compiler inlines the call to VM_EventInlineInternal__() and gives us a set of +// functions which are optimized further based on distance/return having values known at compile time + +int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum, int const nDist, int32_t const nReturn) +{ + return VM_EventInlineInternal__(nEventID, spriteNum, playerNum, nDist, nReturn); +} + +int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum, int const nDist) +{ + return VM_EventInlineInternal__(nEventID, spriteNum, playerNum, nDist); +} + +int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum) +{ + return VM_EventInlineInternal__(nEventID, spriteNum, playerNum); +} + +int32_t VM_ExecuteEventWithValue(int const nEventID, int const spriteNum, int const playerNum, int32_t const nReturn) +{ + return VM_EventInlineInternal__(nEventID, spriteNum, playerNum, -1, nReturn); +} + +static int32_t VM_CheckSquished(void) +{ + if (RR) + return 0; + + usectortype const * const pSector = (usectortype *)§or[vm.pSprite->sectnum]; + + if (pSector->lotag == ST_23_SWINGING_DOOR || + (vm.pSprite->picnum == APLAYER && ud.noclip)) + return 0; + + int32_t floorZ = pSector->floorz; + int32_t ceilZ = pSector->ceilingz; +#ifdef YAX_ENABLE + int16_t cb, fb; + + yax_getbunches(vm.pSprite->sectnum, &cb, &fb); + + if (cb >= 0 && (pSector->ceilingstat&512)==0) // if ceiling non-blocking... + ceilZ -= ZOFFSET5; // unconditionally don't squish... yax_getneighborsect is slowish :/ + if (fb >= 0 && (pSector->floorstat&512)==0) + floorZ += ZOFFSET5; +#endif + + if (vm.pSprite->pal == 1 ? (floorZ - ceilZ >= ZOFFSET5 || (pSector->lotag & 32768u)) : (floorZ - ceilZ >= ZOFFSET4)) + return 0; + + P_DoQuote(QUOTE_SQUISHED, vm.pPlayer); + + if (A_CheckEnemySprite(vm.pSprite)) + vm.pSprite->xvel = 0; + + if (EDUKE32_PREDICT_FALSE(vm.pSprite->pal == 1)) // frozen + { + vm.pActor->picnum = SHOTSPARK1; + vm.pActor->extra = 1; + return 0; + } + + return 1; +} + +GAMEEXEC_STATIC GAMEEXEC_INLINE void P_ForceAngle(DukePlayer_t *pPlayer) +{ + int const nAngle = 128-(krand2()&255); + + pPlayer->q16horiz += F16(64); + pPlayer->return_to_center = 9; + pPlayer->q16rotscrnang = fix16_from_int(nAngle >> 1); + pPlayer->q16look_ang = pPlayer->q16rotscrnang; +} + +// wow, this function sucks +int32_t A_Dodge(spritetype * const); +int32_t A_Dodge(spritetype * const pSprite) +{ + if (DEER) + { + pSprite->ang += ((rrdh_random() & 255) - 127) * 2; + pSprite->ang &= 2047; + return 0; + } + vec2_t const msin = { sintable[(pSprite->ang + 512) & 2047], sintable[pSprite->ang & 2047] }; + + for (native_t nexti, SPRITES_OF_STAT_SAFE(STAT_PROJECTILE, i, nexti)) //weapons list + { + if (OW(i) == i || SECT(i) != pSprite->sectnum) + continue; + + vec2_t const b = { SX(i) - pSprite->x, SY(i) - pSprite->y }; + vec2_t const v = { sintable[(SA(i) + 512) & 2047], sintable[SA(i) & 2047] }; + + if (((msin.x * b.x) + (msin.y * b.y) >= 0) && ((v.x * b.x) + (v.y * b.y) < 0)) + { + if (klabs((v.x * b.y) - (v.y * b.x)) < 65536 << 6) + { + pSprite->ang -= 512+(krand2()&1024); + return 1; + } + } + } + + return 0; +} + +int32_t A_GetFurthestAngle(int const spriteNum, int const angDiv) +{ + uspritetype *const pSprite = (uspritetype *)&sprite[spriteNum]; + + if (pSprite->picnum != APLAYER && (AC_COUNT(actor[spriteNum].t_data)&63) > 2) + return pSprite->ang + 1024; + + int32_t furthestAngle = 0; + int32_t greatestDist = INT32_MIN; + int const angIncs = tabledivide32_noinline(2048, angDiv); + hitdata_t hit; + + for (native_t j = pSprite->ang; j < (2048 + pSprite->ang); j += angIncs) + { + pSprite->z -= ZOFFSET3; + hitscan((const vec3_t *)pSprite, pSprite->sectnum, sintable[(j + 512) & 2047], sintable[j & 2047], 0, &hit, CLIPMASK1); + pSprite->z += ZOFFSET3; + + int const hitDist = klabs(hit.pos.x-pSprite->x) + klabs(hit.pos.y-pSprite->y); + + if (hitDist > greatestDist) + { + greatestDist = hitDist; + furthestAngle = j; + } + } + + return furthestAngle&2047; +} + +int A_FurthestVisiblePoint(int const spriteNum, uspritetype * const ts, vec2_t * const vect) +{ + if (AC_COUNT(actor[spriteNum].t_data)&63) + return -1; + + const uspritetype *const pnSprite = (uspritetype *)&sprite[spriteNum]; + + hitdata_t hit; + int const angincs = ((!g_netServer && ud.multimode < 2) && ud.player_skill < 3) ? 2048 / 2 : tabledivide32_noinline(2048, 1 + (krand2() & 1)); + + for (native_t j = ts->ang; j < (2048 + ts->ang); j += (angincs-(krand2()&511))) + { + ts->z -= ZOFFSET2; + hitscan((const vec3_t *)ts, ts->sectnum, sintable[(j + 512) & 2047], sintable[j & 2047], 16384 - (krand2() & 32767), &hit, CLIPMASK1); + ts->z += ZOFFSET2; + + if (hit.sect < 0) + continue; + + int const d = klabs(hit.pos.x - ts->x) + klabs(hit.pos.y - ts->y); + int const da = klabs(hit.pos.x - pnSprite->x) + klabs(hit.pos.y - pnSprite->y); + + if (d < da) + { + if (cansee(hit.pos.x, hit.pos.y, hit.pos.z, hit.sect, pnSprite->x, pnSprite->y, pnSprite->z - ZOFFSET2, pnSprite->sectnum)) + { + vect->x = hit.pos.x; + vect->y = hit.pos.y; + return hit.sect; + } + } + } + + return -1; +} + +static void VM_GetZRange(int const spriteNum, int32_t * const ceilhit, int32_t * const florhit, int const wallDist) +{ + uspritetype *const pSprite = (uspritetype *)&sprite[spriteNum]; + vec3_t const tempVect = { + pSprite->x, pSprite->y, pSprite->z - ZOFFSET + }; + getzrange(&tempVect, pSprite->sectnum, &actor[spriteNum].ceilingz, ceilhit, &actor[spriteNum].floorz, florhit, wallDist, CLIPMASK0); +} + +void A_GetZLimits(int const spriteNum) +{ + spritetype *const pSprite = &sprite[spriteNum]; + int32_t ceilhit, florhit; + + if (pSprite->statnum == STAT_PLAYER || pSprite->statnum == STAT_STANDABLE || pSprite->statnum == STAT_ZOMBIEACTOR + || pSprite->statnum == STAT_ACTOR || pSprite->statnum == STAT_PROJECTILE) + { + VM_GetZRange(spriteNum, &ceilhit, &florhit, (pSprite->statnum == STAT_PROJECTILE) ? 4 : 127); + actor[spriteNum].flags &= ~SFLAG_NOFLOORSHADOW; + + if ((florhit&49152) == 49152 && (sprite[florhit&(MAXSPRITES-1)].cstat&48) == 0) + { + uspritetype const * const hitspr = (uspritetype *)&sprite[florhit&(MAXSPRITES-1)]; + + florhit &= (MAXSPRITES-1); + + // If a non-projectile would fall onto non-frozen enemy OR an enemy onto a player... + if ((A_CheckEnemySprite(hitspr) && hitspr->pal != 1 && pSprite->statnum != STAT_PROJECTILE) + || (hitspr->picnum == APLAYER && A_CheckEnemySprite(pSprite))) + { + actor[spriteNum].flags |= SFLAG_NOFLOORSHADOW; // No shadows on actors + pSprite->xvel = -256; // SLIDE_ABOVE_ENEMY + A_SetSprite(spriteNum, CLIPMASK0); + } + else if (pSprite->statnum == STAT_PROJECTILE && hitspr->picnum == APLAYER && pSprite->owner==florhit) + { + actor[spriteNum].ceilingz = sector[pSprite->sectnum].ceilingz; + actor[spriteNum].floorz = sector[pSprite->sectnum].floorz; + } + } + } + else + { + actor[spriteNum].ceilingz = sector[pSprite->sectnum].ceilingz; + actor[spriteNum].floorz = sector[pSprite->sectnum].floorz; + } +} + +void A_Fall(int const spriteNum) +{ + spritetype *const pSprite = &sprite[spriteNum]; + int spriteGravity = g_spriteGravity; + + if (EDUKE32_PREDICT_FALSE(G_CheckForSpaceFloor(pSprite->sectnum))) + spriteGravity = 0; + else if (sector[pSprite->sectnum].lotag == ST_2_UNDERWATER || EDUKE32_PREDICT_FALSE(G_CheckForSpaceCeiling(pSprite->sectnum))) + spriteGravity = g_spriteGravity/6; + + if (RRRA && spriteGravity == g_spriteGravity) + { + if (pSprite->picnum == BIKERB || pSprite->picnum == CHEERB) + spriteGravity >>= 2; + else if (pSprite->picnum == BIKERBV2) + spriteGravity >>= 3; + } + + if (pSprite->statnum == STAT_ACTOR || pSprite->statnum == STAT_PLAYER || pSprite->statnum == STAT_ZOMBIEACTOR + || pSprite->statnum == STAT_STANDABLE) + { + int32_t ceilhit, florhit; + VM_GetZRange(spriteNum, &ceilhit, &florhit, 127); + } + else + { + actor[spriteNum].ceilingz = sector[pSprite->sectnum].ceilingz; + actor[spriteNum].floorz = sector[pSprite->sectnum].floorz; + } + +#ifdef YAX_ENABLE + int fbunch = (sector[pSprite->sectnum].floorstat&512) ? -1 : yax_getbunch(pSprite->sectnum, YAX_FLOOR); +#endif + + if (pSprite->z < actor[spriteNum].floorz-ZOFFSET +#ifdef YAX_ENABLE + || fbunch >= 0 +#endif + ) + { + if (sector[pSprite->sectnum].lotag == ST_2_UNDERWATER && pSprite->zvel > 3122) + pSprite->zvel = 3144; + if (pSprite->zvel < 6144) + pSprite->zvel += spriteGravity; + else pSprite->zvel = 6144; + pSprite->z += pSprite->zvel; + } + +#ifdef YAX_ENABLE + if (fbunch >= 0) + setspritez(spriteNum, (vec3_t *)pSprite); + else +#endif + if (pSprite->z >= actor[spriteNum].floorz-ZOFFSET) + { + pSprite->z = actor[spriteNum].floorz-ZOFFSET; + pSprite->zvel = 0; + } +} + +int32_t __fastcall G_GetAngleDelta(int32_t currAngle, int32_t newAngle) +{ + currAngle &= 2047; + newAngle &= 2047; + + if (klabs(currAngle-newAngle) < 1024) + { +// Printf("G_GetAngleDelta() returning %d\n",na-a); + return newAngle-currAngle; + } + + if (newAngle > 1024) + newAngle -= 2048; + if (currAngle > 1024) + currAngle -= 2048; + +// Printf("G_GetAngleDelta() returning %d\n",na-a); + return newAngle-currAngle; +} + +fix16_t __fastcall G_GetQ16AngleDelta(fix16_t oldAngle, fix16_t newAngle) +{ + if (fix16_abs(fix16_sub(oldAngle, newAngle)) < fix16_from_int(1024)) + return fix16_sub(newAngle, oldAngle); + + if (newAngle > fix16_from_int(1024)) + newAngle = fix16_sub(newAngle, fix16_from_int(2048)); + + if (oldAngle > fix16_from_int(1024)) + oldAngle = fix16_sub(oldAngle, fix16_from_int(2048)); + + return fix16_sub(newAngle, oldAngle); +} + +GAMEEXEC_STATIC void VM_AlterAng(int32_t const moveFlags) +{ + int const elapsedTics = (AC_COUNT(vm.pData))&31; + + const intptr_t *moveptr; + if (EDUKE32_PREDICT_FALSE((unsigned)AC_MOVE_ID(vm.pData) >= (unsigned)g_scriptSize-1)) + + { + AC_MOVE_ID(vm.pData) = 0; + Printf(TEXTCOLOR_RED "bad moveptr for actor %d (%d)!\n", vm.spriteNum, vm.pUSprite->picnum); + return; + } + + moveptr = apScript + AC_MOVE_ID(vm.pData); + + vm.pSprite->xvel += (moveptr[0] - vm.pSprite->xvel)/5; + if (vm.pSprite->zvel < 648) + vm.pSprite->zvel += ((moveptr[1]<<4) - vm.pSprite->zvel)/5; + + if (RRRA && (moveFlags&windang)) + vm.pSprite->ang = g_windDir; + else if (moveFlags&seekplayer) + { + int const spriteAngle = vm.pSprite->ang; + int const holoDukeSprite = vm.pPlayer->holoduke_on; + + // NOTE: looks like 'owner' is set to target sprite ID... + + vm.pSprite->owner = (!RR && holoDukeSprite >= 0 + && cansee(sprite[holoDukeSprite].x, sprite[holoDukeSprite].y, sprite[holoDukeSprite].z, sprite[holoDukeSprite].sectnum, + vm.pSprite->x, vm.pSprite->y, vm.pSprite->z, vm.pSprite->sectnum)) + ? holoDukeSprite + : vm.pPlayer->i; + + int const goalAng = (sprite[vm.pSprite->owner].picnum == APLAYER) + ? getangle(vm.pActor->lastv.x - vm.pSprite->x, vm.pActor->lastv.y - vm.pSprite->y) + : getangle(sprite[vm.pSprite->owner].x - vm.pSprite->x, sprite[vm.pSprite->owner].y - vm.pSprite->y); + + if (vm.pSprite->xvel && vm.pSprite->picnum != DRONE) + { + int const angDiff = G_GetAngleDelta(spriteAngle, goalAng); + + if (elapsedTics < 2) + { + if (klabs(angDiff) < 256) + { + int const angInc = 128-(krand2()&256); + vm.pSprite->ang += angInc; + if (A_GetHitscanRange(vm.spriteNum) < 844) + vm.pSprite->ang -= angInc; + } + } + else if (elapsedTics > 18 && elapsedTics < GAMETICSPERSEC) // choose + { + if (klabs(angDiff >> 2) < 128) + vm.pSprite->ang = goalAng; + else + vm.pSprite->ang += angDiff >> 2; + } + } + else + vm.pSprite->ang = goalAng; + } + + if (elapsedTics < 1) + { + if (moveFlags&furthestdir) + { + vm.pSprite->ang = A_GetFurthestAngle(vm.spriteNum, 2); + vm.pSprite->owner = vm.pPlayer->i; + } + + if (moveFlags&fleeenemy) + vm.pSprite->ang = A_GetFurthestAngle(vm.spriteNum, 2); + } +} + +static inline void VM_AddAngle(int const shift, int const goalAng) +{ + int angDiff = G_GetAngleDelta(vm.pSprite->ang, goalAng) >> shift; + + if (angDiff > -8 && angDiff < 0) + angDiff = 0; + + vm.pSprite->ang += angDiff; +} + +static inline void VM_FacePlayer(int const shift) +{ + VM_AddAngle(shift, (vm.pPlayer->newowner >= 0) ? getangle(vm.pPlayer->opos.x - vm.pSprite->x, vm.pPlayer->opos.y - vm.pSprite->y) + : getangle(vm.pPlayer->pos.x - vm.pSprite->x, vm.pPlayer->pos.y - vm.pSprite->y)); +} + +////////// TROR get*zofslope ////////// +// These rather belong into the engine. + +static int32_t VM_GetCeilZOfSlope(void) +{ + vec2_t const vect = *(vec2_t *)vm.pSprite; + int const sectnum = vm.pSprite->sectnum; + +#ifdef YAX_ENABLE + if ((sector[sectnum].ceilingstat&512)==0) + { + int const nsect = yax_getneighborsect(vect.x, vect.y, sectnum, YAX_CEILING); + if (nsect >= 0) + return getceilzofslope(nsect, vect.x, vect.y); + } +#endif + return getceilzofslope(sectnum, vect.x, vect.y); +} + +static int32_t VM_GetFlorZOfSlope(void) +{ + vec2_t const vect = *(vec2_t *)vm.pSprite; + int const sectnum = vm.pSprite->sectnum; + +#ifdef YAX_ENABLE + if ((sector[sectnum].floorstat&512)==0) + { + int const nsect = yax_getneighborsect(vect.x, vect.y, sectnum, YAX_FLOOR); + if (nsect >= 0) + return getflorzofslope(nsect, vect.x, vect.y); + } +#endif + return getflorzofslope(sectnum, vect.x, vect.y); +} + +//////////////////// + +static int32_t A_GetWaterZOffset(int spritenum); + +GAMEEXEC_STATIC void VM_Move(void) +{ + auto const movflagsptr = &AC_MOVFLAGS(vm.pSprite, &actor[vm.spriteNum]); + // NOTE: test against -1 commented out and later revived in source history + // XXX: Does its presence/absence break anything? Where are movflags with all bits set created? + int const movflags = (*movflagsptr == (std::remove_pointer::type)-1) ? 0 : *movflagsptr; + + AC_COUNT(vm.pData)++; + + if (movflags&face_player) + VM_FacePlayer(2); + + if (movflags&spin) + vm.pSprite->ang += sintable[((AC_COUNT(vm.pData)<<3)&2047)]>>6; + + if (movflags&face_player_slow) + { + int const goalAng = (vm.pPlayer->newowner >= 0) ? getangle(vm.pPlayer->opos.x - vm.pSprite->x, vm.pPlayer->opos.y - vm.pSprite->y) + : getangle(vm.pPlayer->pos.x - vm.pSprite->x, vm.pPlayer->pos.y - vm.pSprite->y); + + vm.pSprite->ang += ksgn(G_GetAngleDelta(vm.pSprite->ang, goalAng)) << 5; + } + + if (RRRA && (movflags&antifaceplayerslow)) + { + int goalAng = (vm.pPlayer->newowner >= 0) ? getangle(vm.pPlayer->opos.x - vm.pSprite->x, vm.pPlayer->opos.y - vm.pSprite->y) + : getangle(vm.pPlayer->pos.x - vm.pSprite->x, vm.pPlayer->pos.y - vm.pSprite->y); + goalAng = (goalAng+1024)&2047; + + vm.pSprite->ang += ksgn(G_GetAngleDelta(vm.pSprite->ang, goalAng)) << 5; + } + + if ((movflags&jumptoplayer_bits) == jumptoplayer_bits) + { + if (AC_COUNT(vm.pData) < 16) + vm.pSprite->zvel -= (!DEER && RRRA && vm.pSprite->picnum == CHEER) ? (sintable[(512+(AC_COUNT(vm.pData)<<4))&2047]/40) + : (sintable[(512+(AC_COUNT(vm.pData)<<4))&2047]>>5); + } + + if (movflags&face_player_smart) + { + vec2_t const vect = { vm.pPlayer->pos.x + (vm.pPlayer->vel.x / 768), vm.pPlayer->pos.y + (vm.pPlayer->vel.y / 768) }; + VM_AddAngle(2, getangle(vect.x - vm.pSprite->x, vect.y - vm.pSprite->y)); + } + + if (RRRA && (vm.pSprite->picnum == RABBIT || vm.pSprite->picnum == MAMA)) + { + if(movflags&jumptoplayer_only) + { + if (AC_COUNT(vm.pData) < 8) + vm.pSprite->zvel -= sintable[(512+(AC_COUNT(vm.pData)<<4))&2047]/(vm.pSprite->picnum == RABBIT ? 30 : 35); + } + if(movflags&justjump2) + { + if (AC_COUNT(vm.pData) < 8) + vm.pSprite->zvel -= sintable[(512+(AC_COUNT(vm.pData)<<4))&2047]/(vm.pSprite->picnum == RABBIT ? 24 : 28); + } + } + + if (RRRA && (movflags&windang)) + { + if (AC_COUNT(vm.pData) < 8) + vm.pSprite->zvel -= sintable[(512+(AC_COUNT(vm.pData)<<4))&2047]/24; + } + + if (AC_MOVE_ID(vm.pData) == 0 || movflags == 0) + { + if ((A_CheckEnemySprite(vm.pSprite) && vm.pSprite->extra <= 0) || (vm.pActor->bpos.x != vm.pSprite->x) || (vm.pActor->bpos.y != vm.pSprite->y)) + { + vm.pActor->bpos.x = vm.pSprite->x; + vm.pActor->bpos.y = vm.pSprite->y; + setsprite(vm.spriteNum, (vec3_t *)vm.pSprite); + } + if (RR && A_CheckEnemySprite(vm.pSprite) && vm.pSprite->extra <= 0) + { + vm.pSprite->shade += (sector[vm.pSprite->sectnum].ceilingstat & 1) ? ((g_shadedSector[vm.pSprite->sectnum] == 1 ? 16 : sector[vm.pSprite->sectnum].ceilingshade) - vm.pSprite->shade) >> 1 + : (sector[vm.pSprite->sectnum].floorshade - vm.pSprite->shade) >> 1; + } + return; + } + + if (EDUKE32_PREDICT_FALSE((unsigned)AC_MOVE_ID(vm.pData) >= (unsigned)g_scriptSize-1)) + { + AC_MOVE_ID(vm.pData) = 0; + Printf(TEXTCOLOR_RED "clearing bad moveptr for actor %d (%d)\n", vm.spriteNum, vm.pUSprite->picnum); + return; + } + + intptr_t const * const moveptr = apScript + AC_MOVE_ID(vm.pData); + + if (movflags & geth) + vm.pSprite->xvel += ((moveptr[0]) - vm.pSprite->xvel) >> 1; + if (movflags & getv) + vm.pSprite->zvel += ((moveptr[1] << 4) - vm.pSprite->zvel) >> 1; + + if (movflags&dodgebullet) + A_Dodge(vm.pSprite); + + if (vm.pSprite->picnum != APLAYER) + VM_AlterAng(movflags); + + if (vm.pSprite->xvel > -6 && vm.pSprite->xvel < 6) + vm.pSprite->xvel = 0; + + int badguyp = A_CheckEnemySprite(vm.pSprite); + + if (vm.pSprite->xvel || vm.pSprite->zvel) + { + int spriteXvel = vm.pSprite->xvel; + int angDiff = vm.pSprite->ang; + + if (badguyp && (vm.pSprite->picnum != ROTATEGUN || RR)) + { + if ((vm.pSprite->picnum == DRONE || (!RR && vm.pSprite->picnum == COMMANDER)) && vm.pSprite->extra > 0) + { + if (!RR && vm.pSprite->picnum == COMMANDER) + { + int32_t nSectorZ; + // NOTE: COMMANDER updates both actor[].floorz and + // .ceilingz regardless of its zvel. + vm.pActor->floorz = nSectorZ = VM_GetFlorZOfSlope(); + if (vm.pSprite->z > nSectorZ-ZOFFSET3) + { + vm.pSprite->z = nSectorZ-ZOFFSET3; + vm.pSprite->zvel = 0; + } + + vm.pActor->ceilingz = nSectorZ = VM_GetCeilZOfSlope(); + if (vm.pSprite->z < nSectorZ+(80<<8)) + { + vm.pSprite->z = nSectorZ+(80<<8); + vm.pSprite->zvel = 0; + } + } + else + { + int32_t nSectorZ; + // The DRONE updates either .floorz or .ceilingz, not both. + if (vm.pSprite->zvel > 0) + { + vm.pActor->floorz = nSectorZ = VM_GetFlorZOfSlope(); + int const zDiff = RRRA ? (28<<8) : (30<<8); + if (vm.pSprite->z > nSectorZ-zDiff) + vm.pSprite->z = nSectorZ-zDiff; + } + else + { + vm.pActor->ceilingz = nSectorZ = VM_GetCeilZOfSlope(); + if (vm.pSprite->z < nSectorZ+(50<<8)) + { + vm.pSprite->z = nSectorZ+(50<<8); + vm.pSprite->zvel = 0; + } + } + } + } + else if (vm.pSprite->picnum != ORGANTIC || RR) + { + // All other actors besides ORGANTIC don't update .floorz or + // .ceilingz here. + if (vm.pSprite->zvel > 0) + { + if (vm.pSprite->z > vm.pActor->floorz) + vm.pSprite->z = vm.pActor->floorz; + //vm.pSprite->z += A_GetWaterZOffset(vm.spriteNum); + } + else if (vm.pSprite->zvel < 0) + { + int const l = VM_GetCeilZOfSlope(); + + if (vm.pSprite->z < l+(66<<8)) + { + vm.pSprite->z = l+(66<<8); + vm.pSprite->zvel >>= 1; + } + } + } + + if (vm.playerDist < 960 && vm.pSprite->xrepeat > 16) + { + spriteXvel = -(1024 - vm.playerDist); + angDiff = getangle(vm.pPlayer->pos.x - vm.pSprite->x, vm.pPlayer->pos.y - vm.pSprite->y); + + if (vm.playerDist < 512) + { + vm.pPlayer->vel.x = 0; + vm.pPlayer->vel.y = 0; + } + else + { + vm.pPlayer->vel.x = mulscale16(vm.pPlayer->vel.x, vm.pPlayer->runspeed - 0x2000); + vm.pPlayer->vel.y = mulscale16(vm.pPlayer->vel.y, vm.pPlayer->runspeed - 0x2000); + } + } + else if (vm.pSprite->picnum != DRONE && vm.pSprite->picnum != SHARK + && ((!RR && vm.pSprite->picnum != COMMANDER) + || (RR && vm.pSprite->picnum != UFO1) + || (RR && !RRRA && vm.pSprite->picnum != UFO2 && vm.pSprite->picnum != UFO3 && vm.pSprite->picnum != UFO4 && vm.pSprite->picnum != UFO5))) + { + if (vm.pPlayer->actorsqu == vm.spriteNum) + return; + + if (vm.pActor->bpos.z != vm.pSprite->z || (!g_netServer && ud.multimode < 2 && ud.player_skill < 2)) + { + if (AC_COUNT(vm.pData)&1) return; + spriteXvel <<= 1; + } + else + { + if (AC_COUNT(vm.pData)&3) return; + spriteXvel <<= 2; + } + } + } + else if (vm.pSprite->picnum == APLAYER) + if (vm.pSprite->z < vm.pActor->ceilingz+ZOFFSET5) + vm.pSprite->z = vm.pActor->ceilingz+ZOFFSET5; + + if (RRRA) + { + if (sector[vm.pSprite->sectnum].lotag != ST_1_ABOVE_WATER) + { + switch (DYNAMICTILEMAP(vm.pSprite->picnum)) + { + case MINIONBOAT__STATICRR: + case HULK__STATICRR: + case CHEERBOAT__STATICRR: + spriteXvel >>= 1; + break; + } + } + else + { + switch (DYNAMICTILEMAP(vm.pSprite->picnum)) + { + case BIKERB__STATICRR: + case BIKERBV2__STATICRR: + case CHEERB__STATICRR: + spriteXvel >>= 1; + break; + } + } + } + + vec3_t const vect + = { (spriteXvel * (sintable[(angDiff + 512) & 2047])) >> 14, (spriteXvel * (sintable[angDiff & 2047])) >> 14, vm.pSprite->zvel }; + + vm.pActor->movflag = A_MoveSprite(vm.spriteNum, &vect, CLIPMASK0); + if (DEER && vm.pSprite->picnum != DOGRUN) + { + if ((vm.pActor->movflag & 49152) == 32768) + { + int const wallnum = vm.pActor->movflag & (MAXWALLS-1); + if (ghcons_isanimalescapewall(wallnum)) + { + vm.pSprite->z = sector[vm.pSprite->sectnum].ceilingz; + A_MoveSprite(vm.spriteNum, &vect, CLIPMASK0); + vm.pSprite->z = sector[vm.pSprite->sectnum].floorz; + } + } + else if ((vm.pActor->movflag & 49152) == 16384) + { + int sectnum = vm.pActor->movflag & (MAXSECTORS-1); + if (ghcons_isanimalescapesect(sectnum)) + { + A_MoveSprite(vm.spriteNum, &vect, CLIPMASK0); + vm.pSprite->z = sector[vm.pSprite->sectnum].floorz; + } + } + } + } + + if (!badguyp) + return; + + vm.pSprite->shade += (sector[vm.pSprite->sectnum].ceilingstat & 1) ? ((g_shadedSector[vm.pSprite->sectnum] == 1 ? 16 : sector[vm.pSprite->sectnum].ceilingshade) - vm.pSprite->shade) >> 1 + : (sector[vm.pSprite->sectnum].floorshade - vm.pSprite->shade) >> 1; + + if (sector[vm.pSprite->sectnum].floorpicnum == MIRROR) + A_DeleteSprite(vm.spriteNum); +} + +static void VM_AddWeapon(DukePlayer_t * const pPlayer, int const weaponNum, int const nAmount) +{ + if (EDUKE32_PREDICT_FALSE((unsigned)weaponNum >= MAX_WEAPONS)) + { + CON_ERRPRINTF("invalid weapon %d\n", weaponNum); + return; + } + + if ((pPlayer->gotweapon & (1 << weaponNum)) == 0) + { + P_AddWeapon(pPlayer, weaponNum); + } + else if (pPlayer->ammo_amount[weaponNum] >= pPlayer->max_ammo_amount[weaponNum]) + { + vm.flags |= VM_NOEXECUTE; + return; + } + + P_AddAmmo(pPlayer, weaponNum, nAmount); + + if (pPlayer->curr_weapon == KNEE_WEAPON && (pPlayer->gotweapon & (1<= MAX_WEAPONS)) + { + CON_ERRPRINTF("invalid weapon %d\n", weaponNum); + return; + } + + if (pPlayer->ammo_amount[weaponNum] >= pPlayer->max_ammo_amount[weaponNum]) + { + vm.flags |= VM_NOEXECUTE; + return; + } + + P_AddAmmo(pPlayer, weaponNum, nAmount); + + if (pPlayer->curr_weapon == KNEE_WEAPON && (pPlayer->gotweapon & (1<inven_icon = inv_to_icon[itemNum]; + pPlayer->inv_amount[itemNum] = nAmount; + break; + + case GET_SHIELD: + { + int16_t & shield_amount = pPlayer->inv_amount[GET_SHIELD]; + shield_amount = min(shield_amount + nAmount, pPlayer->max_shield_amount); + break; + } + + case GET_ACCESS: + if (RR) + { + switch (vm.pSprite->lotag) + { + case 100: pPlayer->keys[1] = 1; break; + case 101: pPlayer->keys[2] = 1; break; + case 102: pPlayer->keys[3] = 1; break; + case 103: pPlayer->keys[4] = 1; break; + } + } + else + { + switch (vm.pSprite->pal) + { + case 0: pPlayer->got_access |= 1; break; + case 21: pPlayer->got_access |= 2; break; + case 23: pPlayer->got_access |= 4; break; + } + } + break; + + default: CON_ERRPRINTF("invalid inventory item %d\n", itemNum); break; + } +} + +static int32_t A_GetWaterZOffset(int const spriteNum) +{ + uspritetype const *const pSprite = (uspritetype *)&sprite[spriteNum]; + + if (sector[pSprite->sectnum].lotag == ST_1_ABOVE_WATER) + { + if (RRRA) + { + switch (DYNAMICTILEMAP(pSprite->picnum)) + { + case HULKBOAT__STATICRR: + return (12<<8); + case MINIONBOAT__STATICRR: + return (3<<8); + case CHEERBOAT__STATICRR: + case EMPTYBOAT__STATICRR: + return (6<<8); + } + } + if (A_CheckSpriteFlags(spriteNum, SFLAG_NOWATERDIP)) + return 0; + + return ACTOR_ONWATER_ADDZ; + } + + return 0; +} + +static void VM_Fall(int const spriteNum, spritetype * const pSprite) +{ + int spriteGravity = g_spriteGravity; + int hitSprite = 0; + + pSprite->xoffset = pSprite->yoffset = 0; + + if (RR) + { + if (RRRA) + { + if (sector[vm.pSprite->sectnum].lotag == 801) + { + if (vm.pSprite->picnum == ROCK) + { + A_Spawn(vm.spriteNum, ROCK2); + A_Spawn(vm.spriteNum, ROCK2); + vm.flags |= VM_SAFEDELETE; + } + } + else if (sector[vm.pSprite->sectnum].lotag == 802) + { + if (vm.pSprite->picnum != APLAYER && A_CheckEnemySprite(vm.pSprite) && vm.pSprite->z == vm.pActor->floorz - ZOFFSET) + { + A_DoGuts(vm.spriteNum, JIBS6, 5); + A_PlaySound(SQUISHED, vm.spriteNum); + vm.flags |= VM_SAFEDELETE; + } + } + else if (sector[vm.pSprite->sectnum].lotag == 803) + { + if (vm.pSprite->picnum == ROCK2) + { + vm.flags |= VM_SAFEDELETE; + } + } + } + if (sector[vm.pSprite->sectnum].lotag == 800) + { + if (vm.pSprite->picnum == AMMO) + { + vm.flags |= VM_SAFEDELETE; + return; + } + if (vm.pSprite->picnum != APLAYER && (A_CheckEnemySprite(vm.pSprite) || vm.pSprite->picnum == COW) && g_spriteExtra[vm.spriteNum] < 128) + { + vm.pSprite->z = vm.pActor->floorz-ZOFFSET; + vm.pSprite->zvel = 8000; + vm.pSprite->extra = 0; + g_spriteExtra[vm.spriteNum]++; + hitSprite = 1; + } + else if (vm.pSprite->picnum != APLAYER) + { + if (!g_spriteExtra[vm.spriteNum]) + vm.flags |= VM_SAFEDELETE; + return; + } + vm.pActor->picnum = SHOTSPARK1; + vm.pActor->extra = 1; + } + if (RRRA && EDUKE32_PREDICT_TRUE(sector[vm.pSprite->sectnum].lotag < 800 || sector[vm.pSprite->sectnum].lotag > 803) + && (sector[vm.pSprite->sectnum].floorpicnum == RRTILE7820 || sector[vm.pSprite->sectnum].floorpicnum == RRTILE7768)) + { + if (vm.pSprite->picnum != MINION && vm.pSprite->pal != 19) + { + if ((krand2()&3) == 1) + { + vm.pActor->picnum = SHOTSPARK1; + vm.pActor->extra = 5; + } + } + } + } + + if (sector[pSprite->sectnum].lotag == ST_2_UNDERWATER || EDUKE32_PREDICT_FALSE(G_CheckForSpaceCeiling(pSprite->sectnum))) + spriteGravity = g_spriteGravity/6; + else if (EDUKE32_PREDICT_FALSE(G_CheckForSpaceFloor(pSprite->sectnum))) + spriteGravity = 0; + + if (actor[spriteNum].cgg <= 0 || (sector[pSprite->sectnum].floorstat&2)) + { + A_GetZLimits(spriteNum); + actor[spriteNum].cgg = 6; + } + else actor[spriteNum].cgg--; + + if (pSprite->z < actor[spriteNum].floorz-ZOFFSET) + { + // Free fall. + pSprite->zvel += spriteGravity; + pSprite->z += pSprite->zvel; + +#ifdef YAX_ENABLE + if (yax_getbunch(pSprite->sectnum, YAX_FLOOR) >= 0 && (sector[pSprite->sectnum].floorstat & 512) == 0) + setspritez(spriteNum, (vec3_t *)pSprite); +#endif + + if (pSprite->zvel > 6144) pSprite->zvel = 6144; + return; + } + + pSprite->z = actor[spriteNum].floorz - ZOFFSET; + + if (A_CheckEnemySprite(pSprite) || (pSprite->picnum == APLAYER && pSprite->owner >= 0)) + { + if (pSprite->zvel > 3084 && pSprite->extra <= 1) + { + // I'm guessing this DRONE check is from a beta version of the game + // where they crashed into the ground when killed + if (!(pSprite->picnum == APLAYER && pSprite->extra > 0) && pSprite->pal != 1 && pSprite->picnum != DRONE) + { + A_PlaySound(SQUISHED,spriteNum); + if (hitSprite) + { + A_DoGuts(spriteNum,JIBS6,5); + } + else + { + A_DoGuts(spriteNum,JIBS6,15); + A_Spawn(spriteNum,BLOODPOOL); + } + } + actor[spriteNum].picnum = SHOTSPARK1; + actor[spriteNum].extra = 1; + pSprite->zvel = 0; + } + else if (pSprite->zvel > 2048 && sector[pSprite->sectnum].lotag != ST_1_ABOVE_WATER) + { + int16_t newsect = pSprite->sectnum; + + pushmove((vec3_t *)pSprite, &newsect, 128, 4<<8, 4<<8, CLIPMASK0); + if ((unsigned)newsect < MAXSECTORS) + changespritesect(spriteNum, newsect); + + if (!DEER) + A_PlaySound(THUD, spriteNum); + } + } + + if (sector[pSprite->sectnum].lotag == ST_1_ABOVE_WATER) + { + pSprite->z += A_GetWaterZOffset(spriteNum); + return; + } + + pSprite->zvel = 0; +} + +static int32_t VM_ResetPlayer(int const playerNum, int32_t vmFlags) +{ + //AddLog("resetplayer"); + if (!g_netServer && ud.multimode < 2) + { +#if 0 + if (g_quickload && g_quickload->isValid() && ud.recstat != 2) + { + M_StartControlPanel(false); + M_SetMenu(NAME_ConfirmPlayerReset); + } + else +#endif + g_player[playerNum].ps->gm = MODE_RESTART; + vmFlags |= VM_NOEXECUTE; + } + else + { + if (playerNum == myconnectindex) + { + CAMERADIST = 0; + CAMERACLOCK = (int32_t) totalclock; + } + + //if (g_fakeMultiMode) + P_ResetPlayer(playerNum); +#ifndef NETCODE_DISABLE + //if (g_netServer) + //{ + // P_ResetPlayer(playerNum); + // Net_SpawnPlayer(playerNum); + //} +#endif + } + + P_UpdateScreenPal(g_player[playerNum].ps); + //AddLog("EOF: resetplayer"); + + return vmFlags; +} + +void G_GetTimeDate(int32_t * const pValues) +{ + time_t timeStruct; + time(&timeStruct); + struct tm *pTime = localtime(&timeStruct); + + // Printf("Time&date: %s\n",asctime (ti)); + + pValues[0] = pTime->tm_sec; + pValues[1] = pTime->tm_min; + pValues[2] = pTime->tm_hour; + pValues[3] = pTime->tm_mday; + pValues[4] = pTime->tm_mon; + pValues[5] = pTime->tm_year+1900; + pValues[6] = pTime->tm_wday; + pValues[7] = pTime->tm_yday; +} + +void Screen_Play(void) +{ + int32_t running = 1; + + inputState.ClearAllInput(); + + do + { + G_HandleAsync(); + + ototalclock = totalclock + 1; // pause game like ANMs + + if (!G_FPSLimit()) + continue; + + videoClearScreen(0); + if (inputState.CheckAllInput()) + running = 0; + + videoNextPage(); + inputState.ClearAllInput(); + } while (running); +} + +GAMEEXEC_STATIC void VM_Execute(native_t loop) +{ + native_t tw = *insptr; + DukePlayer_t *const pPlayer = vm.pPlayer; + + // jump directly into the loop, skipping branches during the first iteration + goto skip_check; + + while (loop) + { + if (vm.flags & (VM_RETURN | VM_KILL | VM_NOEXECUTE)) + break; + + tw = *insptr; + + skip_check: + // Bsprintf(g_szBuf,"Parsing: %d",*insptr); + // AddLog(g_szBuf); + + g_errorLineNum = tw >> 12; + g_tw = tw &= VM_INSTMASK; + + if (tw == CON_LEFTBRACE) + { + insptr++, loop++; + continue; + } + else if (tw == CON_RIGHTBRACE) + { + insptr++, loop--; + continue; + } + else if (tw == CON_ELSE) + { + insptr = (intptr_t *)*(insptr + 1); + continue; + } + else if (tw == CON_STATE) + { + intptr_t const *const tempscrptr = insptr + 2; + insptr = (intptr_t *)*(insptr + 1); + VM_Execute(1); + insptr = tempscrptr; + continue; + } + + switch (tw) + { + case CON_ENDA: + case CON_BREAK: + case CON_ENDS: + case CON_ENDEVENT: return; + + case CON_IFRND: VM_CONDITIONAL(rnd(*(++insptr))); continue; + + case CON_IFCANSHOOTTARGET: + { + if (vm.playerDist > 1024) + { + int16_t temphit; + + if ((tw = A_CheckHitSprite(vm.spriteNum, &temphit)) == (1 << 30)) + { + VM_CONDITIONAL(1); + continue; + } + + int dist = 768; + int angDiff = 16; + + if (A_CheckEnemySprite(vm.pSprite) && vm.pSprite->xrepeat > 56) + { + dist = 3084; + angDiff = 48; + } + +#define CHECK(x) \ + if (x >= 0 && sprite[x].picnum == vm.pSprite->picnum) \ + { \ + VM_CONDITIONAL(0); \ + continue; \ + } +#define CHECK2(x) \ + do \ + { \ + vm.pSprite->ang += x; \ + tw = A_CheckHitSprite(vm.spriteNum, &temphit); \ + vm.pSprite->ang -= x; \ + } while (0) + + if (tw > dist) + { + CHECK(temphit); + CHECK2(angDiff); + + if (tw > dist) + { + CHECK(temphit); + CHECK2(-angDiff); + + if (tw > 768) + { + CHECK(temphit); + VM_CONDITIONAL(1); + continue; + } + } + } + VM_CONDITIONAL(0); + continue; + } + VM_CONDITIONAL(1); + } + continue; + + case CON_IFCANSEETARGET: + tw = cansee(vm.pSprite->x, vm.pSprite->y, vm.pSprite->z - ((krand2() & 41) << 8), vm.pSprite->sectnum, pPlayer->pos.x, pPlayer->pos.y, + pPlayer->pos.z /*-((krand2()&41)<<8)*/, sprite[pPlayer->i].sectnum); + VM_CONDITIONAL(tw); + if (tw) + vm.pActor->timetosleep = SLEEPTIME; + continue; + + case CON_IFNOCOVER: + tw = cansee(vm.pSprite->x, vm.pSprite->y, vm.pSprite->z, vm.pSprite->sectnum, pPlayer->pos.x, pPlayer->pos.y, + pPlayer->pos.z, sprite[pPlayer->i].sectnum); + VM_CONDITIONAL(tw); + if (tw) + vm.pActor->timetosleep = SLEEPTIME; + continue; + + case CON_IFACTORNOTSTAYPUT: VM_CONDITIONAL(vm.pActor->actorstayput == -1); continue; + + case CON_IFCANSEE: + { + uspritetype *pSprite = (uspritetype *)&sprite[pPlayer->i]; + + if (DEER) + { + if (sintable[vm.pSprite->ang&2047] * (pSprite->y - vm.pSprite->y) + sintable[(vm.pSprite->ang+512)&2047] * (pSprite->x - vm.pSprite->x) >= 0) + tw = cansee(vm.pSprite->x, vm.pSprite->y, vm.pSprite->z - (krand2() % 13312), vm.pSprite->sectnum, + pSprite->x, pSprite->y, pPlayer->opos.z-(krand2() % 8192), pPlayer->cursectnum); + else + tw = 0; + + VM_CONDITIONAL(tw); + continue; + } + +// select sprite for monster to target +// if holoduke is on, let them target holoduke first. +// + if (!RR && pPlayer->holoduke_on >= 0) + { + pSprite = (uspritetype *)&sprite[pPlayer->holoduke_on]; + tw = cansee(vm.pSprite->x, vm.pSprite->y, vm.pSprite->z - (krand2() & (ZOFFSET5 - 1)), vm.pSprite->sectnum, pSprite->x, pSprite->y, + pSprite->z, pSprite->sectnum); + + if (tw == 0) + { + // they can't see player's holoduke + // check for player... + pSprite = (uspritetype *)&sprite[pPlayer->i]; + } + } + // can they see player, (or player's holoduke) + tw = cansee(vm.pSprite->x, vm.pSprite->y, vm.pSprite->z - (krand2() & ((47 << 8))), vm.pSprite->sectnum, pSprite->x, pSprite->y, + pSprite->z - (RR ? (28 << 8) : (24 << 8)), pSprite->sectnum); + + if (tw == 0) + { + // search around for target player + + // also modifies 'target' x&y if found.. + + tw = 1; + if (A_FurthestVisiblePoint(vm.spriteNum, pSprite, &vm.pActor->lastv) == -1) + tw = 0; + } + else + { + // else, they did see it. + // save where we were looking... + vm.pActor->lastv.x = pSprite->x; + vm.pActor->lastv.y = pSprite->y; + } + + if (tw && (vm.pSprite->statnum == STAT_ACTOR || vm.pSprite->statnum == STAT_STANDABLE)) + vm.pActor->timetosleep = SLEEPTIME; + + VM_CONDITIONAL(tw); + continue; + } + + case CON_IFHITWEAPON: + if (DEER) + { + VM_CONDITIONAL(ghtrophy_isakill(vm.spriteNum)); + } + else + { + VM_CONDITIONAL(A_IncurDamage(vm.spriteNum) >= 0); + } + continue; + + case CON_IFSQUISHED: VM_CONDITIONAL(VM_CheckSquished()); continue; + + case CON_IFDEAD: VM_CONDITIONAL(vm.pSprite->extra - (vm.pSprite->picnum == APLAYER) < 0); continue; + + case CON_AI: + insptr++; + // Following changed to use pointersizes + AC_AI_ID(vm.pData) = *insptr++; // Ai + AC_ACTION_ID(vm.pData) = *(apScript + AC_AI_ID(vm.pData)); // Action + AC_MOVE_ID(vm.pData) = *(apScript + AC_AI_ID(vm.pData) + 1); // move + + vm.pSprite->hitag = *(apScript + AC_AI_ID(vm.pData) + 2); // move flags + + AC_COUNT(vm.pData) = 0; + AC_ACTION_COUNT(vm.pData) = 0; + AC_CURFRAME(vm.pData) = 0; + + if (vm.pSprite->hitag & random_angle) + vm.pSprite->ang = krand2() & 2047; + continue; + + case CON_ACTION: + insptr++; + AC_ACTION_COUNT(vm.pData) = 0; + AC_CURFRAME(vm.pData) = 0; + AC_ACTION_ID(vm.pData) = *insptr++; + continue; + + case CON_IFPDISTL: + insptr++; + VM_CONDITIONAL(!(DEER && sub_535EC()) && vm.playerDist < *(insptr)); + if (vm.playerDist > MAXSLEEPDIST && vm.pActor->timetosleep == 0) + vm.pActor->timetosleep = SLEEPTIME; + continue; + + case CON_IFPDISTG: + VM_CONDITIONAL(vm.playerDist > *(++insptr)); + if (vm.playerDist > MAXSLEEPDIST && vm.pActor->timetosleep == 0) + vm.pActor->timetosleep = SLEEPTIME; + continue; + + case CON_ADDSTRENGTH: + insptr++; + vm.pSprite->extra += *insptr++; + continue; + + case CON_STRENGTH: + insptr++; + vm.pSprite->extra = *insptr++; + continue; + + case CON_SMACKSPRITE: + insptr++; + if (krand2()&1) + vm.pSprite->ang = (vm.pSprite->ang-(512+(krand2()&511)))&2047; + else + vm.pSprite->ang = (vm.pSprite->ang+(512+(krand2()&511)))&2047; + continue; + + case CON_FAKEBUBBA: + insptr++; + switch (++g_fakeBubbaCnt) + { + case 1: + A_Spawn(vm.spriteNum, PIG); + break; + case 2: + A_Spawn(vm.spriteNum, MINION); + break; + case 3: + A_Spawn(vm.spriteNum, CHEER); + break; + case 4: + A_Spawn(vm.spriteNum, VIXEN); + G_OperateActivators(666, vm.playerNum); + break; + } + continue; + + case CON_RNDMOVE: + insptr++; + vm.pSprite->ang = krand2()&2047; + vm.pSprite->xvel = 25; + continue; + + case CON_MAMATRIGGER: + insptr++; + G_OperateActivators(667, vm.playerNum); + continue; + + case CON_MAMASPAWN: + insptr++; + if (g_mamaSpawnCnt) + { + g_mamaSpawnCnt--; + A_Spawn(vm.spriteNum, RABBIT); + } + continue; + + case CON_MAMAQUAKE: + insptr++; + if (vm.pSprite->pal == 31) + g_earthquakeTime = 4; + else if(vm.pSprite->pal == 32) + g_earthquakeTime = 6; + continue; + + case CON_GARYBANJO: + insptr++; + if (g_banjoSong == 0) + { + switch (krand2()&3) + { + case 3: + g_banjoSong = 262; + break; + case 0: + g_banjoSong = 272; + break; + default: + g_banjoSong = 273; + break; + } + A_PlaySound(g_banjoSong, vm.spriteNum); + } + else if (!S_CheckSoundPlaying(vm.spriteNum, g_banjoSong)) + A_PlaySound(g_banjoSong, vm.spriteNum); + continue; + case CON_MOTOLOOPSND: + insptr++; + if (!S_CheckSoundPlaying(vm.spriteNum, 411)) + A_PlaySound(411, vm.spriteNum); + continue; + + case CON_IFGOTWEAPONCE: + insptr++; + + if ((g_gametypeFlags[ud.coop] & GAMETYPE_WEAPSTAY) && (g_netServer || ud.multimode > 1)) + { + if (*insptr == 0) + { + int j = 0; + for (; j < pPlayer->weapreccnt; ++j) + if (pPlayer->weaprecs[j] == vm.pSprite->picnum) + break; + + VM_CONDITIONAL(j < pPlayer->weapreccnt && vm.pSprite->owner == vm.spriteNum); + continue; + } + else if (pPlayer->weapreccnt < MAX_WEAPON_RECS-1) + { + pPlayer->weaprecs[pPlayer->weapreccnt++] = vm.pSprite->picnum; + VM_CONDITIONAL(vm.pSprite->owner == vm.spriteNum); + continue; + } + } + VM_CONDITIONAL(0); + continue; + + case CON_GETLASTPAL: + insptr++; + if (vm.pSprite->picnum == APLAYER) + vm.pSprite->pal = g_player[P_GetP(vm.pSprite)].ps->palookup; + else + vm.pSprite->pal = vm.pActor->tempang; + vm.pActor->tempang = 0; + continue; + + case CON_TOSSWEAPON: + insptr++; + // NOTE: assumes that current actor is APLAYER + P_DropWeapon(P_GetP(vm.pSprite)); + continue; + + case CON_MIKESND: + insptr++; + if (EDUKE32_PREDICT_FALSE(((unsigned)vm.pSprite->yvel >= MAXSOUNDS))) + { + CON_ERRPRINTF("invalid sound %d\n", vm.pUSprite->yvel); + continue; + } + if (!S_CheckSoundPlaying(vm.spriteNum, vm.pSprite->yvel)) + A_PlaySound(vm.pSprite->yvel, vm.spriteNum); + continue; + + case CON_PKICK: + insptr++; + + if ((g_netServer || ud.multimode > 1) && vm.pSprite->picnum == APLAYER) + { + if (g_player[otherp].ps->quick_kick == 0) + g_player[otherp].ps->quick_kick = 14; + } + else if (vm.pSprite->picnum != APLAYER && pPlayer->quick_kick == 0) + pPlayer->quick_kick = 14; + continue; + + case CON_SIZETO: + insptr++; + + tw = (*insptr++ - vm.pSprite->xrepeat) << 1; + vm.pSprite->xrepeat += ksgn(tw); + + if ((vm.pSprite->picnum == APLAYER && vm.pSprite->yrepeat < 36) || *insptr < vm.pSprite->yrepeat + || ((vm.pSprite->yrepeat * (tilesiz[vm.pSprite->picnum].y + 8)) << 2) < (vm.pActor->floorz - vm.pActor->ceilingz)) + { + tw = ((*insptr) - vm.pSprite->yrepeat) << 1; + if (klabs(tw)) + vm.pSprite->yrepeat += ksgn(tw); + } + + insptr++; + + continue; + + case CON_SIZEAT: + insptr++; + vm.pSprite->xrepeat = (uint8_t)*insptr++; + vm.pSprite->yrepeat = (uint8_t)*insptr++; + continue; + + case CON_SHOOT: + insptr++; + if (EDUKE32_PREDICT_FALSE((unsigned)vm.pSprite->sectnum >= (unsigned)numsectors)) + { + CON_ERRPRINTF("invalid sector %d\n", vm.pUSprite->sectnum); + continue; + } + A_Shoot(vm.spriteNum, *insptr++); + continue; + + case CON_IFSOUNDID: + insptr++; + VM_CONDITIONAL((int16_t)*insptr == g_ambientLotag[vm.pSprite->ang]); + continue; + + case CON_IFSOUNDDIST: + insptr++; + if (*insptr == 0) + { + VM_CONDITIONAL(g_ambientHitag[vm.pSprite->ang] > vm.playerDist); + } + else if (*insptr == 1) + { + VM_CONDITIONAL(g_ambientHitag[vm.pSprite->ang] < vm.playerDist); + } + else + { + VM_CONDITIONAL(0); + } + + continue; + + case CON_SOUNDTAG: + insptr++; + A_PlaySound(g_ambientLotag[vm.pSprite->ang], vm.spriteNum); + continue; + + case CON_SOUNDTAGONCE: + insptr++; + if (!S_CheckSoundPlaying(vm.spriteNum, g_ambientLotag[vm.pSprite->ang])) + A_PlaySound(g_ambientLotag[vm.pSprite->ang], vm.spriteNum); + continue; + + case CON_SOUNDONCE: + if (EDUKE32_PREDICT_FALSE((unsigned)*(++insptr) >= MAXSOUNDS)) + { + CON_ERRPRINTF("invalid sound %d\n", (int32_t)*insptr++); + continue; + } + + if (!S_CheckSoundPlaying(vm.spriteNum, *insptr++)) + A_PlaySound(*(insptr - 1), vm.spriteNum); + + continue; + + case CON_STOPSOUND: + if (EDUKE32_PREDICT_FALSE((unsigned)*(++insptr) >= MAXSOUNDS)) + { + CON_ERRPRINTF("invalid sound %d\n", (int32_t)*insptr); + insptr++; + continue; + } + if (S_CheckSoundPlaying(vm.spriteNum, *insptr)) + S_StopSound((int16_t)*insptr); + insptr++; + continue; + + case CON_GLOBALSOUND: + if (EDUKE32_PREDICT_FALSE((unsigned)*(++insptr) >= MAXSOUNDS)) + { + CON_ERRPRINTF("invalid sound %d\n", (int32_t)*insptr); + insptr++; + continue; + } + if (vm.playerNum == screenpeek || (g_gametypeFlags[ud.coop] & GAMETYPE_COOPSOUND) +#ifdef SPLITSCREEN_MOD_HACKS + || (g_fakeMultiMode == 2) +#endif + ) + A_PlaySound(*insptr, g_player[screenpeek].ps->i); + insptr++; + continue; + + case CON_SMACKBUBBA: + insptr++; + if (!RRRA || vm.pSprite->pal != 105) + { + for (bssize_t TRAVERSE_CONNECT(playerNum)) + g_player[playerNum].ps->gm = MODE_EOL; + if (++ud.level_number > 6) + ud.level_number = 0; + m_level_number = ud.level_number; + } + continue; + + case CON_DEPLOYBIAS: + insptr++; + ghdeploy_bias(vm.spriteNum); + continue; + + case CON_MAMAEND: + insptr++; + g_player[myconnectindex].ps->level_end_timer = 150; + continue; + + case CON_IFACTORHEALTHG: + insptr++; + VM_CONDITIONAL(vm.pSprite->extra > (int16_t)*insptr); + continue; + + case CON_IFACTORHEALTHL: + insptr++; + VM_CONDITIONAL(vm.pSprite->extra < (int16_t)*insptr); + continue; + + case CON_SOUND: + if (EDUKE32_PREDICT_FALSE((unsigned)*(++insptr) >= MAXSOUNDS)) + { + CON_ERRPRINTF("invalid sound %d\n", (int32_t)*insptr); + insptr++; + continue; + } + A_PlaySound(*insptr++, vm.spriteNum); + continue; + + case CON_TIP: + insptr++; + pPlayer->tipincs = GAMETICSPERSEC; + continue; + + case CON_IFTIPCOW: + if (g_spriteExtra[vm.spriteNum] == 1) + { + g_spriteExtra[vm.spriteNum]++; + VM_CONDITIONAL(1); + } + else + VM_CONDITIONAL(0); + continue; + + case CON_IFHITTRUCK: + if (g_spriteExtra[vm.spriteNum] == 1) + { + g_spriteExtra[vm.spriteNum]++; + VM_CONDITIONAL(1); + } + else + VM_CONDITIONAL(0); + continue; + + case CON_IFFINDNEWSPOT: + VM_CONDITIONAL(ghcons_findnewspot(vm.spriteNum)); + continue; + + case CON_LEAVEDROPPINGS: + insptr++; + ghtrax_leavedroppings(vm.spriteNum); + continue; + + case CON_TEARITUP: + insptr++; + for (bssize_t SPRITES_OF_SECT(vm.pSprite->sectnum, spriteNum)) + { + if (sprite[spriteNum].picnum == DESTRUCTO) + { + actor[spriteNum].picnum = SHOTSPARK1; + actor[spriteNum].extra = 1; + } + } + continue; + + case CON_FALL: + insptr++; + VM_Fall(vm.spriteNum, vm.pSprite); + continue; + + case CON_NULLOP: insptr++; continue; + + case CON_ADDAMMO: + insptr++; + { + int const weaponNum = *insptr++; + int const addAmount = *insptr++; + + VM_AddAmmo(pPlayer, weaponNum, addAmount); + + continue; + } + + case CON_MONEY: + insptr++; + A_SpawnMultiple(vm.spriteNum, MONEY, *insptr++); + continue; + + case CON_MAIL: + insptr++; + A_SpawnMultiple(vm.spriteNum, RR ? MONEY : MAIL, *insptr++); + continue; + + case CON_SLEEPTIME: + insptr++; + vm.pActor->timetosleep = (int16_t)*insptr++; + continue; + + case CON_PAPER: + insptr++; + A_SpawnMultiple(vm.spriteNum, RR ? MONEY : PAPER, *insptr++); + continue; + + case CON_ADDKILLS: + if (DEER) + { + // no op + insptr++; + insptr++; + continue; + } + insptr++; + if (!RR || ((g_spriteExtra[vm.spriteNum] < 1 || g_spriteExtra[vm.spriteNum] == 128) && A_CheckSpriteFlags(vm.spriteNum, SFLAG_KILLCOUNT))) + P_AddKills(pPlayer, *insptr); + insptr++; + vm.pActor->actorstayput = -1; + continue; + + case CON_LOTSOFGLASS: + insptr++; + A_SpawnGlass(vm.spriteNum, *insptr++); + continue; + + case CON_KILLIT: + insptr++; + vm.flags |= VM_KILL; + return; + + case CON_ADDWEAPON: + insptr++; + { + int const weaponNum = *insptr++; + VM_AddWeapon(pPlayer, weaponNum, *insptr++); + continue; + } + + case CON_DEBUG: + insptr++; + buildprint(*insptr++, "\n"); + continue; + + case CON_ENDOFGAME: + insptr++; + pPlayer->timebeforeexit = *insptr++; + pPlayer->customexitsound = -1; + ud.eog = 1; + continue; + + case CON_ISDRUNK: + insptr++; + { + pPlayer->drink_amt += *insptr; + + int newHealth = sprite[pPlayer->i].extra; + + if (newHealth > 0) + newHealth += *insptr; + if (newHealth > (pPlayer->max_player_health << 1)) + newHealth = (pPlayer->max_player_health << 1); + if (newHealth < 0) + newHealth = 0; + + if (ud.god == 0) + { + if (*insptr > 0) + { + if ((newHealth - *insptr) < (pPlayer->max_player_health >> 2) && newHealth >= (pPlayer->max_player_health >> 2)) + A_PlaySound(DUKE_GOTHEALTHATLOW, pPlayer->i); + pPlayer->last_extra = newHealth; + } + + sprite[pPlayer->i].extra = newHealth; + } + if (pPlayer->drink_amt > 100) + pPlayer->drink_amt = 100; + + if (sprite[pPlayer->i].extra >= pPlayer->max_player_health) + { + sprite[pPlayer->i].extra = pPlayer->max_player_health; + pPlayer->last_extra = pPlayer->max_player_health; + } + } + insptr++; + continue; + + case CON_STRAFELEFT: + insptr++; + { + vec3_t const vect = { sintable[(vm.pSprite->ang+1024)&2047]>>10, sintable[(vm.pSprite->ang+512)&2047]>>10, vm.pSprite->zvel }; + A_MoveSprite(vm.spriteNum, &vect, CLIPMASK0); + } + continue; + + case CON_STRAFERIGHT: + insptr++; + { + vec3_t const vect = { sintable[(vm.pSprite->ang-0)&2047]>>10, sintable[(vm.pSprite->ang-512)&2047]>>10, vm.pSprite->zvel }; + A_MoveSprite(vm.spriteNum, &vect, CLIPMASK0); + } + continue; + + case CON_LARRYBIRD: + insptr++; + pPlayer->pos.z = sector[sprite[pPlayer->i].sectnum].ceilingz; + sprite[pPlayer->i].z = pPlayer->pos.z; + continue; + + case CON_LEAVETRAX: + insptr++; + ghtrax_leavetrax(vm.spriteNum); + continue; + + case CON_DESTROYIT: + insptr++; + { + int16_t hitag, lotag, spr, jj, k, nextk; + hitag = 0; + for (SPRITES_OF_SECT(vm.pSprite->sectnum,k)) + { + if (sprite[k].picnum == RRTILE63) + { + lotag = sprite[k].lotag; + spr = k; + if (sprite[k].hitag) + hitag = sprite[k].hitag; + } + } + for (SPRITES_OF(100, jj)) + { + spritetype const *js = &sprite[jj]; + if (hitag && hitag == js->hitag) + { + for (SPRITES_OF_SECT(js->sectnum,k)) + { + if (sprite[k].picnum == DESTRUCTO) + { + actor[k].picnum = SHOTSPARK1; + actor[k].extra = 1; + } + } + } + if (sprite[spr].sectnum != js->sectnum && lotag == js->lotag) + { + int16_t const sectnum = sprite[spr].sectnum; + int16_t const wallstart = sector[sectnum].wallptr; + int16_t const wallend = wallstart + sector[sectnum].wallnum; + int16_t const wallstart2 = sector[js->sectnum].wallptr; + //int16_t const wallend2 = wallstart2 + sector[js->sectnum].wallnum; + for (bssize_t wi = wallstart, wj = wallstart2; wi < wallend; wi++, wj++) + { + wall[wi].picnum = wall[wj].picnum; + wall[wi].overpicnum = wall[wj].overpicnum; + wall[wi].shade = wall[wj].shade; + wall[wi].xrepeat = wall[wj].xrepeat; + wall[wi].yrepeat = wall[wj].yrepeat; + wall[wi].xpanning = wall[wj].xpanning; + wall[wi].ypanning = wall[wj].ypanning; + if (RRRA && wall[wi].nextwall != -1) + { + wall[wi].cstat = 0; + wall[wall[wi].nextwall].cstat = 0; + } + } + sector[sectnum].floorz = sector[js->sectnum].floorz; + sector[sectnum].ceilingz = sector[js->sectnum].ceilingz; + sector[sectnum].ceilingstat = sector[js->sectnum].ceilingstat; + sector[sectnum].floorstat = sector[js->sectnum].floorstat; + sector[sectnum].ceilingpicnum = sector[js->sectnum].ceilingpicnum; + sector[sectnum].ceilingheinum = sector[js->sectnum].ceilingheinum; + sector[sectnum].ceilingshade = sector[js->sectnum].ceilingshade; + sector[sectnum].ceilingpal = sector[js->sectnum].ceilingpal; + sector[sectnum].ceilingxpanning = sector[js->sectnum].ceilingxpanning; + sector[sectnum].ceilingypanning = sector[js->sectnum].ceilingypanning; + sector[sectnum].floorpicnum = sector[js->sectnum].floorpicnum; + sector[sectnum].floorheinum = sector[js->sectnum].floorheinum; + sector[sectnum].floorshade = sector[js->sectnum].floorshade; + sector[sectnum].floorpal = sector[js->sectnum].floorpal; + sector[sectnum].floorxpanning = sector[js->sectnum].floorxpanning; + sector[sectnum].floorypanning = sector[js->sectnum].floorypanning; + sector[sectnum].visibility = sector[js->sectnum].visibility; + g_sectorExtra[sectnum] = g_sectorExtra[js->sectnum]; + sector[sectnum].lotag = sector[js->sectnum].lotag; + sector[sectnum].hitag = sector[js->sectnum].hitag; + sector[sectnum].extra = sector[js->sectnum].extra; + } + } + for (SPRITES_OF_SECT_SAFE(vm.pSprite->sectnum, k, nextk)) + { + switch (DYNAMICTILEMAP(sprite[k].picnum)) + { + case DESTRUCTO__STATICRR: + case RRTILE63__STATICRR: + case TORNADO__STATICRR: + case APLAYER__STATIC: + case COOT__STATICRR: + break; + default: + A_DeleteSprite(k); + break; + } + } + } + continue; + + case CON_ISEAT: + insptr++; + + { + pPlayer->eat_amt += *insptr; + if (pPlayer->eat_amt > 100) + pPlayer->eat_amt = 100; + + pPlayer->drink_amt -= *insptr; + if (pPlayer->drink_amt < 0) + pPlayer->drink_amt = 0; + + int newHealth = sprite[pPlayer->i].extra; + + if (vm.pSprite->picnum != ATOMICHEALTH) + { + if (newHealth > pPlayer->max_player_health && *insptr > 0) + { + insptr++; + continue; + } + else + { + if (newHealth > 0) + newHealth += (*insptr)*3; + if (newHealth > pPlayer->max_player_health && *insptr > 0) + newHealth = pPlayer->max_player_health; + } + } + else + { + if (newHealth > 0) + newHealth += *insptr; + if (newHealth > (pPlayer->max_player_health << 1)) + newHealth = (pPlayer->max_player_health << 1); + } + + if (newHealth < 0) + newHealth = 0; + + if (ud.god == 0) + { + if (*insptr > 0) + { + if ((newHealth - *insptr) < (pPlayer->max_player_health >> 2) && newHealth >= (pPlayer->max_player_health >> 2)) + A_PlaySound(DUKE_GOTHEALTHATLOW, pPlayer->i); + pPlayer->last_extra = newHealth; + } + + sprite[pPlayer->i].extra = newHealth; + } + } + + insptr++; + continue; + + case CON_ADDPHEALTH: + insptr++; + + { + if (!RR && pPlayer->newowner >= 0) + G_ClearCameraView(pPlayer); + + int newHealth = sprite[pPlayer->i].extra; + + if (vm.pSprite->picnum != ATOMICHEALTH) + { + if (newHealth > pPlayer->max_player_health && *insptr > 0) + { + insptr++; + continue; + } + else + { + if (newHealth > 0) + newHealth += *insptr; + if (newHealth > pPlayer->max_player_health && *insptr > 0) + newHealth = pPlayer->max_player_health; + } + } + else + { + if (newHealth > 0) + newHealth += *insptr; + if (newHealth > (pPlayer->max_player_health << 1)) + newHealth = (pPlayer->max_player_health << 1); + } + + if (newHealth < 0) + newHealth = 0; + + if (ud.god == 0) + { + if (*insptr > 0) + { + if ((newHealth - *insptr) < (pPlayer->max_player_health >> 2) && newHealth >= (pPlayer->max_player_health >> 2)) + A_PlaySound(DUKE_GOTHEALTHATLOW, pPlayer->i); + pPlayer->last_extra = newHealth; + } + + sprite[pPlayer->i].extra = newHealth; + } + } + + insptr++; + continue; + + case CON_MOVE: + insptr++; + AC_COUNT(vm.pData) = 0; + AC_MOVE_ID(vm.pData) = *insptr++; + vm.pSprite->hitag = *insptr++; + if (vm.pSprite->hitag & random_angle) + vm.pSprite->ang = krand2() & 2047; + continue; + + case CON_SPAWN: + insptr++; + if ((unsigned)vm.pSprite->sectnum >= MAXSECTORS) + { + CON_ERRPRINTF("invalid sector %d\n", vm.pUSprite->sectnum); + insptr++; + continue; + } + A_Spawn(vm.spriteNum, *insptr++); + continue; + + case CON_IFWASWEAPON: + case CON_IFSPAWNEDBY: + insptr++; + VM_CONDITIONAL(vm.pActor->picnum == *insptr); + continue; + + case CON_IFAI: + insptr++; + VM_CONDITIONAL(AC_AI_ID(vm.pData) == *insptr); + continue; + + case CON_IFACTION: + insptr++; + VM_CONDITIONAL(AC_ACTION_ID(vm.pData) == *insptr); + continue; + + case CON_IFACTIONCOUNT: + insptr++; + VM_CONDITIONAL(AC_ACTION_COUNT(vm.pData) >= *insptr); + continue; + + case CON_RESETACTIONCOUNT: + insptr++; + AC_ACTION_COUNT(vm.pData) = 0; + continue; + + case CON_DEBRIS: + insptr++; + { + int debrisTile = *insptr++; + + if ((unsigned)vm.pSprite->sectnum < MAXSECTORS) + for (native_t cnt = (*insptr) - 1; cnt >= 0; cnt--) + { + int const tileOffset = ((RR || vm.pSprite->picnum == BLIMP) && debrisTile == SCRAP1) ? 0 : (krand2() % 3); + + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(), r4 = krand2(), r5 = krand2(), r6 = krand2(), r7 = krand2(), r8 = krand2(); + int const spriteNum = A_InsertSprite(vm.pSprite->sectnum, vm.pSprite->x + (r8 & 255) - 128, + vm.pSprite->y + (r7 & 255) - 128, vm.pSprite->z - (8 << 8) - (r6 & 8191), + debrisTile + tileOffset, vm.pSprite->shade, 32 + (r5 & 15), 32 + (r4 & 15), + r3 & 2047, (r2 & 127) + 32, -(r1 & 2047), vm.spriteNum, 5); + + sprite[spriteNum].yvel = ((RR || vm.pSprite->picnum == BLIMP) && debrisTile == SCRAP1) ? g_blimpSpawnItems[cnt % 14] : -1; + sprite[spriteNum].pal = vm.pSprite->pal; + } + insptr++; + } + continue; + + case CON_COUNT: + insptr++; + AC_COUNT(vm.pData) = (int16_t)*insptr++; + continue; + + case CON_CSTATOR: + insptr++; + vm.pSprite->cstat |= (int16_t)*insptr++; + continue; + + case CON_CLIPDIST: + insptr++; + vm.pSprite->clipdist = (int16_t)*insptr++; + continue; + + case CON_CSTAT: + insptr++; + vm.pSprite->cstat = (int16_t)*insptr++; + continue; + + case CON_NEWPIC: + insptr++; + vm.pSprite->picnum = (int16_t)*insptr++; + continue; + + case CON_IFMOVE: + insptr++; + VM_CONDITIONAL(AC_MOVE_ID(vm.pData) == *insptr); + continue; + + case CON_RESETPLAYER: + insptr++; + vm.flags = VM_ResetPlayer(vm.playerNum, vm.flags); + continue; + + case CON_IFCOOP: + VM_CONDITIONAL(GTFLAGS(GAMETYPE_COOP) || numplayers > 2); + continue; + + case CON_IFONMUD: + VM_CONDITIONAL(sector[vm.pSprite->sectnum].floorpicnum == RRTILE3073 + && klabs(vm.pSprite->z - sector[vm.pSprite->sectnum].floorz) < ZOFFSET5); + continue; + + case CON_IFONWATER: + if (DEER) + { + VM_CONDITIONAL(sector[vm.pSprite->sectnum].hitag == 2003); + continue; + } + VM_CONDITIONAL(sector[vm.pSprite->sectnum].lotag == ST_1_ABOVE_WATER + && klabs(vm.pSprite->z - sector[vm.pSprite->sectnum].floorz) < ZOFFSET5); + continue; + + case CON_IFMOTOFAST: + VM_CONDITIONAL(pPlayer->moto_speed > 60); + continue; + + case CON_IFONMOTO: + VM_CONDITIONAL(pPlayer->on_motorcycle == 1); + continue; + + case CON_IFONBOAT: + VM_CONDITIONAL(pPlayer->on_boat == 1); + continue; + + case CON_IFSIZEDOWN: + vm.pSprite->xrepeat--; + vm.pSprite->yrepeat--; + VM_CONDITIONAL(vm.pSprite->xrepeat <= 5); + continue; + + case CON_IFWIND: + VM_CONDITIONAL(g_windTime > 0); + continue; + + case CON_IFPUPWIND: + VM_CONDITIONAL(ghtrax_isplrupwind(vm.spriteNum, vm.playerNum)); + continue; + + case CON_IFINWATER: + if (DEER) + { + VM_CONDITIONAL(sector[vm.pSprite->sectnum].hitag == 2003 && klabs(vm.pSprite->z - sector[vm.pSprite->sectnum].floorz) < ZOFFSET5); + continue; + } + VM_CONDITIONAL(sector[vm.pSprite->sectnum].lotag == ST_2_UNDERWATER); + continue; + + case CON_IFCOUNT: + insptr++; + VM_CONDITIONAL(AC_COUNT(vm.pData) >= *insptr); + continue; + + case CON_IFACTOR: + insptr++; + VM_CONDITIONAL(vm.pSprite->picnum == *insptr); + continue; + + case CON_RESETCOUNT: + insptr++; + AC_COUNT(vm.pData) = 0; + continue; + + case CON_ADDINVENTORY: + insptr += 2; + + VM_AddInventory(pPlayer, *(insptr - 1), *insptr); + + insptr++; + continue; + + case CON_HITRADIUS: + A_RadiusDamage(vm.spriteNum, *(insptr + 1), *(insptr + 2), *(insptr + 3), *(insptr + 4), *(insptr + 5)); + insptr += 6; + continue; + + case CON_IFP: + { + int const moveFlags = *(++insptr); + int nResult = 0; + int const playerXVel = sprite[pPlayer->i].xvel; + int const syncBits = g_player[vm.playerNum].input->bits; + + if (((moveFlags & pducking) && pPlayer->on_ground && (TEST_SYNC_KEY(syncBits, SK_CROUCH) ^ vm.pPlayer->crouch_toggle)) + || ((moveFlags & pfalling) && pPlayer->jumping_counter == 0 && !pPlayer->on_ground && pPlayer->vel.z > 2048) + || ((moveFlags & pjumping) && pPlayer->jumping_counter > 348) + || ((moveFlags & pstanding) && playerXVel >= 0 && playerXVel < 8) + || ((moveFlags & pwalking) && playerXVel >= 8 && !TEST_SYNC_KEY(syncBits, SK_RUN)) + || ((moveFlags & prunning) && playerXVel >= 8 && TEST_SYNC_KEY(syncBits, SK_RUN)) + || ((moveFlags & phigher) && pPlayer->pos.z < (vm.pSprite->z - (48 << 8))) + || ((moveFlags & pwalkingback) && playerXVel <= -8 && !TEST_SYNC_KEY(syncBits, SK_RUN)) + || ((moveFlags & prunningback) && playerXVel <= -8 && TEST_SYNC_KEY(syncBits, SK_RUN)) + || ((moveFlags & pkicking) + && (DEER ? ghsound_pfiredgunnear(vm.pSprite, vm.playerNum) :(pPlayer->quick_kick > 0 + || (pPlayer->curr_weapon == KNEE_WEAPON && pPlayer->kickback_pic > 0)))) + || ((moveFlags & pshrunk) && (DEER ? pPlayer->dhat60f && !sub_535EC() : sprite[pPlayer->i].xrepeat < (RR ? 8 : 32))) + || ((moveFlags & pjetpack) && pPlayer->jetpack_on) + || ((moveFlags & ponsteroids) && (DEER ? ghsound_pmadesound(vm.pSprite, vm.playerNum) : + pPlayer->inv_amount[GET_STEROIDS] > 0 && pPlayer->inv_amount[GET_STEROIDS] < 400)) + || ((moveFlags & ponground) && (DEER ? ghsound_pmadecall(vm.pSprite, vm.playerNum) : pPlayer->on_ground)) + || ((moveFlags & palive) && sprite[pPlayer->i].xrepeat > (RR ? 8 : 32) && sprite[pPlayer->i].extra > 0 && pPlayer->timebeforeexit == 0) + || ((moveFlags & pdead) && sprite[pPlayer->i].extra <= 0)) + nResult = 1; + else if ((moveFlags & pfacing)) + { + nResult + = (vm.pSprite->picnum == APLAYER && (g_netServer || ud.multimode > 1)) + ? G_GetAngleDelta(fix16_to_int(g_player[otherp].ps->q16ang), + getangle(pPlayer->pos.x - g_player[otherp].ps->pos.x, pPlayer->pos.y - g_player[otherp].ps->pos.y)) + : G_GetAngleDelta(fix16_to_int(pPlayer->q16ang), getangle(vm.pSprite->x - pPlayer->pos.x, vm.pSprite->y - pPlayer->pos.y)); + + nResult = (nResult > -128 && nResult < 128); + } + VM_CONDITIONAL(nResult); + } + continue; + + case CON_IFSTRENGTH: + insptr++; + VM_CONDITIONAL(vm.pSprite->extra <= *insptr); + continue; + + case CON_GUTS: + A_DoGuts(vm.spriteNum, *(insptr + 1), *(insptr + 2)); + insptr += 3; + continue; + + case CON_SLAPPLAYER: + insptr++; + P_ForceAngle(pPlayer); + pPlayer->vel.x -= sintable[(fix16_to_int(pPlayer->q16ang)+512)&2047]<<7; + pPlayer->vel.y -= sintable[fix16_to_int(pPlayer->q16ang)&2047]<<7; + continue; + + case CON_WACKPLAYER: + insptr++; + if (RR) + { + pPlayer->vel.x -= sintable[(fix16_to_int(pPlayer->q16ang)+512)&2047]<<7; + pPlayer->vel.y -= sintable[fix16_to_int(pPlayer->q16ang)&2047]<<7; + pPlayer->jumping_counter = 767; + pPlayer->jumping_toggle = 1; + } + else + P_ForceAngle(pPlayer); + continue; + + case CON_IFGAPZL: + insptr++; + VM_CONDITIONAL(((vm.pActor->floorz - vm.pActor->ceilingz) >> 8) < *insptr); + continue; + + case CON_IFHITSPACE: VM_CONDITIONAL(TEST_SYNC_KEY(g_player[vm.playerNum].input->bits, SK_OPEN)); continue; + + case CON_IFOUTSIDE: + if (DEER) + { + VM_CONDITIONAL(sector[vm.pSprite->sectnum].hitag = 2000); + continue; + } + VM_CONDITIONAL(sector[vm.pSprite->sectnum].ceilingstat & 1); + continue; + + case CON_IFMULTIPLAYER: VM_CONDITIONAL((g_netServer || g_netClient || ud.multimode > 1)); continue; + + case CON_OPERATE: + insptr++; + if (sector[vm.pSprite->sectnum].lotag == 0) + { + int16_t foundSect, foundWall, foundSprite; + int32_t foundDist; + + neartag(vm.pSprite->x, vm.pSprite->y, vm.pSprite->z - ZOFFSET5, vm.pSprite->sectnum, vm.pSprite->ang, &foundSect, &foundWall, + &foundSprite, &foundDist, 768, 4 + 1, NULL); + + if (foundSect >= 0 && isanearoperator(sector[foundSect].lotag)) + if ((sector[foundSect].lotag & 0xff) == ST_23_SWINGING_DOOR || sector[foundSect].floorz == sector[foundSect].ceilingz) + if ((sector[foundSect].lotag & (16384u | 32768u)) == 0) + { + int32_t j; + + for (SPRITES_OF_SECT(foundSect, j)) + if (sprite[j].picnum == ACTIVATOR) + break; + + if (j == -1) + G_OperateSectors(foundSect, vm.spriteNum); + } + } + continue; + + case CON_IFINSPACE: VM_CONDITIONAL(G_CheckForSpaceCeiling(vm.pSprite->sectnum)); continue; + + case CON_SPRITEPAL: + insptr++; + if (vm.pSprite->picnum != APLAYER) + vm.pActor->tempang = vm.pSprite->pal; + vm.pSprite->pal = *insptr++; + continue; + + case CON_CACTOR: + insptr++; + vm.pSprite->picnum = *insptr++; + continue; + + case CON_IFBULLETNEAR: VM_CONDITIONAL(A_Dodge(vm.pSprite) == 1); continue; + + case CON_IFRESPAWN: + if (A_CheckEnemySprite(vm.pSprite)) + VM_CONDITIONAL(ud.respawn_monsters) + else if (A_CheckInventorySprite(vm.pSprite)) + VM_CONDITIONAL(ud.respawn_inventory) + else + VM_CONDITIONAL(ud.respawn_items) + continue; + + case CON_IFFLOORDISTL: + insptr++; + VM_CONDITIONAL((vm.pActor->floorz - vm.pSprite->z) <= ((*insptr) << 8)); + continue; + + case CON_IFCEILINGDISTL: + insptr++; + VM_CONDITIONAL((vm.pSprite->z - vm.pActor->ceilingz) <= ((*insptr) << 8)); + continue; + + case CON_PALFROM: + insptr++; + if (EDUKE32_PREDICT_FALSE((unsigned)vm.playerNum >= (unsigned)g_mostConcurrentPlayers)) + { + CON_ERRPRINTF("invalid player %d\n", vm.playerNum); + insptr += 4; + } + else + { + palette_t const pal = { (uint8_t) * (insptr + 1), (uint8_t) * (insptr + 2), (uint8_t) * (insptr + 3), (uint8_t) * (insptr) }; + insptr += 4; + P_PalFrom(pPlayer, pal.f, pal.r, pal.g, pal.b); + } + continue; + + case CON_IFPHEALTHL: + insptr++; + VM_CONDITIONAL(sprite[pPlayer->i].extra < *insptr); + continue; + + case CON_IFPINVENTORY: + insptr++; + + switch (*insptr++) + { + case GET_STEROIDS: + case GET_SCUBA: + case GET_HOLODUKE: + case GET_HEATS: + case GET_FIRSTAID: + case GET_BOOTS: + case GET_JETPACK: tw = (pPlayer->inv_amount[*(insptr - 1)] != *insptr); break; + + case GET_SHIELD: + tw = (pPlayer->inv_amount[GET_SHIELD] != pPlayer->max_player_health); break; + case GET_ACCESS: + if (RR) + { + switch (vm.pSprite->lotag) + { + case 100: tw = pPlayer->keys[1]; break; + case 101: tw = pPlayer->keys[2]; break; + case 102: tw = pPlayer->keys[3]; break; + case 103: tw = pPlayer->keys[4]; break; + } + } + else + { + switch (vm.pSprite->pal) + { + case 0: tw = (pPlayer->got_access & 1); break; + case 21: tw = (pPlayer->got_access & 2); break; + case 23: tw = (pPlayer->got_access & 4); break; + } + } + break; + default: tw = 0; CON_ERRPRINTF("invalid inventory item %d\n", (int32_t) * (insptr - 1)); + } + + VM_CONDITIONAL(tw); + continue; + + case CON_PSTOMP: + insptr++; + if (pPlayer->knee_incs == 0 && sprite[pPlayer->i].xrepeat >= (RR ? 9 : 40)) + if (cansee(vm.pSprite->x, vm.pSprite->y, vm.pSprite->z - ZOFFSET6, vm.pSprite->sectnum, pPlayer->pos.x, pPlayer->pos.y, + pPlayer->pos.z + ZOFFSET2, sprite[pPlayer->i].sectnum)) + { + if (pPlayer->weapon_pos == 0) + pPlayer->weapon_pos = -1; + + pPlayer->actorsqu = vm.spriteNum; + pPlayer->knee_incs = 1; + } + continue; + + case CON_IFAWAYFROMWALL: + { + int16_t otherSectnum = vm.pSprite->sectnum; + tw = 0; + +#define IFAWAYDIST 108 + + updatesector(vm.pSprite->x + IFAWAYDIST, vm.pSprite->y + IFAWAYDIST, &otherSectnum); + if (otherSectnum == vm.pSprite->sectnum) + { + updatesector(vm.pSprite->x - IFAWAYDIST, vm.pSprite->y - IFAWAYDIST, &otherSectnum); + if (otherSectnum == vm.pSprite->sectnum) + { + updatesector(vm.pSprite->x + IFAWAYDIST, vm.pSprite->y - IFAWAYDIST, &otherSectnum); + if (otherSectnum == vm.pSprite->sectnum) + { + updatesector(vm.pSprite->x - IFAWAYDIST, vm.pSprite->y + IFAWAYDIST, &otherSectnum); + if (otherSectnum == vm.pSprite->sectnum) + tw = 1; + } + } + } + + VM_CONDITIONAL(tw); + +#undef IFAWAYDIST + } + continue; + + case CON_QUOTE: + insptr++; + + if (EDUKE32_PREDICT_FALSE((unsigned)(*insptr) >= MAXQUOTES)) + { + CON_ERRPRINTF("invalid quote %d\n", (int32_t)(*insptr)); + insptr++; + continue; + } + + if (EDUKE32_PREDICT_FALSE((unsigned)vm.playerNum >= MAXPLAYERS)) + { + CON_ERRPRINTF("invalid player %d\n", vm.playerNum); + insptr++; + continue; + } + + P_DoQuote(*(insptr++) | MAXQUOTES, pPlayer); + continue; + + case CON_IFINOUTERSPACE: VM_CONDITIONAL(G_CheckForSpaceFloor(vm.pSprite->sectnum)); continue; + + case CON_IFNOTMOVING: VM_CONDITIONAL((vm.pActor->movflag & 49152) > 16384); continue; + + case CON_RESPAWNHITAG: + insptr++; + switch (DYNAMICTILEMAP(vm.pSprite->picnum)) + { + case FEM1__STATIC: + case FEM2__STATIC: + case FEM3__STATIC: + case FEM4__STATIC: + case FEM5__STATIC: + case FEM6__STATIC: + case FEM7__STATIC: + case FEM8__STATIC: + case FEM9__STATIC: + case PODFEM1__STATIC: + if (RR) break; + fallthrough__; + case FEM10__STATIC: + case NAKED1__STATIC: + case STATUE__STATIC: + if (vm.pSprite->yvel) + G_OperateRespawns(vm.pSprite->yvel); + break; + default: + if (vm.pSprite->hitag >= 0) + G_OperateRespawns(vm.pSprite->hitag); + break; + } + continue; + + case CON_IFSPRITEPAL: + insptr++; + VM_CONDITIONAL(vm.pSprite->pal == *insptr); + continue; + + case CON_IFANGDIFFL: + insptr++; + tw = klabs(G_GetAngleDelta(fix16_to_int(pPlayer->q16ang), vm.pSprite->ang)); + VM_CONDITIONAL(tw <= *insptr); + continue; + + case CON_IFNOSOUNDS: VM_CONDITIONAL(!A_CheckAnySoundPlaying(vm.spriteNum)); continue; + + + case CON_IFVARG: + insptr++; + tw = Gv_GetVar(*insptr++); + VM_CONDITIONAL(tw > *insptr); + continue; + + case CON_IFVARL: + insptr++; + tw = Gv_GetVar(*insptr++); + VM_CONDITIONAL(tw < *insptr); + continue; + + case CON_SETVARVAR: + insptr++; + { + tw = *insptr++; + int const nValue = Gv_GetVar(*insptr++); + + if ((aGameVars[tw].flags & (GAMEVAR_USER_MASK | GAMEVAR_PTR_MASK)) == 0) + aGameVars[tw].global = nValue; + else + Gv_SetVar(tw, nValue); + } + continue; + + case CON_SETVAR: + Gv_SetVar(insptr[1], insptr[2]); + insptr += 3; + continue; + + case CON_ADDVARVAR: + insptr++; + tw = *insptr++; + Gv_AddVar(tw, Gv_GetVar(*insptr++)); + continue; + + case CON_ADDVAR: + Gv_AddVar(insptr[1], insptr[2]); + insptr += 3; + continue; + + case CON_IFVARVARL: + insptr++; + tw = Gv_GetVar(*insptr++); + tw = (tw < Gv_GetVar(*insptr++)); + insptr--; + VM_CONDITIONAL(tw); + continue; + + case CON_IFVARVARG: + insptr++; + tw = Gv_GetVar(*insptr++); + tw = (tw > Gv_GetVar(*insptr++)); + insptr--; + VM_CONDITIONAL(tw); + continue; + + case CON_ADDLOGVAR: + insptr++; + { + int32_t m = 1; + char szBuf[256]; + int32_t lVarID = *insptr; + + if ((lVarID >= g_gameVarCount) || lVarID < 0) + { + if (*insptr == MAXGAMEVARS) // addlogvar for a constant? Har. + insptr++; + else if (EDUKE32_PREDICT_TRUE(*insptr & GV_FLAG_NEGATIVE)) + { + m = -m; + lVarID ^= GV_FLAG_NEGATIVE; + } + else + { + // invalid varID + CON_ERRPRINTF("invalid variable\n"); + continue; + } + } + Bsprintf(tempbuf, "CONLOGVAR: L=%d %s ", VM_DECODE_LINE_NUMBER(g_tw), aGameVars[lVarID].szLabel); + + if (aGameVars[lVarID].flags & GAMEVAR_READONLY) + { + Bsprintf(szBuf, " (read-only)"); + Bstrcat(tempbuf, szBuf); + } + if (aGameVars[lVarID].flags & GAMEVAR_PERPLAYER) + { + Bsprintf(szBuf, " (Per Player. Player=%d)", vm.playerNum); + } + else if (aGameVars[lVarID].flags & GAMEVAR_PERACTOR) + { + Bsprintf(szBuf, " (Per Actor. Actor=%d)", vm.spriteNum); + } + else + { + Bsprintf(szBuf, " (Global)"); + } + Bstrcat(tempbuf, szBuf); + Bsprintf(szBuf, " =%d\n", Gv_GetVar(lVarID) * m); + Bstrcat(tempbuf, szBuf); + Printf(TEXTCOLOR_GREEN "%s", tempbuf); + insptr++; + continue; + } + + case CON_IFVARE: + insptr++; + tw = Gv_GetVar(*insptr++); + VM_CONDITIONAL(tw == *insptr); + continue; + + case CON_IFVARVARE: + insptr++; + tw = Gv_GetVar(*insptr++); + tw = (tw == Gv_GetVar(*insptr++)); + insptr--; + VM_CONDITIONAL(tw); + continue; + + default: // you aren't supposed to be here! + if (RR && ud.recstat == 2) + { + vm.flags |= VM_KILL; + return; + } + debug_break(); + VM_ScriptInfo(insptr, 64); + G_GameExit("An error has occurred in the " GAMENAME " virtual machine.\n\n"); +#if 0 + "If you are an end user, please e-mail the file " GAMENAMELOWERCASE ".log\n" + "along with links to any mods you're using to development@voidpoint.com.\n\n" + "If you are a developer, please attach all of your script files\n" + "along with instructions on how to reproduce this error.\n\n" + "Thank you!"); +#endif + break; + } + } +} + +void VM_UpdateAnim(int spriteNum, int32_t *pData) +{ + size_t const actionofs = AC_ACTION_ID(pData); + intptr_t const *actionptr = (actionofs != 0 && actionofs + (ACTION_PARAM_COUNT-1) < (unsigned) g_scriptSize) ? &apScript[actionofs] : NULL; + + if (actionptr != NULL) + { + int const action_frames = actionptr[ACTION_NUMFRAMES]; + int const action_incval = actionptr[ACTION_INCVAL]; + int const action_delay = actionptr[ACTION_DELAY]; + auto actionticsptr = &AC_ACTIONTICS(&sprite[spriteNum], &actor[spriteNum]); + *actionticsptr += TICSPERFRAME; + + if (*actionticsptr > action_delay) + { + *actionticsptr = 0; + AC_ACTION_COUNT(pData)++; + AC_CURFRAME(pData) += action_incval; + } + + if (klabs(AC_CURFRAME(pData)) >= klabs(action_frames * action_incval)) + AC_CURFRAME(pData) = 0; + } +} + +// NORECURSE +void A_Execute(int spriteNum, int playerNum, int playerDist) +{ + vmstate_t tempvm + = { spriteNum, playerNum, playerDist, 0, &sprite[spriteNum], &actor[spriteNum].t_data[0], g_player[playerNum].ps, &actor[spriteNum] }; + vm = tempvm; + +/* + if (g_netClient && A_CheckSpriteFlags(spriteNum, SFLAG_NULL)) + { + A_DeleteSprite(spriteNum); + return; + } +*/ + + //if (g_netClient) // [75] The server should not overwrite its own randomseed + // randomseed = ticrandomseed; + + if (EDUKE32_PREDICT_FALSE((unsigned)vm.pSprite->sectnum >= MAXSECTORS)) + { + if (A_CheckEnemySprite(vm.pSprite)) + P_AddKills(vm.pPlayer, 1); + + A_DeleteSprite(vm.spriteNum); + return; + } + + VM_UpdateAnim(vm.spriteNum, vm.pData); + + double t = timerGetHiTicks(); + int const picnum = vm.pSprite->picnum; + insptr = 4 + (g_tile[vm.pSprite->picnum].execPtr); + VM_Execute(1); + insptr = NULL; + + t = timerGetHiTicks()-t; + g_actorTotalMs[picnum] += t; + g_actorMinMs[picnum] = min(g_actorMinMs[picnum], t); + g_actorMaxMs[picnum] = max(g_actorMaxMs[picnum], t); + g_actorCalls[picnum]++; + + if (vm.flags & VM_KILL) + { + VM_DeleteSprite(spriteNum, playerNum); + return; + } + + VM_Move(); + + if (DEER || vm.pSprite->statnum != STAT_ACTOR) + { + if (vm.pSprite->statnum == STAT_STANDABLE) + { + switch (DYNAMICTILEMAP(vm.pSprite->picnum)) + { + case RUBBERCAN__STATIC: + case EXPLODINGBARREL__STATIC: + case WOODENHORSE__STATIC: + case HORSEONSIDE__STATIC: + case CANWITHSOMETHING__STATIC: + case FIREBARREL__STATIC: + case NUKEBARREL__STATIC: + case NUKEBARRELDENTED__STATIC: + case NUKEBARRELLEAKED__STATIC: + case TRIPBOMB__STATIC: + case EGG__STATIC: + if (vm.pActor->timetosleep > 1) + vm.pActor->timetosleep--; + else if (vm.pActor->timetosleep == 1) + changespritestat(vm.spriteNum, STAT_ZOMBIEACTOR); + default: break; + } + } + goto safe_delete; + } + + if (A_CheckEnemySprite(vm.pSprite)) + { + if (vm.pSprite->xrepeat > 60 || (ud.respawn_monsters == 1 && vm.pSprite->extra <= 0)) + goto safe_delete; + } + else if (EDUKE32_PREDICT_FALSE(ud.respawn_items == 1 && (vm.pSprite->cstat & 32768))) + goto safe_delete; + + if (A_CheckSpriteFlags(vm.spriteNum, SFLAG_USEACTIVATOR) && sector[vm.pSprite->sectnum].lotag & 16384) + changespritestat(vm.spriteNum, STAT_ZOMBIEACTOR); + else if (vm.pActor->timetosleep > 1) + vm.pActor->timetosleep--; + else if (vm.pActor->timetosleep == 1) + changespritestat(vm.spriteNum, STAT_ZOMBIEACTOR); + +safe_delete: + if (vm.flags & VM_SAFEDELETE) + A_DeleteSprite(spriteNum); +} +END_DUKE_NS diff --git a/source/duke/src/gameexec.h b/source/duke/src/gameexec.h new file mode 100644 index 000000000..53e207e49 --- /dev/null +++ b/source/duke/src/gameexec.h @@ -0,0 +1,95 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef gameexec_h_ +#define gameexec_h_ + +#include "build.h" +#include "sector.h" // mapstate_t +#include "gamedef.h" // vmstate_t + +BEGIN_DUKE_NS +int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum, int const nDist, int32_t const nReturn); +int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum, int const nDist); +int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum); +int32_t VM_ExecuteEventWithValue(int const nEventID, int const spriteNum, int const playerNum, int32_t const nReturn); + +static FORCE_INLINE int VM_HaveEvent(int const nEventID) +{ + return !!apScriptEvents[nEventID]; +} + +static FORCE_INLINE int32_t VM_OnEvent(int nEventID, int spriteNum, int playerNum, int nDist, int32_t nReturn) +{ + return VM_HaveEvent(nEventID) ? VM_ExecuteEvent(nEventID, spriteNum, playerNum, nDist, nReturn) : nReturn; +} + +static FORCE_INLINE int32_t VM_OnEvent(int nEventID, int spriteNum, int playerNum, int nDist) +{ + return VM_HaveEvent(nEventID) ? VM_ExecuteEvent(nEventID, spriteNum, playerNum, nDist) : 0; +} + +static FORCE_INLINE int32_t VM_OnEvent(int nEventID, int spriteNum = -1, int playerNum = -1) +{ + return VM_HaveEvent(nEventID) ? VM_ExecuteEvent(nEventID, spriteNum, playerNum) : 0; +} + +static FORCE_INLINE int32_t VM_OnEventWithReturn(int nEventID, int spriteNum, int playerNum, int32_t nReturn) +{ + return VM_HaveEvent(nEventID) ? VM_ExecuteEventWithValue(nEventID, spriteNum, playerNum, nReturn) : nReturn; +} + + +extern int32_t ticrandomseed; + +extern vmstate_t vm; +extern int32_t g_tw; +extern int32_t g_currentEvent; +extern int32_t g_errorLineNum; + +extern uint32_t g_actorCalls[MAXTILES]; +extern double g_actorTotalMs[MAXTILES], g_actorMinMs[MAXTILES], g_actorMaxMs[MAXTILES]; + +void A_Execute(int spriteNum, int playerNum, int playerDist); +void A_Fall(int spriteNum); +int32_t A_GetFurthestAngle(int spriteNum, int angDiv); +void A_GetZLimits(int spriteNum); +int32_t __fastcall G_GetAngleDelta(int32_t currAngle, int32_t newAngle); +fix16_t __fastcall G_GetQ16AngleDelta(fix16_t oldAngle, fix16_t newAngle); +//void G_RestoreMapState(); +//void G_SaveMapState(); + +#define CON_ERRPRINTF(Text, ...) do { \ + Printf("Line %d, %s: " Text, g_errorLineNum, VM_GetKeywordForID(g_tw), ## __VA_ARGS__); \ +} while (0) + +#define CON_CRITICALERRPRINTF(Text, ...) do { \ + I_Error("Line %d, %s: " Text, VM_DECODE_LINE_NUMBER(g_tw), VM_GetKeywordForID(VM_DECODE_INST(g_tw)), ## __VA_ARGS__); \ +} while (0) + +void G_GetTimeDate(int32_t * pValues); +int G_StartTrack(int levelNum); +void VM_UpdateAnim(int spriteNum, int32_t *pData); + +END_DUKE_NS + +#endif diff --git a/source/duke/src/gamevars.cpp b/source/duke/src/gamevars.cpp new file mode 100644 index 000000000..f81261d3d --- /dev/null +++ b/source/duke/src/gamevars.cpp @@ -0,0 +1,830 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! + +#include "duke3d.h" +#include "menus.h" +#include "savegame.h" +#include "namesdyn.h" +#include "gamevars.h" + +//#include "vfs.h" + +BEGIN_DUKE_NS + +#define gamevars_c_ + +gamevar_t aGameVars[MAXGAMEVARS]; +int32_t g_gameVarCount = 0; + +// pointers to weapon gamevar data +intptr_t *aplWeaponClip[MAX_WEAPONS]; // number of items in magazine +intptr_t *aplWeaponFireDelay[MAX_WEAPONS]; // delay to fire +intptr_t *aplWeaponFireSound[MAX_WEAPONS]; // Sound made when firing (each time for automatic) +intptr_t *aplWeaponFlags[MAX_WEAPONS]; // Flags for weapon +intptr_t *aplWeaponFlashColor[MAX_WEAPONS]; // Muzzle flash color +intptr_t *aplWeaponHoldDelay[MAX_WEAPONS]; // delay after release fire button to fire (0 for none) +intptr_t *aplWeaponInitialSound[MAX_WEAPONS]; // Sound made when weapon starts firing. zero for no sound +intptr_t *aplWeaponReload[MAX_WEAPONS]; // delay to reload (include fire) +intptr_t *aplWeaponShoots[MAX_WEAPONS]; // what the weapon shoots +intptr_t *aplWeaponShotsPerBurst[MAX_WEAPONS]; // number of shots per 'burst' (one ammo per 'burst') +intptr_t *aplWeaponSound2Sound[MAX_WEAPONS]; // Alternate sound sound ID +intptr_t *aplWeaponSound2Time[MAX_WEAPONS]; // Alternate sound time +intptr_t *aplWeaponSpawn[MAX_WEAPONS]; // the item to spawn +intptr_t *aplWeaponSpawnTime[MAX_WEAPONS]; // the frame at which to spawn an item +intptr_t *aplWeaponTotalTime[MAX_WEAPONS]; // The total time the weapon is cycling before next fire. +intptr_t *aplWeaponWorksLike[MAX_WEAPONS]; // What original the weapon works like + + +// Frees the memory for the *values* of game variables and arrays. Resets their +// counts to zero. Call this function as many times as needed. +// +// Returns: old g_gameVarCount | (g_gameArrayCount<<16). +int Gv_Free(void) +{ + for (auto &gameVar : aGameVars) + { + if (gameVar.flags & GAMEVAR_USER_MASK) + ALIGNED_FREE_AND_NULL(gameVar.pValues); + gameVar.flags |= GAMEVAR_RESET; + } + + EDUKE32_STATIC_ASSERT(MAXGAMEVARS < 32768); + int const varCount = g_gameVarCount; + g_gameVarCount = 0; + + hash_init(&h_gamevars); + + return varCount; +} + +// Calls Gv_Free() and in addition frees the labels of all game variables and +// arrays. +// Only call this function at exit +void Gv_Clear(void) +{ + Gv_Free(); + + // Now, only do work that Gv_Free() hasn't done. + for (auto & gameVar : aGameVars) + DO_FREE_AND_NULL(gameVar.szLabel); +} + +// Note that this entire function is totally architecture dependent and needs to be fixed (which won't be easy...) +int Gv_ReadSave(FileReader &kFile) +{ + char tbuf[12]; + + if (kFile.Read(tbuf, 12)!=12) goto corrupt; + if (Bmemcmp(tbuf, "BEG: EDuke32", 12)) { Printf("BEG ERR\n"); return 2; } + + Gv_Free(); // nuke 'em from orbit, it's the only way to be sure... + + if (kFile.Read(&g_gameVarCount,sizeof(g_gameVarCount)) != sizeof(g_gameVarCount)) goto corrupt; + for (bssize_t i=0; i= MAXGAMEVARS)) + { + g_errorCnt++; + C_ReportError(-1); + Printf("%s:%d: error: too many gamevars!\n",g_scriptFileName,g_lineNumber); + return; + } + + if (EDUKE32_PREDICT_FALSE(Bstrlen(pszLabel) > (MAXVARLABEL-1))) + { + g_errorCnt++; + C_ReportError(-1); + Printf("%s:%d: error: variable name `%s' exceeds limit of %d characters.\n",g_scriptFileName,g_lineNumber,pszLabel, MAXVARLABEL); + return; + } + + int gV = hash_find(&h_gamevars,pszLabel); + + if (gV >= 0 && !(aGameVars[gV].flags & GAMEVAR_RESET)) + { + // found it... + if (EDUKE32_PREDICT_FALSE(aGameVars[gV].flags & (GAMEVAR_PTR_MASK))) + { + C_ReportError(-1); + Printf("%s:%d: warning: cannot redefine internal gamevar `%s'.\n",g_scriptFileName,g_lineNumber,label+(g_labelCnt<<6)); + return; + } + else if (EDUKE32_PREDICT_FALSE(!(aGameVars[gV].flags & GAMEVAR_SYSTEM))) + { + // it's a duplicate in error + g_warningCnt++; + C_ReportError(WARNING_DUPLICATEDEFINITION); + return; + } + } + + if (gV == -1) + gV = g_gameVarCount; + + // If it's a user gamevar... + if ((aGameVars[gV].flags & GAMEVAR_SYSTEM) == 0) + { + // Allocate and set its label + if (aGameVars[gV].szLabel == NULL) + aGameVars[gV].szLabel = (char *)Xcalloc(MAXVARLABEL,sizeof(uint8_t)); + + if (aGameVars[gV].szLabel != pszLabel) + Bstrcpy(aGameVars[gV].szLabel,pszLabel); + + // and the flags + aGameVars[gV].flags=dwFlags; + + // only free if per-{actor,player} + if (aGameVars[gV].flags & GAMEVAR_USER_MASK) + ALIGNED_FREE_AND_NULL(aGameVars[gV].pValues); + } + + // if existing is system, they only get to change default value.... + aGameVars[gV].defaultValue = lValue; + aGameVars[gV].flags &= ~GAMEVAR_RESET; + + if (gV == g_gameVarCount) + { + // we're adding a new one. + hash_add(&h_gamevars, aGameVars[gV].szLabel, g_gameVarCount++, 0); + } + + // Set initial values. (Or, override values for system gamevars.) + if (aGameVars[gV].flags & GAMEVAR_PERPLAYER) + { + if (!aGameVars[gV].pValues) + { + aGameVars[gV].pValues = (intptr_t *) Xaligned_alloc(PLAYER_VAR_ALIGNMENT, MAXPLAYERS * sizeof(intptr_t)); + Bmemset(aGameVars[gV].pValues, 0, MAXPLAYERS * sizeof(intptr_t)); + } + for (bssize_t j=MAXPLAYERS-1; j>=0; --j) + aGameVars[gV].pValues[j]=lValue; + } + else if (aGameVars[gV].flags & GAMEVAR_PERACTOR) + { + if (!aGameVars[gV].pValues) + { + aGameVars[gV].pValues = (intptr_t *) Xaligned_alloc(ACTOR_VAR_ALIGNMENT, MAXSPRITES * sizeof(intptr_t)); + Bmemset(aGameVars[gV].pValues, 0, MAXSPRITES * sizeof(intptr_t)); + } + for (bssize_t j=MAXSPRITES-1; j>=0; --j) + aGameVars[gV].pValues[j]=lValue; + } + else aGameVars[gV].global = lValue; +} + +static int Gv_GetVarIndex(const char *szGameLabel) +{ + int const gameVar = hash_find(&h_gamevars,szGameLabel); + + if (EDUKE32_PREDICT_FALSE((unsigned)gameVar >= MAXGAMEVARS)) + { + Printf(TEXTCOLOR_RED "Gv_GetVarIndex(): INTERNAL ERROR: couldn't find gamevar %s!\n", szGameLabel); + return 0; + } + + return gameVar; +} + +static FORCE_INLINE int __fastcall getvar__(int const gameVar, int const spriteNum, int const playerNum) +{ + auto const &var = aGameVars[gameVar & (MAXGAMEVARS-1)]; + + int returnValue = 0; + int const varFlags = var.flags & (GAMEVAR_USER_MASK|GAMEVAR_PTR_MASK); + + if (!varFlags) returnValue = var.global; + else if (varFlags == GAMEVAR_PERACTOR) + returnValue = var.pValues[spriteNum & (MAXSPRITES-1)]; + else if (varFlags == GAMEVAR_PERPLAYER) + returnValue = var.pValues[playerNum & (MAXPLAYERS-1)]; + else switch (varFlags & GAMEVAR_PTR_MASK) + { + case GAMEVAR_RAWQ16PTR: + case GAMEVAR_INT32PTR: returnValue = *(int32_t *)var.global; break; + case GAMEVAR_INT16PTR: returnValue = *(int16_t *)var.global; break; + case GAMEVAR_Q16PTR: returnValue = fix16_to_int(*(fix16_t *)var.global); break; + } + + return NEGATE_ON_CONDITION(returnValue, gameVar & GV_FLAG_NEGATIVE); +} + +int __fastcall Gv_GetVar(int const gameVar, int const spriteNum, int const playerNum) { return getvar__(gameVar, spriteNum, playerNum); } +int __fastcall Gv_GetVar(int const gameVar) { return getvar__(gameVar, vm.spriteNum, vm.playerNum); } + +void __fastcall Gv_GetManyVars(int const numVars, int32_t * const outBuf) +{ + for (native_t j = 0; j < numVars; ++j) + outBuf[j] = getvar__(*insptr++, vm.spriteNum, vm.playerNum); +} + +static FORCE_INLINE void __fastcall setvar__(int const gameVar, int const newValue, int const spriteNum, int const playerNum) +{ + gamevar_t &var = aGameVars[gameVar]; + int const varFlags = var.flags & (GAMEVAR_USER_MASK|GAMEVAR_PTR_MASK); + + if (!varFlags) var.global=newValue; + else if (varFlags == GAMEVAR_PERACTOR) + var.pValues[spriteNum & (MAXSPRITES-1)] = newValue; + else if (varFlags == GAMEVAR_PERPLAYER) + var.pValues[playerNum & (MAXPLAYERS-1)] = newValue; + else switch (varFlags & GAMEVAR_PTR_MASK) + { + case GAMEVAR_RAWQ16PTR: + case GAMEVAR_INT32PTR: *((int32_t *)var.global) = (int32_t)newValue; break; + case GAMEVAR_INT16PTR: *((int16_t *)var.global) = (int16_t)newValue; break; + case GAMEVAR_Q16PTR: *(fix16_t *)var.global = fix16_from_int((int16_t)newValue); break; + } + return; +} + +void __fastcall Gv_SetVar(int const gameVar, int const newValue) { setvar__(gameVar, newValue, vm.spriteNum, vm.playerNum); } +void __fastcall Gv_SetVar(int const gameVar, int const newValue, int const spriteNum, int const playerNum) +{ + setvar__(gameVar, newValue, spriteNum, playerNum); +} + +int Gv_GetVarByLabel(const char *szGameLabel, int const defaultValue, int const spriteNum, int const playerNum) +{ + int const gameVar = hash_find(&h_gamevars, szGameLabel); + return EDUKE32_PREDICT_TRUE(gameVar >= 0) ? Gv_GetVar(gameVar, spriteNum, playerNum) : defaultValue; +} + +static intptr_t *Gv_GetVarDataPtr(const char *szGameLabel) +{ + int const gameVar = hash_find(&h_gamevars, szGameLabel); + + if (EDUKE32_PREDICT_FALSE((unsigned)gameVar >= MAXGAMEVARS)) + return NULL; + + gamevar_t &var = aGameVars[gameVar]; + + if (var.flags & (GAMEVAR_USER_MASK | GAMEVAR_PTR_MASK)) + return var.pValues; + + return &(var.global); +} + +void Gv_ResetSystemDefaults(void) +{ + // call many times... + char aszBuf[64]; + + //AddLog("ResetWeaponDefaults"); + + for (int weaponNum = 0; weaponNum < MAX_WEAPONS; ++weaponNum) + { + for (int playerNum = 0; playerNum < MAXPLAYERS; ++playerNum) + { + Bsprintf(aszBuf, "WEAPON%d_CLIP", weaponNum); + aplWeaponClip[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_RELOAD", weaponNum); + aplWeaponReload[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_FIREDELAY", weaponNum); + aplWeaponFireDelay[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_TOTALTIME", weaponNum); + aplWeaponTotalTime[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_HOLDDELAY", weaponNum); + aplWeaponHoldDelay[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_FLAGS", weaponNum); + aplWeaponFlags[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_SHOOTS", weaponNum); + aplWeaponShoots[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + if ((unsigned)aplWeaponShoots[weaponNum][playerNum] >= MAXTILES) + aplWeaponShoots[weaponNum][playerNum] = 0; + Bsprintf(aszBuf, "WEAPON%d_SPAWNTIME", weaponNum); + aplWeaponSpawnTime[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_SPAWN", weaponNum); + aplWeaponSpawn[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_SHOTSPERBURST", weaponNum); + aplWeaponShotsPerBurst[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_WORKSLIKE", weaponNum); + aplWeaponWorksLike[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_INITIALSOUND", weaponNum); + aplWeaponInitialSound[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_FIRESOUND", weaponNum); + aplWeaponFireSound[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_SOUND2TIME", weaponNum); + aplWeaponSound2Time[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_SOUND2SOUND", weaponNum); + aplWeaponSound2Sound[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + Bsprintf(aszBuf, "WEAPON%d_FLASHCOLOR", weaponNum); + aplWeaponFlashColor[weaponNum][playerNum] = Gv_GetVarByLabel(aszBuf, 0, -1, playerNum); + } + } + + g_aimAngleVarID = Gv_GetVarIndex("AUTOAIMANGLE"); + g_angRangeVarID = Gv_GetVarIndex("ANGRANGE"); + g_returnVarID = Gv_GetVarIndex("RETURN"); + g_weaponVarID = Gv_GetVarIndex("WEAPON"); + g_worksLikeVarID = Gv_GetVarIndex("WORKSLIKE"); + g_zRangeVarID = Gv_GetVarIndex("ZRANGE"); + + //AddLog("EOF:ResetWeaponDefaults"); +} + +// Will set members that were overridden at CON translation time to 1. +// For example, if +// gamevar WEAPON1_SHOOTS 2200 GAMEVAR_PERPLAYER +// was specified at file scope, g_weaponOverridden[1].Shoots will be 1. +weapondata_t g_weaponOverridden[MAX_WEAPONS]; + +static weapondata_t weapondefaults[MAX_WEAPONS] = { + /* + WorksLike, Clip, Reload, FireDelay, TotalTime, HoldDelay, + Flags, + Shoots, SpawnTime, Spawn, ShotsPerBurst, InitialSound, FireSound, Sound2Time, Sound2Sound, + FlashColor + */ + { + KNEE_WEAPON__STATIC, 0, 30, 7, 14, 14, + WEAPON_RANDOMRESTART | WEAPON_AUTOMATIC, + KNEE__STATIC, 0, 0, 0, 0, 0, 0, + 0 + }, + + { + PISTOL_WEAPON, 20, 50, 2, 5, 0, + WEAPON_AUTOMATIC | WEAPON_HOLSTER_CLEARS_CLIP, + SHOTSPARK1__STATIC, 2, SHELL__STATIC, 0, 0, PISTOL_FIRE__STATIC, 0, 0, + 255+(95<<8) + }, + + { + SHOTGUN_WEAPON__STATIC, 0, 13, 4, 31, 0, + WEAPON_CHECKATRELOAD, + SHOTGUN__STATIC, 24, SHOTGUNSHELL__STATIC, 7, 0, SHOTGUN_FIRE__STATIC, 15, SHOTGUN_COCK__STATIC, + 255+(95<<8) + }, + + { + CHAINGUN_WEAPON__STATIC, 0, 30, 1, 12, 10, + WEAPON_AUTOMATIC | WEAPON_FIREEVERYTHIRD | WEAPON_AMMOPERSHOT, + CHAINGUN__STATIC, 0, SHELL__STATIC, 0, 0, CHAINGUN_FIRE__STATIC, 0, 0, + 255+(95<<8) + }, + + { + RPG_WEAPON__STATIC, 0, 30, 4, 20, 0, + 0, + RPG__STATIC, 0, 0, 0, 0, 0, 0, 0, + 255+(95<<8) + }, + + { + HANDBOMB_WEAPON__STATIC, 0, 30, 6, 19, 12, + WEAPON_THROWIT, + HEAVYHBOMB__STATIC, 0, 0, 0, 0, 0, 0, + 0 + }, + + { + SHRINKER_WEAPON__STATIC, 0, 0, 10, 30, 0, + WEAPON_GLOWS, + SHRINKER__STATIC, 0, 0, 0, SHRINKER_FIRE__STATIC, 0, 0, 0, + 176+(252<<8)+(120<<16) + }, + + { + DEVISTATOR_WEAPON__STATIC, 0, 30, 2, 5, 5, + WEAPON_FIREEVERYOTHER, + RPG__STATIC, 0, 0, 2, CAT_FIRE__STATIC, 0, 0, 0, + 255+(95<<8) + }, + + { + TRIPBOMB_WEAPON__STATIC, 0, 30, 3, 16, 0, + WEAPON_STANDSTILL, + HANDHOLDINGLASER__STATIC, 0, 0, 0, 0, 0, 0, + 0 + }, + + { + FREEZE_WEAPON__STATIC, 0, 0, 3, 5, 0, + WEAPON_FIREEVERYOTHER, + FREEZEBLAST__STATIC, 0, 0, 0, CAT_FIRE__STATIC, CAT_FIRE__STATIC, 0, 0, + 72+(88<<8)+(140<<16) + }, + + { + HANDREMOTE_WEAPON__STATIC, 0, 30, 2, 10, 0, + WEAPON_BOMB_TRIGGER | WEAPON_NOVISIBLE, + 0, 0, 0, 0, 0, 0, 0, + 0 + }, + + { + GROW_WEAPON__STATIC, 0, 0, 3, 30, 0, + WEAPON_GLOWS, + GROWSPARK__STATIC, 0, 0, 0, EXPANDERSHOOT__STATIC, EXPANDERSHOOT__STATIC, 0, 0, + 216+(52<<8)+(20<<16) + }, +}; + +// KEEPINSYNC with what is contained above +// XXX: ugly +static int32_t G_StaticToDynamicTile(int32_t const tile) +{ + switch (tile) + { +#ifndef EDUKE32_STANDALONE + case CHAINGUN__STATIC: return CHAINGUN; + case FREEZEBLAST__STATIC: return FREEZEBLAST; + case GROWSPARK__STATIC: return GROWSPARK; + case HANDHOLDINGLASER__STATIC: return HANDHOLDINGLASER; + case HEAVYHBOMB__STATIC: return HEAVYHBOMB; + case KNEE__STATIC: return KNEE; + case RPG__STATIC: return RPG; + case SHELL__STATIC: return SHELL; + case SHOTGUNSHELL__STATIC: return SHOTGUNSHELL; + case SHOTGUN__STATIC: return SHOTGUN; + case SHOTSPARK1__STATIC: return SHOTSPARK1; + case SHRINKER__STATIC: return SHRINKER; +#endif + default: return tile; + } +} + +static int32_t G_StaticToDynamicSound(int32_t const sound) +{ + switch (sound) + { +#ifndef EDUKE32_STANDALONE + case CAT_FIRE__STATIC: return CAT_FIRE; + case CHAINGUN_FIRE__STATIC: return CHAINGUN_FIRE; + case EJECT_CLIP__STATIC: return EJECT_CLIP; + case EXPANDERSHOOT__STATIC: return EXPANDERSHOOT; + case INSERT_CLIP__STATIC: return INSERT_CLIP; + case PISTOL_FIRE__STATIC: return PISTOL_FIRE; + case SELECT_WEAPON__STATIC: return SELECT_WEAPON; + case SHOTGUN_FIRE__STATIC: return SHOTGUN_FIRE; + case SHOTGUN_COCK__STATIC: return SHOTGUN_COCK; + case SHRINKER_FIRE__STATIC: return SHRINKER_FIRE; +#endif + default: return sound; + } +} + +// Initialize WEAPONx_* gamevars. In C-CON, a new CON variable is defined together with +// its initial value. +# define ADDWEAPONVAR(Weapidx, Membname) do { \ + FStringf aszBuf("WEAPON%d_" #Membname, Weapidx); \ + aszBuf.ToUpper(); \ + Gv_NewVar(aszBuf, weapondefaults[Weapidx].Membname, GAMEVAR_PERPLAYER | GAMEVAR_SYSTEM); \ +} while (0) + +// After CON translation, get not-overridden members from weapondefaults[] back +// into the live arrays! +// NYI +# define POSTADDWEAPONVAR(Weapidx, Membname) do {} while (0) + +// Finish a default weapon member after CON translation. If it was not +// overridden from CON itself (see example at g_weaponOverridden[]), we set +// both the weapondefaults[] entry (probably dead by now) and the live value. +#define FINISH_WEAPON_DEFAULT_X(What, i, Membname) do { \ + if (!g_weaponOverridden[i].Membname) \ + { \ + weapondefaults[i].Membname = G_StaticToDynamic##What(weapondefaults[i].Membname); \ + POSTADDWEAPONVAR(i, Membname); \ + } \ +} while (0) + +#define FINISH_WEAPON_DEFAULT_TILE(i, Membname) FINISH_WEAPON_DEFAULT_X(Tile, i, Membname) +#define FINISH_WEAPON_DEFAULT_SOUND(i, Membname) FINISH_WEAPON_DEFAULT_X(Sound, i, Membname) + +// Process the dynamic {tile,sound} mappings after CON has been translated. +// We cannot do this before, because the dynamic maps are not yet set up then. +void Gv_FinalizeWeaponDefaults(void) +{ + for (int i=0; i=0; i--) + { + Bsprintf(aszBuf, "WEAPON%d_CLIP", i); + aplWeaponClip[i] = Gv_GetVarDataPtr(aszBuf); + + if (!aplWeaponClip[i]) + { + I_Error("ERROR: NULL weapon! WTF?! %s\n", aszBuf); + } + + Bsprintf(aszBuf, "WEAPON%d_RELOAD", i); + aplWeaponReload[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_FIREDELAY", i); + aplWeaponFireDelay[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_TOTALTIME", i); + aplWeaponTotalTime[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_HOLDDELAY", i); + aplWeaponHoldDelay[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_FLAGS", i); + aplWeaponFlags[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_SHOOTS", i); + aplWeaponShoots[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_SPAWNTIME", i); + aplWeaponSpawnTime[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_SPAWN", i); + aplWeaponSpawn[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_SHOTSPERBURST", i); + aplWeaponShotsPerBurst[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_WORKSLIKE", i); + aplWeaponWorksLike[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_INITIALSOUND", i); + aplWeaponInitialSound[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_FIRESOUND", i); + aplWeaponFireSound[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_SOUND2TIME", i); + aplWeaponSound2Time[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_SOUND2SOUND", i); + aplWeaponSound2Sound[i] = Gv_GetVarDataPtr(aszBuf); + Bsprintf(aszBuf, "WEAPON%d_FLASHCOLOR", i); + aplWeaponFlashColor[i] = Gv_GetVarDataPtr(aszBuf); + } +} + +void Gv_RefreshPointers(void) +{ + aGameVars[Gv_GetVarIndex("COOP")].global = (intptr_t)&ud.coop; + aGameVars[Gv_GetVarIndex("FFIRE")].global = (intptr_t)&ud.ffire; + aGameVars[Gv_GetVarIndex("LEVEL")].global = (intptr_t)&ud.level_number; + aGameVars[Gv_GetVarIndex("MARKER")].global = (intptr_t)&ud.marker; + aGameVars[Gv_GetVarIndex("MONSTERS_OFF")].global = (intptr_t)&ud.monsters_off; + aGameVars[Gv_GetVarIndex("MULTIMODE")].global = (intptr_t)&ud.multimode; + aGameVars[Gv_GetVarIndex("RESPAWN_INVENTORY")].global = (intptr_t)&ud.respawn_inventory; + aGameVars[Gv_GetVarIndex("RESPAWN_ITEMS")].global = (intptr_t)&ud.respawn_items; + aGameVars[Gv_GetVarIndex("RESPAWN_MONSTERS")].global = (intptr_t)&ud.respawn_monsters; + aGameVars[Gv_GetVarIndex("VOLUME")].global = (intptr_t)&ud.volume_number; +} + +END_DUKE_NS diff --git a/source/duke/src/gamevars.h b/source/duke/src/gamevars.h new file mode 100644 index 000000000..e2e26fb6b --- /dev/null +++ b/source/duke/src/gamevars.h @@ -0,0 +1,151 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef gamevars_h_ +#define gamevars_h_ + +#include "gamedef.h" + +BEGIN_DUKE_NS + +#define MAXGAMEVARS 2048 // must be a power of two +#define MAXVARLABEL 26 + +#define GV_FLAG_CONSTANT (MAXGAMEVARS) +#define GV_FLAG_NEGATIVE (MAXGAMEVARS<<1) + +// store global game definitions +enum GamevarFlags_t +{ + GAMEVAR_PERPLAYER = 0x00000001, // per-player variable + GAMEVAR_PERACTOR = 0x00000002, // per-actor variable + GAMEVAR_USER_MASK = (GAMEVAR_PERPLAYER | GAMEVAR_PERACTOR), + GAMEVAR_RESET = 0x00000008, // INTERNAL, don't use + GAMEVAR_DEFAULT = 0x00000100, // UNUSED, but always cleared for user-defined gamevars + GAMEVAR_NODEFAULT = 0x00000400, // don't reset on actor spawn + GAMEVAR_SYSTEM = 0x00000800, // cannot change mode flags...(only default value) + GAMEVAR_READONLY = 0x00001000, // values are read-only (no setvar allowed) + GAMEVAR_INT32PTR = 0x00002000, // plValues is a pointer to an int32_t + GAMEVAR_INT16PTR = 0x00008000, // plValues is a pointer to a short + GAMEVAR_NORESET = 0x00020000, // var values are not reset when restoring map state + GAMEVAR_SPECIAL = 0x00040000, // flag for structure member shortcut vars + GAMEVAR_NOMULTI = 0x00080000, // don't attach to multiplayer packets + GAMEVAR_Q16PTR = 0x00100000, // plValues is a pointer to a q16.16 + GAMEVAR_SERIALIZE = 0x00200000, // write into permasaves + + GAMEVAR_RAWQ16PTR = GAMEVAR_Q16PTR | GAMEVAR_SPECIAL, // plValues is a pointer to a q16.16 but we don't want conversion + GAMEVAR_PTR_MASK = GAMEVAR_INT32PTR | GAMEVAR_INT16PTR | GAMEVAR_Q16PTR | GAMEVAR_RAWQ16PTR, +}; + +// Alignments for per-player and per-actor variables. +#define PLAYER_VAR_ALIGNMENT (sizeof(intptr_t)) +#define ACTOR_VAR_ALIGNMENT 16 + +#define ARRAY_ALIGNMENT 16 + +#pragma pack(push,1) +typedef struct +{ + union { + intptr_t global; + intptr_t *pValues; // array of values when 'per-player', or 'per-actor' + }; + intptr_t defaultValue; + uintptr_t flags; + char * szLabel; +} gamevar_t; +#pragma pack(pop) + +extern gamevar_t aGameVars[MAXGAMEVARS]; +extern int32_t g_gameVarCount; + +int __fastcall Gv_GetVar(int const gameVar, int const spriteNum, int const playerNum); +void __fastcall Gv_SetVar(int const gameVar, int const newValue, int const spriteNum, int const playerNum); +int __fastcall Gv_GetVar(int const gameVar); +void __fastcall Gv_GetManyVars(int const numVars, int32_t * const outBuf); +void __fastcall Gv_SetVar(int const gameVar, int const newValue); + +template +static FORCE_INLINE void Gv_FillWithVars(T & rv) +{ + EDUKE32_STATIC_ASSERT(sizeof(T) % sizeof(int32_t) == 0); + EDUKE32_STATIC_ASSERT(sizeof(T) > sizeof(int32_t)); + Gv_GetManyVars(sizeof(T)/sizeof(int32_t), (int32_t *)&rv); +} + +int Gv_GetVarByLabel(const char *szGameLabel,int defaultValue,int spriteNum,int playerNum); +void Gv_NewVar(const char *pszLabel,intptr_t lValue,uint32_t dwFlags); + +static FORCE_INLINE void A_ResetVars(int const spriteNum) +{ + for (auto &gv : aGameVars) + { + if ((gv.flags & (GAMEVAR_PERACTOR|GAMEVAR_NODEFAULT)) == GAMEVAR_PERACTOR) + gv.pValues[spriteNum] = gv.defaultValue; + } +} +void Gv_DumpValues(void); +void Gv_InitWeaponPointers(void); +void Gv_RefreshPointers(void); +void Gv_ResetVars(void); +int Gv_ReadSave(FileReader &kFile); +void Gv_WriteSave(FileWriter &fil); +void Gv_Clear(void); + +void Gv_ResetSystemDefaults(void); +void Gv_Init(void); +void Gv_FinalizeWeaponDefaults(void); + +#define VM_GAMEVAR_OPERATOR(func, operator) \ + static FORCE_INLINE ATTRIBUTE((flatten)) void __fastcall func(int const id, int32_t const operand) \ + { \ + auto &var = aGameVars[id]; \ + \ + switch (var.flags & (GAMEVAR_USER_MASK | GAMEVAR_PTR_MASK)) \ + { \ + default: \ + var.global operator operand; \ + break; \ + case GAMEVAR_PERPLAYER: \ + var.pValues[vm.playerNum & (MAXPLAYERS-1)] operator operand; \ + break; \ + case GAMEVAR_PERACTOR: \ + var.pValues[vm.spriteNum & (MAXSPRITES-1)] operator operand; \ + break; \ + case GAMEVAR_INT32PTR: *(int32_t *)var.pValues operator(int32_t) operand; break; \ + case GAMEVAR_INT16PTR: *(int16_t *)var.pValues operator(int16_t) operand; break; \ + case GAMEVAR_Q16PTR: \ + { \ + Fix16 *pfix = (Fix16 *)var.global; \ + *pfix operator fix16_from_int(operand); \ + break; \ + } \ + } \ + } + +VM_GAMEVAR_OPERATOR(Gv_AddVar, +=) +VM_GAMEVAR_OPERATOR(Gv_SubVar, -=) + +#undef VM_GAMEVAR_OPERATOR + +END_DUKE_NS +#endif diff --git a/source/duke/src/global.cpp b/source/duke/src/global.cpp new file mode 100644 index 000000000..b3a6b93cc --- /dev/null +++ b/source/duke/src/global.cpp @@ -0,0 +1,123 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- +#include "ns.h" // Must come before everything else! + +#define global_c_ +#include "global.h" +#include "duke3d.h" + +BEGIN_DUKE_NS + +user_defs ud; + +const char *s_buildDate = "20120522"; + +char g_gametypeNames[MAXGAMETYPES][33] += { "DukeMatch (Spawn)", "Cooperative Play", "DukeMatch (No Spawn)", "Team DM (Spawn)", "Team DM (No Spawn)" }; + +int32_t g_gametypeFlags[MAXGAMETYPES] = +{ + GAMETYPE_FRAGBAR | + GAMETYPE_SCORESHEET | + GAMETYPE_DMSWITCHES | + GAMETYPE_ITEMRESPAWN | + GAMETYPE_MARKEROPTION | + GAMETYPE_ACCESSATSTART, + + GAMETYPE_COOP | + GAMETYPE_WEAPSTAY | + GAMETYPE_COOPSPAWN | + GAMETYPE_ACCESSCARDSPRITES | + GAMETYPE_COOPVIEW | + GAMETYPE_COOPSOUND | + GAMETYPE_OTHERPLAYERSINMAP | + GAMETYPE_PLAYERSFRIENDLY | + GAMETYPE_FIXEDRESPAWN | + GAMETYPE_PRESERVEINVENTORYDEATH, + + GAMETYPE_WEAPSTAY | + GAMETYPE_FRAGBAR | + GAMETYPE_SCORESHEET | + GAMETYPE_DMSWITCHES | + GAMETYPE_ACCESSATSTART, + + GAMETYPE_FRAGBAR | + GAMETYPE_SCORESHEET | + GAMETYPE_DMSWITCHES | + GAMETYPE_ITEMRESPAWN | + GAMETYPE_MARKEROPTION | + GAMETYPE_ACCESSATSTART | + GAMETYPE_TDM | + GAMETYPE_TDMSPAWN, + + GAMETYPE_WEAPSTAY | + GAMETYPE_FRAGBAR | + GAMETYPE_SCORESHEET | + GAMETYPE_DMSWITCHES | + GAMETYPE_ACCESSATSTART | + GAMETYPE_TDM | + GAMETYPE_TDMSPAWN, +}; + +float g_gameUpdateAvgTime = -1.f; + +int32_t g_actorRespawnTime = 768; +int32_t g_bouncemineRadius = 2500; +int32_t g_deleteQueueSize = 64; +int32_t g_itemRespawnTime = 768; + +int32_t g_morterRadius = 2500; +int32_t g_numFreezeBounces = 3; +int32_t g_gametypeCnt = 5; +int32_t g_volumeCnt = 3; +int32_t g_pipebombRadius = 2500; +int32_t g_playerFriction = 0xCFD0; +int32_t g_rpgRadius = 1780; +int32_t g_scriptSize = 1048576; +int32_t g_seenineRadius = 2048; +int32_t g_shrinkerRadius = 650; +int32_t g_spriteGravity = 176; +int32_t g_timerTicsPerSecond = TICRATE; +int32_t g_tripbombRadius = 3880; + +int16_t g_blimpSpawnItems[15] = +{ + RPGSPRITE__STATIC, + CHAINGUNSPRITE__STATIC, + DEVISTATORAMMO__STATIC, + RPGAMMO__STATIC, + RPGAMMO__STATIC, + JETPACK__STATIC, + SHIELD__STATIC, + FIRSTAID__STATIC, + STEROIDS__STATIC, + RPGAMMO__STATIC, + RPGAMMO__STATIC, + RPGSPRITE__STATIC, + RPGAMMO__STATIC, + FREEZESPRITE__STATIC, + FREEZEAMMO__STATIC +}; + +char CheatKeys[2] = { sc_D, sc_N }; + +END_DUKE_NS diff --git a/source/duke/src/global.h b/source/duke/src/global.h new file mode 100644 index 000000000..6a3e0951e --- /dev/null +++ b/source/duke/src/global.h @@ -0,0 +1,311 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef global_h_ +#define global_h_ + +#include "build.h" +#include "compat.h" +#include "duke3d.h" +#include "mmulti.h" +#include "quotes.h" +#include "sector.h" +#include "sounds.h" + +BEGIN_DUKE_NS + +#define MAXMINECARTS 16 +#define MAXJAILDOORS 32 +#define MAXLIGHTNINSECTORS 64 +#define MAXTORCHSECTORS 64 +#define MAXGEOSECTORS 64 + +#ifdef global_c_ + #define G_EXTERN +#else + #define G_EXTERN extern +#endif + +#define MAXINTERPOLATIONS MAXSPRITES + +// duke3d global soup :( + + +G_EXTERN int32_t g_interpolationCnt; +G_EXTERN int32_t g_interpolationLock; +G_EXTERN int32_t oldipos[MAXINTERPOLATIONS]; +G_EXTERN int32_t *curipos[MAXINTERPOLATIONS]; +G_EXTERN int32_t bakipos[MAXINTERPOLATIONS]; + + +G_EXTERN int32_t duke3d_globalflags; + +// KEEPINSYNC astub.c (used values only) +enum DUKE3D_GLOBALFLAGS { + DUKE3D_NO_WIDESCREEN_PINNING = 1<<0, + DUKE3D_NO_HARDCODED_FOGPALS = 1<<1, + DUKE3D_NO_PALETTE_CHANGES = 1<<2, +}; + +G_EXTERN DukeStatus_t sbar; +G_EXTERN actor_t actor[MAXSPRITES]; +// g_tile: tile-specific data THAT DOES NOT CHANGE during the course of a game +G_EXTERN tiledata_t g_tile[MAXTILES]; +G_EXTERN animwalltype animwall[MAXANIMWALLS]; +G_EXTERN char *label; +G_EXTERN char g_loadFromGroupOnly; +G_EXTERN char g_skillCnt; +G_EXTERN char pus,pub; +G_EXTERN char ready2send; +#define MAXPLAYERNAME 32 +G_EXTERN char tempbuf[MAXSECTORS<<1],buf[1024]; +G_EXTERN uint8_t packbuf[PACKBUF_SIZE]; + + +G_EXTERN input_t localInput; +G_EXTERN input_t recsync[RECSYNCBUFSIZ]; + +//G_EXTERN uint8_t syncstat, syncval[MAXPLAYERS][MOVEFIFOSIZ]; +//G_EXTERN int32_t syncvalhead[MAXPLAYERS], syncvaltail, syncvaltottail; + +G_EXTERN int32_t avgfvel, avgsvel, avgbits; +G_EXTERN fix16_t avgavel, avghorz; +G_EXTERN int8_t avgextbits; + +G_EXTERN int32_t movefifosendplc; +G_EXTERN int32_t movefifoplc; + +G_EXTERN int32_t predictfifoplc; +G_EXTERN vec3_t mypos, omypos, myvel; +G_EXTERN fix16_t myhoriz, omyhoriz, myhorizoff, omyhorizoff, myang, omyang; +G_EXTERN int16_t mycursectnum, myjumpingcounter; +G_EXTERN uint8_t myjumpingtoggle, myonground, myhardlanding, myreturntocenter; +G_EXTERN int16_t my_moto_speed; +G_EXTERN uint8_t my_not_on_water, my_moto_on_ground; +G_EXTERN uint8_t my_moto_do_bump, my_moto_bump_fast, my_moto_on_oil, my_moto_on_mud; +G_EXTERN int16_t my_moto_bump, my_moto_bump_target, my_moto_turb; +G_EXTERN int32_t my_stairs; + +G_EXTERN vec3_t myposbak[MOVEFIFOSIZ]; +G_EXTERN fix16_t myhorizbak[MOVEFIFOSIZ], myangbak[MOVEFIFOSIZ]; +G_EXTERN int32_t myminlag[MAXPLAYERS], mymaxlag, otherminlag, bufferjitter; + +G_EXTERN int32_t g_networkBroadcastMode, g_movesPerPacket; + +G_EXTERN int32_t g_animWallCnt; +G_EXTERN int32_t g_animateCnt; +G_EXTERN int32_t g_cloudCnt; +G_EXTERN int32_t g_curViewscreen; +G_EXTERN int32_t g_frameRate; +G_EXTERN int32_t g_cyclerCnt; +G_EXTERN int32_t g_damageCameras; +G_EXTERN int32_t g_defaultLabelCnt; +G_EXTERN int32_t g_doQuickSave; +G_EXTERN int32_t g_earthquakeTime; +G_EXTERN int32_t g_freezerSelfDamage; +G_EXTERN int32_t g_gameQuit; +G_EXTERN int32_t g_globalRandom; +G_EXTERN int32_t g_impactDamage; +G_EXTERN int32_t g_labelCnt; +G_EXTERN int32_t g_maxPlayerHealth; +G_EXTERN int32_t g_mirrorCount; +G_EXTERN int32_t g_mostConcurrentPlayers; +G_EXTERN int32_t g_musicSize; +G_EXTERN int32_t g_playerSpawnCnt; +G_EXTERN int32_t g_scriptDebug; +G_EXTERN int32_t g_showShareware; +G_EXTERN int32_t g_spriteDeleteQueuePos; +G_EXTERN int32_t g_startArmorAmount; +G_EXTERN int32_t g_tripbombLaserMode; +G_EXTERN int32_t screenpeek; + +G_EXTERN int16_t g_animateSect[MAXANIMATES]; +G_EXTERN int32_t *g_animatePtr[MAXANIMATES]; +G_EXTERN int32_t g_animateGoal[MAXANIMATES]; +G_EXTERN int32_t g_animateVel[MAXANIMATES]; + +G_EXTERN int16_t g_cloudSect[256]; +G_EXTERN int16_t g_cloudX; +G_EXTERN int16_t g_cloudY; +G_EXTERN ClockTicks g_cloudClock; + +G_EXTERN int16_t SpriteDeletionQueue[1024]; +G_EXTERN int16_t g_cyclers[MAXCYCLERS][6]; +G_EXTERN int16_t g_mirrorSector[64]; +G_EXTERN int16_t g_mirrorWall[64]; +G_EXTERN int32_t *labelcode; +G_EXTERN int32_t *labeltype; +G_EXTERN ClockTicks lockclock; +G_EXTERN ClockTicks ototalclock; + +G_EXTERN int32_t g_wupass; +G_EXTERN int32_t g_chickenPlant; +G_EXTERN int32_t g_thunderOn; +G_EXTERN int32_t g_ufoSpawn; +G_EXTERN int32_t g_ufoCnt; +G_EXTERN int32_t g_hulkSpawn; +G_EXTERN int32_t g_vixenLevel; +G_EXTERN int32_t g_lastLevel; +G_EXTERN int32_t g_turdLevel; + +G_EXTERN int32_t g_mineCartDir[MAXMINECARTS]; +G_EXTERN int32_t g_mineCartSpeed[MAXMINECARTS]; +G_EXTERN int32_t g_mineCartChildSect[MAXMINECARTS]; +G_EXTERN int32_t g_mineCartSound[MAXMINECARTS]; +G_EXTERN int32_t g_mineCartDist[MAXMINECARTS]; +G_EXTERN int32_t g_mineCartDrag[MAXMINECARTS]; +G_EXTERN int32_t g_mineCartOpen[MAXMINECARTS]; +G_EXTERN int32_t g_mineCartSect[MAXMINECARTS]; +G_EXTERN uint32_t g_mineCartCnt; + +G_EXTERN int32_t g_jailDoorSound[MAXJAILDOORS]; +G_EXTERN int32_t g_jailDoorDrag[MAXJAILDOORS]; +G_EXTERN int32_t g_jailDoorSpeed[MAXJAILDOORS]; +G_EXTERN int32_t g_jailDoorSecHitag[MAXJAILDOORS]; +G_EXTERN int32_t g_jailDoorDist[MAXJAILDOORS]; +G_EXTERN int32_t g_jailDoorDir[MAXJAILDOORS]; +G_EXTERN int32_t g_jailDoorOpen[MAXJAILDOORS]; +G_EXTERN int32_t g_jailDoorSect[MAXJAILDOORS]; +G_EXTERN uint32_t g_jailDoorCnt; + +G_EXTERN int32_t g_lightninSector[MAXLIGHTNINSECTORS]; +G_EXTERN int32_t g_lightninSectorShade[MAXLIGHTNINSECTORS]; +G_EXTERN uint32_t g_lightninCnt; + +G_EXTERN int32_t g_torchSector[MAXTORCHSECTORS]; +G_EXTERN int32_t g_torchSectorShade[MAXTORCHSECTORS]; +G_EXTERN int32_t g_torchType[MAXTORCHSECTORS]; +G_EXTERN uint32_t g_torchCnt; + +G_EXTERN int32_t g_geoSectorWarp[MAXGEOSECTORS]; +G_EXTERN int32_t g_geoSectorWarp2[MAXGEOSECTORS]; +G_EXTERN int32_t g_geoSector[MAXGEOSECTORS]; +G_EXTERN int32_t g_geoSectorX[MAXGEOSECTORS]; +G_EXTERN int32_t g_geoSectorY[MAXGEOSECTORS]; +G_EXTERN int32_t g_geoSectorX2[MAXGEOSECTORS]; +G_EXTERN int32_t g_geoSectorY2[MAXGEOSECTORS]; +G_EXTERN uint32_t g_geoSectorCnt; + +G_EXTERN int32_t g_thunderFlash; +G_EXTERN int32_t g_thunderTime; +G_EXTERN int32_t g_winderFlash; +G_EXTERN int32_t g_winderTime; +G_EXTERN int32_t g_brightness; + +G_EXTERN int16_t g_ambientLotag[64]; +G_EXTERN int16_t g_ambientHitag[64]; +G_EXTERN uint32_t g_ambientCnt; + +G_EXTERN intptr_t *apScript; +G_EXTERN intptr_t *g_scriptPtr; + +G_EXTERN map_t g_mapInfo[(MAXVOLUMES + 1) * MAXLEVELS]; // +1 volume for "intro", "briefing" and "loading" music +G_EXTERN vec2_t g_origins[MAXANIMPOINTS]; + +G_EXTERN int32_t g_windTime, g_windDir; +G_EXTERN int16_t g_fakeBubbaCnt, g_mamaSpawnCnt, g_banjoSong, g_bellTime, g_bellSprite; +G_EXTERN uint8_t g_spriteExtra[MAXSPRITES], g_sectorExtra[MAXSECTORS]; +G_EXTERN uint8_t g_changeEnemySize, g_slotWin, g_ufoSpawnMinion, g_pistonSound, g_chickenWeaponTimer, g_RAendLevel, g_RAendEpisode, g_fogType; +G_EXTERN int32_t g_cdTrack; + +// XXX: I think this pragma pack is meaningless here. +// MSDN (https://msdn.microsoft.com/en-us/library/2e70t5y1%28VS.80%29.aspx) says: +// "pack takes effect at the first struct, union, or class declaration after +// the pragma is seen; pack has no effect on definitions." +#pragma pack(push,1) +#ifdef global_c_ +static playerdata_t g_player_s[1 + MAXPLAYERS]; +playerdata_t *const g_player = &g_player_s[1]; +#else +extern playerdata_t *const g_player; +#endif +G_EXTERN playerspawn_t g_playerSpawnPoints[MAXPLAYERS]; +G_EXTERN input_t inputfifo[MOVEFIFOSIZ][MAXPLAYERS]; +#pragma pack(pop) + +G_EXTERN int32_t g_noEnemies; +G_EXTERN int32_t g_restorePalette; +G_EXTERN uint32_t everyothertime; +G_EXTERN uint32_t g_moveThingsCount; +G_EXTERN double g_gameUpdateTime; +G_EXTERN double g_gameUpdateAndDrawTime; +#define GAMEUPDATEAVGTIMENUMSAMPLES 100 +extern float g_gameUpdateAvgTime; + +#ifndef global_c_ +extern char CheatKeys[2]; +extern char g_gametypeNames[MAXGAMETYPES][33]; + +extern int32_t g_actorRespawnTime; +extern int32_t g_bouncemineRadius; +extern int32_t g_deleteQueueSize; +extern int32_t g_gametypeCnt; +extern int32_t g_itemRespawnTime; +extern int32_t g_morterRadius; +extern int32_t g_numFreezeBounces; +extern int32_t g_pipebombRadius; +extern int32_t g_playerFriction; +extern int32_t g_rpgRadius; +extern int32_t g_scriptSize; +extern int32_t g_seenineRadius; +extern int32_t g_shrinkerRadius; +extern int32_t g_spriteGravity; +extern int32_t g_timerTicsPerSecond; +extern int32_t g_tripbombRadius; +extern int32_t g_volumeCnt; + +extern int16_t g_blimpSpawnItems[15]; +extern int32_t g_gametypeFlags[MAXGAMETYPES]; + +extern const char *s_buildDate; +#endif + +enum +{ + EF_HIDEFROMSP = 1<<0, +}; + +EXTERN_INLINE_HEADER void G_UpdateInterpolations(void); +EXTERN_INLINE_HEADER void G_RestoreInterpolations(void); + +#if defined global_c_ || !defined DISABLE_INLINING + +EXTERN_INLINE void G_UpdateInterpolations(void) //Stick at beginning of G_DoMoveThings +{ + for (bssize_t i=g_interpolationCnt-1; i>=0; i--) oldipos[i] = *curipos[i]; +} + +EXTERN_INLINE void G_RestoreInterpolations(void) //Stick at end of drawscreen +{ + int32_t i=g_interpolationCnt-1; + + if (--g_interpolationLock) + return; + + for (; i>=0; i--) *curipos[i] = bakipos[i]; +} + +#endif + +END_DUKE_NS + +#endif diff --git a/source/duke/src/inv.h b/source/duke/src/inv.h new file mode 100644 index 000000000..3a12d4f52 --- /dev/null +++ b/source/duke/src/inv.h @@ -0,0 +1,61 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#pragma once + +BEGIN_DUKE_NS + +enum dukeinv_t +{ + GET_STEROIDS, // 0 + GET_SHIELD, + GET_SCUBA, + GET_HOLODUKE, + GET_JETPACK, + GET_DUMMY1, // 5 + GET_ACCESS, + GET_HEATS, + GET_DUMMY2, + GET_FIRSTAID, + GET_BOOTS, // 10 + GET_MAX +}; + +// these are not in the same order as the above, and it can't be changed for compat reasons. lame! +enum dukeinvicon_t +{ + ICON_NONE, // 0 + ICON_FIRSTAID, + ICON_STEROIDS, + ICON_HOLODUKE, + ICON_JETPACK, + ICON_HEATS, // 5 + ICON_SCUBA, + ICON_BOOTS, + ICON_MAX +}; + +extern int const icon_to_inv[ICON_MAX]; + +extern int const inv_to_icon[GET_MAX]; + +END_DUKE_NS diff --git a/source/duke/src/keys.h b/source/duke/src/keys.h new file mode 100644 index 000000000..44662de13 --- /dev/null +++ b/source/duke/src/keys.h @@ -0,0 +1,153 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef KEYS_H + +BEGIN_DUKE_NS + + +#define KEYS_H + + #define NUM_CODES 128 + + #define ESC 0x1B + #define ENTER 0x0D + + #define KEYSC_ESC 0x01 + #define KEYSC_1 0x02 + #define KEYSC_2 0x03 + #define KEYSC_3 0x04 + #define KEYSC_4 0x05 + #define KEYSC_5 0x06 + #define KEYSC_6 0x07 + #define KEYSC_7 0x08 + #define KEYSC_8 0x09 + #define KEYSC_9 0x0a + #define KEYSC_0 0x0b + #define KEYSC_DASH 0x0c + #define KEYSC_EQUAL 0x0d + + #define KEYSC_BS 0x0e + #define KEYSC_TAB 0x0f + #define KEYSC_Q 0x10 + #define KEYSC_W 0x11 + #define KEYSC_E 0x12 + #define KEYSC_R 0x13 + #define KEYSC_T 0x14 + #define KEYSC_Y 0x15 + #define KEYSC_U 0x16 + #define KEYSC_I 0x17 + #define KEYSC_O 0x18 + #define KEYSC_P 0x19 + #define KEYSC_LBRACK 0x1a + #define KEYSC_RBRACK 0x1b + #define KEYSC_ENTER 0x1c + + #define KEYSC_LCTRL 0x1d + #define KEYSC_A 0x1e + #define KEYSC_S 0x1f + #define KEYSC_D 0x20 + #define KEYSC_F 0x21 + #define KEYSC_G 0x22 + #define KEYSC_H 0x23 + #define KEYSC_J 0x24 + #define KEYSC_K 0x25 + #define KEYSC_L 0x26 + #define KEYSC_SEMI 0x27 + #define KEYSC_QUOTE 0x28 + #define KEYSC_BQUOTE 0x29 + #define KEYSC_TILDE 0x29 + + #define KEYSC_LSHIFT 0x2a + #define KEYSC_BSLASH 0x2b + #define KEYSC_Z 0x2c + #define KEYSC_X 0x2d + #define KEYSC_C 0x2e + #define KEYSC_V 0x2f + #define KEYSC_B 0x30 + #define KEYSC_N 0x31 + #define KEYSC_M 0x32 + #define KEYSC_COMMA 0x33 + #define KEYSC_PERIOD 0x34 + #define KEYSC_SLASH 0x35 + #define KEYSC_RSHIFT 0x36 + #define KEYSC_gSTAR 0x37 + + #define KEYSC_LALT 0x38 + #define KEYSC_SPACE 0x39 + #define KEYSC_CAPS 0x3a + + #define KEYSC_F1 0x3b + #define KEYSC_F2 0x3c + #define KEYSC_F3 0x3d + #define KEYSC_F4 0x3e + #define KEYSC_F5 0x3f + #define KEYSC_F6 0x40 + #define KEYSC_F7 0x41 + #define KEYSC_F8 0x42 + #define KEYSC_F9 0x43 + #define KEYSC_F10 0x44 + + #define KEYSC_gNUM 0x45 + #define KEYSC_SCROLL 0x46 + + #define KEYSC_gHOME 0x47 + #define KEYSC_gUP 0x48 + #define KEYSC_gPGUP 0x49 + #define KEYSC_gMINUS 0x4a + #define KEYSC_gLEFT 0x4b + #define KEYSC_gKP5 0x4c + #define KEYSC_gRIGHT 0x4d + #define KEYSC_gPLUS 0x4e + #define KEYSC_gEND 0x4f + #define KEYSC_gDOWN 0x50 + #define KEYSC_gPGDN 0x51 + #define KEYSC_gINS 0x52 + #define KEYSC_gDEL 0x53 + + #define KEYSC_F11 0x57 + #define KEYSC_F12 0x58 + + #define KEYSC_gENTER 0x9C + #define KEYSC_RCTRL 0x9D + #define KEYSC_gSLASH 0xB5 + #define KEYSC_RALT 0xB8 + #define KEYSC_PRTSCN 0xB7 + #define KEYSC_PAUSE 0xC5 + #define KEYSC_HOME 0xC7 + #define KEYSC_UP 0xC8 + #define KEYSC_PGUP 0xC9 + #define KEYSC_LEFT 0xCB + #define KEYSC_RIGHT 0xCD + #define KEYSC_END 0xCF + #define KEYSC_DOWN 0xD0 + #define KEYSC_PGDN 0xD1 + #define KEYSC_INSERT 0xD2 + #define KEYSC_DELETE 0xD3 + + #define asc_Esc 27 + #define asc_Enter 13 + #define asc_Space 32 + +END_DUKE_NS + +#endif diff --git a/source/duke/src/macros.h b/source/duke/src/macros.h new file mode 100644 index 000000000..c09bfdaeb --- /dev/null +++ b/source/duke/src/macros.h @@ -0,0 +1,212 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef EDUKE32_MACROS_H_ +#define EDUKE32_MACROS_H_ + +#include "mmulti.h" + +BEGIN_DUKE_NS + +// Macros, some from SW source + +static FORCE_INLINE int32_t krand2(void) +{ + randomseed = (randomseed * 27584621ul) + 1ul; + return ((uint32_t) randomseed)>>16; +} + +#define BGSTRETCH (hud_bgstretch ? 1024 : 0) + +#define RANDOMSCRAP(s, i) \ +{ \ + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(), r4 = krand2(), r5 = krand2(), r6 = krand2(), r7 = krand2(); \ + A_InsertSprite(s->sectnum,s->x+(r7&255)-128,s->y+(r6&255)-128,s->z-ZOFFSET3-(r5&8191),\ + SCRAP6+(r4&15),-8,RR?16:48,RR?16:48,r3&2047,(r2&63)+64,-512-(r1&2047),i,5); \ +} + +#define GTFLAGS(x) (g_gametypeFlags[ud.coop] & x) + +#define TRAVERSE_SPRITE_SECT(l, o, n) (o) = (l); ((o) != -1) && ((n) = nextspritesect[o]); (o) = (n) +#define TRAVERSE_SPRITE_STAT(l, o, n) (o) = (l); ((o) != -1) && ((n) = nextspritestat[o]); (o) = (n) +#define TRAVERSE_CONNECT(i) i = 0; i != -1; i = connectpoint2[i] + +#define TEST(flags,mask) ((flags) & (mask)) +#define SET(flags,mask) ((flags) |= (mask)) +#define RESET(flags,mask) ((flags) &= ~(mask)) +#define FLIP(flags,mask) ((flags) ^= (mask)) + +// mask definitions + +#define BIT(shift) (1u<<(shift)) + +#define TEST_SYNC_KEY(bits, sync_num) (!!TEST((bits), BIT(sync_num))) + +#define AFLAMABLE(X) (X==BOX||X==TREE1||X==TREE2||X==TIRE||X==CONE) +#define rnd(X) ((krand2()>>8)>=(255-(X))) + +// +// NETWORK - REDEFINABLE SHARED (SYNC) KEYS BIT POSITIONS +// + +#define SK_JUMP 0 +#define SK_CROUCH 1 +#define SK_FIRE 2 +#define SK_AIM_UP 3 +#define SK_AIM_DOWN 4 +#define SK_RUN 5 +#define SK_LOOK_LEFT 6 +#define SK_LOOK_RIGHT 7 +// weapons take up 4 bits... +#define SK_WEAPON_BITS 8 +#define SK_WEAPON_BITS1 9 +#define SK_WEAPON_BITS2 10 +#define SK_WEAPON_BITS3 11 +#define SK_STEROIDS 12 +#define SK_LOOK_UP 13 +#define SK_LOOK_DOWN 14 +#define SK_NIGHTVISION 15 +#define SK_MEDKIT 16 +#define SK_MULTIFLAG 17 +#define SK_CENTER_VIEW 18 +#define SK_HOLSTER 19 +#define SK_INV_LEFT 20 +#define SK_PAUSE 21 +#define SK_QUICK_KICK 22 +#define SK_AIMMODE 23 +#define SK_HOLODUKE 24 +#define SK_JETPACK 25 +#define SK_GAMEQUIT 26 +#define SK_INV_RIGHT 27 +#define SK_TURNAROUND 28 +#define SK_OPEN 29 +#define SK_INVENTORY 30 +#define SK_ESCAPE 31 + +// rotatesprite flags +#define ROTATE_SPRITE_TRANSLUCENT (BIT(0)) +#define ROTATE_SPRITE_VIEW_CLIP (BIT(1)) // clip to view +#define ROTATE_SPRITE_YFLIP (BIT(2)) +#define ROTATE_SPRITE_IGNORE_START_MOST (BIT(3)) // don't clip to startumost +#define ROTATE_SPRITE_SCREEN_CLIP (BIT(1)|BIT(3)) // use window +#define ROTATE_SPRITE_CORNER (BIT(4)) // place sprite from upper left corner +#define ROTATE_SPRITE_TRANS_FLIP (BIT(5)) +#define ROTATE_SPRITE_NON_MASK (BIT(6)) // non masked sprites +#define ROTATE_SPRITE_ALL_PAGES (BIT(7)) // copies to all pages + +#define RS_SCALE BIT(16) + +// system defines for status bits +#define CEILING_STAT_PLAX BIT(0) +#define CEILING_STAT_SLOPE BIT(1) +#define CEILING_STAT_SWAPXY BIT(2) +#define CEILING_STAT_SMOOSH BIT(3) +#define CEILING_STAT_XFLIP BIT(4) +#define CEILING_STAT_YFLIP BIT(5) +#define CEILING_STAT_RELATIVE BIT(6) +#define CEILING_STAT_TYPE_MASK (BIT(7)|BIT(8)) +#define CEILING_STAT_MASKED BIT(7) +#define CEILING_STAT_TRANS BIT(8) +#define CEILING_STAT_TRANS_FLIP (BIT(7)|BIT(8)) +#define CEILING_STAT_FAF_BLOCK_HITSCAN BIT(15) + +#define FLOOR_STAT_PLAX BIT(0) +#define FLOOR_STAT_SLOPE BIT(1) +#define FLOOR_STAT_SWAPXY BIT(2) +#define FLOOR_STAT_SMOOSH BIT(3) +#define FLOOR_STAT_XFLIP BIT(4) +#define FLOOR_STAT_YFLIP BIT(5) +#define FLOOR_STAT_RELATIVE BIT(6) +#define FLOOR_STAT_TYPE_MASK (BIT(7)|BIT(8)) +#define FLOOR_STAT_MASKED BIT(7) +#define FLOOR_STAT_TRANS BIT(8) +#define FLOOR_STAT_TRANS_FLIP (BIT(7)|BIT(8)) +#define FLOOR_STAT_FAF_BLOCK_HITSCAN BIT(15) + +#define CSTAT_WALL_BLOCK BIT(0) +#define CSTAT_WALL_BOTTOM_SWAP BIT(1) +#define CSTAT_WALL_ALIGN_BOTTOM BIT(2) +#define CSTAT_WALL_XFLIP BIT(3) +#define CSTAT_WALL_MASKED BIT(4) +#define CSTAT_WALL_1WAY BIT(5) +#define CSTAT_WALL_BLOCK_HITSCAN BIT(6) +#define CSTAT_WALL_TRANSLUCENT BIT(7) +#define CSTAT_WALL_YFLIP BIT(8) +#define CSTAT_WALL_TRANS_FLIP BIT(9) +#define CSTAT_WALL_BLOCK_ACTOR (BIT(14)) // my def +#define CSTAT_WALL_WARP_HITSCAN (BIT(15)) // my def + +//cstat, bit 0: 1 = Blocking sprite (use with clipmove, getzrange) "B" +// bit 1: 1 = 50/50 transluscence, 0 = normal "T" +// bit 2: 1 = x-flipped, 0 = normal "F" +// bit 3: 1 = y-flipped, 0 = normal "F" +// bits 5-4: 00 = FACE sprite (default) "R" +// 01 = WALL sprite (like masked walls) +// 10 = FLOOR sprite (parallel to ceilings&floors) +// 11 = SPIN sprite (face sprite that can spin 2draw style - not done yet) +// bit 6: 1 = 1-sided sprite, 0 = normal "1" +// bit 7: 1 = Real centered centering, 0 = foot center "C" +// bit 8: 1 = Blocking sprite (use with hitscan) "H" +// bit 9: reserved +// bit 10: reserved +// bit 11: 1 = determine shade based only on its own shade member (see CON's spritenoshade command), i.e. +// don't take over shade from parallaxed ceiling/nonparallaxed floor +// (NOTE: implemented on the game side) +// bit 12: reserved +// bit 13: reserved +// bit 14: reserved +// bit 15: 1 = Invisible sprite, 0 = not invisible +#define CSTAT_SPRITE_NOSHADE BIT(11) +#define CSTAT_SPRITE_BREAKABLE (CSTAT_SPRITE_BLOCK_HITSCAN) + +#define SP(i) sprite[i].yvel +#define SX(i) sprite[i].x +#define SY(i) sprite[i].y +#define SZ(i) sprite[i].z +#define SS(i) sprite[i].shade +#define PN(i) sprite[i].picnum +#define SA(i) sprite[i].ang +//#define SV sprite[i].xvel +//#define ZV sprite[i].zvel +//#define RX sprite[i].xrepeat +//#define RY sprite[i].yrepeat +#define OW(i) sprite[i].owner +#define CS(i) sprite[i].cstat +#define SH(i) sprite[i].extra +//#define CX sprite[i].xoffset +//#define CY sprite[i].yoffset +//#define CD sprite[i].clipdist +//#define PL sprite[i].pal +#define SLT(i) sprite[i].lotag +#define SHT(i) sprite[i].hitag +#define SECT(i) sprite[i].sectnum + +#define T1(i) actor[i].t_data[0] +#define T2(i) actor[i].t_data[1] +#define T3(i) actor[i].t_data[2] +#define T4(i) actor[i].t_data[3] +#define T5(i) actor[i].t_data[4] +#define T6(i) actor[i].t_data[5] + +END_DUKE_NS + +#endif diff --git a/source/duke/src/menus.h b/source/duke/src/menus.h new file mode 100644 index 000000000..c6b622c61 --- /dev/null +++ b/source/duke/src/menus.h @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef menus_h_ +#define menus_h_ + +#include "compat.h" + +BEGIN_DUKE_NS + +// a subset of screentext parameters, restricted because menus require accessibility +typedef struct MenuFont_t +{ + // int32_t xspace, yline; + vec2_t emptychar, between; + int32_t zoom; + int32_t cursorLeftPosition, cursorCenterPosition, cursorScale, cursorScale2, cursorScale3; + int32_t textflags; + int16_t tilenum; + // selected shade glows, deselected shade is used by Blood, disabled shade is used by SW + int8_t shade_deselected, shade_disabled; + uint8_t pal; + uint8_t pal_selected, pal_deselected, pal_disabled; + uint8_t pal_selected_right, pal_deselected_right, pal_disabled_right; + + int32_t get_yline() const { return mulscale16(emptychar.y, zoom); } +} MenuFont_t; + +extern MenuFont_t MF_Redfont, MF_Bluefont, MF_Minifont; + +void Menu_Init(void); +inline int G_CheckPlayerColor(int color) +{ + static int32_t player_pals[] = { 0, 9, 10, 11, 12, 13, 14, 15, 16, 21, 23, }; + if (color >= 0 && color < 10) return player_pals[color]; + return 0; +} + + + +END_DUKE_NS + +#endif diff --git a/source/duke/src/namesdyn.cpp b/source/duke/src/namesdyn.cpp new file mode 100644 index 000000000..90722929a --- /dev/null +++ b/source/duke/src/namesdyn.cpp @@ -0,0 +1,3051 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- +#include "ns.h" // Must come before everything else! + +#include "compat.h" +#include "build.h" + +#include "namesdyn.h" +#include "global.h" +#include "gamecontrol.h" + +BEGIN_DUKE_NS + +#define DVPTR(x) &x + +int16_t DynamicTileMap[MAXTILES]; +int16_t DynamicWeaponMap[MAX_WEAPONS]; + +struct dynitem +{ + const char *str; + int32_t *dynvalptr; + const int16_t staticval; + const int16_t staticval_rr; +}; + +static struct dynitem g_dynTileList[] = +{ + { "SECTOREFFECTOR", DVPTR(SECTOREFFECTOR), SECTOREFFECTOR__STATIC, SECTOREFFECTOR__STATICRR }, + { "ACTIVATOR", DVPTR(ACTIVATOR), ACTIVATOR__STATIC, ACTIVATOR__STATICRR }, + { "TOUCHPLATE", DVPTR(TOUCHPLATE), TOUCHPLATE__STATIC, TOUCHPLATE__STATICRR }, + { "ACTIVATORLOCKED", DVPTR(ACTIVATORLOCKED), ACTIVATORLOCKED__STATIC, ACTIVATORLOCKED__STATICRR }, + { "MUSICANDSFX", DVPTR(MUSICANDSFX), MUSICANDSFX__STATIC, MUSICANDSFX__STATICRR }, + { "LOCATORS", DVPTR(LOCATORS), LOCATORS__STATIC, LOCATORS__STATICRR }, + { "CYCLER", DVPTR(CYCLER), CYCLER__STATIC, CYCLER__STATICRR }, + { "MASTERSWITCH", DVPTR(MASTERSWITCH), MASTERSWITCH__STATIC, MASTERSWITCH__STATICRR }, + { "RESPAWN", DVPTR(RESPAWN), RESPAWN__STATIC, RESPAWN__STATICRR }, + { "GPSPEED", DVPTR(GPSPEED), GPSPEED__STATIC, GPSPEED__STATICRR }, + { "FOF", DVPTR(FOF), FOF__STATIC, FOF__STATICRR }, + { "ARROW", DVPTR(ARROW), ARROW__STATIC, ARROW__STATICRR }, + { "FIRSTGUNSPRITE", DVPTR(FIRSTGUNSPRITE), FIRSTGUNSPRITE__STATIC, FIRSTGUNSPRITE__STATICRR }, + { "CHAINGUNSPRITE", DVPTR(CHAINGUNSPRITE), CHAINGUNSPRITE__STATIC, CHAINGUNSPRITE__STATICRR }, + { "RPGSPRITE", DVPTR(RPGSPRITE), RPGSPRITE__STATIC, RPGSPRITE__STATICRR }, + { "FREEZESPRITE", DVPTR(FREEZESPRITE), FREEZESPRITE__STATIC, FREEZESPRITE__STATICRR }, + { "SHRINKERSPRITE", DVPTR(SHRINKERSPRITE), SHRINKERSPRITE__STATIC, SHRINKERSPRITE__STATICRR }, + { "HEAVYHBOMB", DVPTR(HEAVYHBOMB), HEAVYHBOMB__STATIC, HEAVYHBOMB__STATICRR }, + { "TRIPBOMBSPRITE", DVPTR(TRIPBOMBSPRITE), TRIPBOMBSPRITE__STATIC, TRIPBOMBSPRITE__STATICRR }, + { "SHOTGUNSPRITE", DVPTR(SHOTGUNSPRITE), SHOTGUNSPRITE__STATIC, SHOTGUNSPRITE__STATICRR }, + { "DEVISTATORSPRITE", DVPTR(DEVISTATORSPRITE), DEVISTATORSPRITE__STATIC, DEVISTATORSPRITE__STATICRR }, + { "HEALTHBOX", DVPTR(HEALTHBOX), HEALTHBOX__STATIC, HEALTHBOX__STATICRR }, + { "AMMOBOX", DVPTR(AMMOBOX), AMMOBOX__STATIC, AMMOBOX__STATICRR }, + { "GROWSPRITEICON", DVPTR(GROWSPRITEICON), GROWSPRITEICON__STATIC, GROWSPRITEICON__STATICRR }, + { "INVENTORYBOX", DVPTR(INVENTORYBOX), INVENTORYBOX__STATIC, INVENTORYBOX__STATICRR }, + { "FREEZEAMMO", DVPTR(FREEZEAMMO), FREEZEAMMO__STATIC, FREEZEAMMO__STATICRR }, + { "AMMO", DVPTR(AMMO), AMMO__STATIC, AMMO__STATICRR }, + { "BATTERYAMMO", DVPTR(BATTERYAMMO), BATTERYAMMO__STATIC, BATTERYAMMO__STATICRR }, + { "DEVISTATORAMMO", DVPTR(DEVISTATORAMMO), DEVISTATORAMMO__STATIC, DEVISTATORAMMO__STATICRR }, + { "RPGAMMO", DVPTR(RPGAMMO), RPGAMMO__STATIC, RPGAMMO__STATICRR }, + { "GROWAMMO", DVPTR(GROWAMMO), GROWAMMO__STATIC, GROWAMMO__STATICRR }, + { "CRYSTALAMMO", DVPTR(CRYSTALAMMO), CRYSTALAMMO__STATIC, CRYSTALAMMO__STATICRR }, + { "HBOMBAMMO", DVPTR(HBOMBAMMO), HBOMBAMMO__STATIC, HBOMBAMMO__STATICRR }, + { "AMMOLOTS", DVPTR(AMMOLOTS), AMMOLOTS__STATIC, AMMOLOTS__STATICRR }, + { "SHOTGUNAMMO", DVPTR(SHOTGUNAMMO), SHOTGUNAMMO__STATIC, SHOTGUNAMMO__STATICRR }, + { "COLA", DVPTR(COLA), COLA__STATIC, COLA__STATICRR }, + { "SIXPAK", DVPTR(SIXPAK), SIXPAK__STATIC, SIXPAK__STATICRR }, + { "FIRSTAID", DVPTR(FIRSTAID), FIRSTAID__STATIC, FIRSTAID__STATICRR }, + { "SHIELD", DVPTR(SHIELD), SHIELD__STATIC, SHIELD__STATICRR }, + { "STEROIDS", DVPTR(STEROIDS), STEROIDS__STATIC, STEROIDS__STATICRR }, + { "AIRTANK", DVPTR(AIRTANK), AIRTANK__STATIC, AIRTANK__STATICRR }, + { "JETPACK", DVPTR(JETPACK), JETPACK__STATIC, JETPACK__STATICRR }, + { "HEATSENSOR", DVPTR(HEATSENSOR), HEATSENSOR__STATIC, HEATSENSOR__STATICRR }, + { "ACCESSCARD", DVPTR(ACCESSCARD), ACCESSCARD__STATIC, ACCESSCARD__STATICRR }, + { "BOOTS", DVPTR(BOOTS), BOOTS__STATIC, BOOTS__STATICRR }, + { "MIRRORBROKE", DVPTR(MIRRORBROKE), MIRRORBROKE__STATIC, MIRRORBROKE__STATICRR }, + { "CLOUDYOCEAN", DVPTR(CLOUDYOCEAN), CLOUDYOCEAN__STATIC, 0 }, + { "CLOUDYSKIES", DVPTR(CLOUDYSKIES), CLOUDYSKIES__STATIC, CLOUDYSKIES__STATICRR }, + { "MOONSKY1", DVPTR(MOONSKY1), MOONSKY1__STATIC, MOONSKY1__STATICRR }, + { "MOONSKY2", DVPTR(MOONSKY2), MOONSKY2__STATIC, MOONSKY2__STATICRR }, + { "MOONSKY3", DVPTR(MOONSKY3), MOONSKY3__STATIC, MOONSKY3__STATICRR }, + { "MOONSKY4", DVPTR(MOONSKY4), MOONSKY4__STATIC, MOONSKY4__STATICRR }, + { "BIGORBIT1", DVPTR(BIGORBIT1), BIGORBIT1__STATIC, BIGORBIT1__STATICRR }, + { "BIGORBIT2", DVPTR(BIGORBIT2), BIGORBIT2__STATIC, BIGORBIT2__STATICRR }, + { "BIGORBIT3", DVPTR(BIGORBIT3), BIGORBIT3__STATIC, BIGORBIT3__STATICRR }, + { "BIGORBIT4", DVPTR(BIGORBIT4), BIGORBIT4__STATIC, BIGORBIT4__STATICRR }, + { "BIGORBIT5", DVPTR(BIGORBIT5), BIGORBIT5__STATIC, BIGORBIT5__STATICRR }, + { "LA", DVPTR(LA), LA__STATIC, LA__STATICRR }, + { "REDSKY1", DVPTR(REDSKY1), REDSKY1__STATIC, REDSKY1__STATICRR }, + { "REDSKY2", DVPTR(REDSKY2), REDSKY2__STATIC, REDSKY2__STATICRR }, + { "ATOMICHEALTH", DVPTR(ATOMICHEALTH), ATOMICHEALTH__STATIC, ATOMICHEALTH__STATICRR }, + { "TECHLIGHT2", DVPTR(TECHLIGHT2), TECHLIGHT2__STATIC, TECHLIGHT2__STATICRR }, + { "TECHLIGHTBUST2", DVPTR(TECHLIGHTBUST2), TECHLIGHTBUST2__STATIC, TECHLIGHTBUST2__STATICRR }, + { "TECHLIGHT4", DVPTR(TECHLIGHT4), TECHLIGHT4__STATIC, TECHLIGHT4__STATICRR }, + { "TECHLIGHTBUST4", DVPTR(TECHLIGHTBUST4), TECHLIGHTBUST4__STATIC, TECHLIGHTBUST4__STATICRR }, + { "WALLLIGHT4", DVPTR(WALLLIGHT4), WALLLIGHT4__STATIC, WALLLIGHT4__STATICRR }, + { "WALLLIGHTBUST4", DVPTR(WALLLIGHTBUST4), WALLLIGHTBUST4__STATIC, WALLLIGHTBUST4__STATICRR }, + { "ACCESSSWITCH", DVPTR(ACCESSSWITCH), ACCESSSWITCH__STATIC, ACCESSSWITCH__STATICRR }, + { "SLOTDOOR", DVPTR(SLOTDOOR), SLOTDOOR__STATIC, SLOTDOOR__STATICRR }, + { "LIGHTSWITCH", DVPTR(LIGHTSWITCH), LIGHTSWITCH__STATIC, LIGHTSWITCH__STATICRR }, + { "SPACEDOORSWITCH", DVPTR(SPACEDOORSWITCH), SPACEDOORSWITCH__STATIC, SPACEDOORSWITCH__STATICRR }, + { "SPACELIGHTSWITCH", DVPTR(SPACELIGHTSWITCH), SPACELIGHTSWITCH__STATIC, SPACELIGHTSWITCH__STATICRR }, + { "FRANKENSTINESWITCH", DVPTR(FRANKENSTINESWITCH), FRANKENSTINESWITCH__STATIC, FRANKENSTINESWITCH__STATICRR }, + { "NUKEBUTTON", DVPTR(NUKEBUTTON), NUKEBUTTON__STATIC, NUKEBUTTON__STATICRR }, + { "MULTISWITCH", DVPTR(MULTISWITCH), MULTISWITCH__STATIC, MULTISWITCH__STATICRR }, + { "DOORTILE5", DVPTR(DOORTILE5), DOORTILE5__STATIC, DOORTILE5__STATICRR }, + { "DOORTILE6", DVPTR(DOORTILE6), DOORTILE6__STATIC, DOORTILE6__STATICRR }, + { "DOORTILE1", DVPTR(DOORTILE1), DOORTILE1__STATIC, DOORTILE1__STATICRR }, + { "DOORTILE2", DVPTR(DOORTILE2), DOORTILE2__STATIC, DOORTILE2__STATICRR }, + { "DOORTILE3", DVPTR(DOORTILE3), DOORTILE3__STATIC, DOORTILE3__STATICRR }, + { "DOORTILE4", DVPTR(DOORTILE4), DOORTILE4__STATIC, DOORTILE4__STATICRR }, + { "DOORTILE7", DVPTR(DOORTILE7), DOORTILE7__STATIC, DOORTILE7__STATICRR }, + { "DOORTILE8", DVPTR(DOORTILE8), DOORTILE8__STATIC, DOORTILE8__STATICRR }, + { "DOORTILE9", DVPTR(DOORTILE9), DOORTILE9__STATIC, DOORTILE9__STATICRR }, + { "DOORTILE10", DVPTR(DOORTILE10), DOORTILE10__STATIC, DOORTILE10__STATICRR }, + { "DOORSHOCK", DVPTR(DOORSHOCK), DOORSHOCK__STATIC, DOORSHOCK__STATICRR }, + { "DIPSWITCH", DVPTR(DIPSWITCH), DIPSWITCH__STATIC, DIPSWITCH__STATICRR }, + { "DIPSWITCH2", DVPTR(DIPSWITCH2), DIPSWITCH2__STATIC, DIPSWITCH2__STATICRR }, + { "TECHSWITCH", DVPTR(TECHSWITCH), TECHSWITCH__STATIC, TECHSWITCH__STATICRR }, + { "DIPSWITCH3", DVPTR(DIPSWITCH3), DIPSWITCH3__STATIC, DIPSWITCH3__STATICRR }, + { "ACCESSSWITCH2", DVPTR(ACCESSSWITCH2), ACCESSSWITCH2__STATIC, ACCESSSWITCH2__STATICRR }, + { "REFLECTWATERTILE", DVPTR(REFLECTWATERTILE), REFLECTWATERTILE__STATIC, REFLECTWATERTILE__STATICRR }, + { "FLOORSLIME", DVPTR(FLOORSLIME), FLOORSLIME__STATIC, FLOORSLIME__STATICRR }, + { "BIGFORCE", DVPTR(BIGFORCE), BIGFORCE__STATIC, BIGFORCE__STATICRR }, + { "EPISODE", DVPTR(EPISODE), EPISODE__STATIC, EPISODE__STATICRR }, + { "MASKWALL9", DVPTR(MASKWALL9), MASKWALL9__STATIC, MASKWALL9__STATICRR }, + { "W_LIGHT", DVPTR(W_LIGHT), W_LIGHT__STATIC, W_LIGHT__STATICRR }, + { "SCREENBREAK1", DVPTR(SCREENBREAK1), SCREENBREAK1__STATIC, SCREENBREAK1__STATICRR }, + { "SCREENBREAK2", DVPTR(SCREENBREAK2), SCREENBREAK2__STATIC, SCREENBREAK2__STATICRR }, + { "SCREENBREAK3", DVPTR(SCREENBREAK3), SCREENBREAK3__STATIC, SCREENBREAK3__STATICRR }, + { "SCREENBREAK4", DVPTR(SCREENBREAK4), SCREENBREAK4__STATIC, SCREENBREAK4__STATICRR }, + { "SCREENBREAK5", DVPTR(SCREENBREAK5), SCREENBREAK5__STATIC, SCREENBREAK5__STATICRR }, + { "SCREENBREAK6", DVPTR(SCREENBREAK6), SCREENBREAK6__STATIC, SCREENBREAK6__STATICRR }, + { "SCREENBREAK7", DVPTR(SCREENBREAK7), SCREENBREAK7__STATIC, SCREENBREAK7__STATICRR }, + { "SCREENBREAK8", DVPTR(SCREENBREAK8), SCREENBREAK8__STATIC, SCREENBREAK8__STATICRR }, + { "SCREENBREAK9", DVPTR(SCREENBREAK9), SCREENBREAK9__STATIC, SCREENBREAK9__STATICRR }, + { "SCREENBREAK10", DVPTR(SCREENBREAK10), SCREENBREAK10__STATIC, SCREENBREAK10__STATICRR }, + { "SCREENBREAK11", DVPTR(SCREENBREAK11), SCREENBREAK11__STATIC, SCREENBREAK11__STATICRR }, + { "SCREENBREAK12", DVPTR(SCREENBREAK12), SCREENBREAK12__STATIC, SCREENBREAK12__STATICRR }, + { "SCREENBREAK13", DVPTR(SCREENBREAK13), SCREENBREAK13__STATIC, SCREENBREAK13__STATICRR }, + { "MASKWALL1", DVPTR(MASKWALL1), MASKWALL1__STATIC, MASKWALL1__STATICRR }, + { "W_TECHWALL1", DVPTR(W_TECHWALL1), W_TECHWALL1__STATIC, W_TECHWALL1__STATICRR }, + { "W_TECHWALL2", DVPTR(W_TECHWALL2), W_TECHWALL2__STATIC, W_TECHWALL2__STATICRR }, + { "W_TECHWALL15", DVPTR(W_TECHWALL15), W_TECHWALL15__STATIC, W_TECHWALL15__STATICRR }, + { "W_TECHWALL3", DVPTR(W_TECHWALL3), W_TECHWALL3__STATIC, W_TECHWALL3__STATICRR }, + { "W_TECHWALL4", DVPTR(W_TECHWALL4), W_TECHWALL4__STATIC, W_TECHWALL4__STATICRR }, + { "W_TECHWALL10", DVPTR(W_TECHWALL10), W_TECHWALL10__STATIC, W_TECHWALL10__STATICRR }, + { "W_TECHWALL16", DVPTR(W_TECHWALL16), W_TECHWALL16__STATIC, W_TECHWALL16__STATICRR }, + { "WATERTILE2", DVPTR(WATERTILE2), WATERTILE2__STATIC, WATERTILE2__STATICRR }, + { "BPANNEL1", DVPTR(BPANNEL1), BPANNEL1__STATIC, BPANNEL1__STATICRR }, + { "PANNEL1", DVPTR(PANNEL1), PANNEL1__STATIC, PANNEL1__STATICRR }, + { "PANNEL2", DVPTR(PANNEL2), PANNEL2__STATIC, PANNEL2__STATICRR }, + { "WATERTILE", DVPTR(WATERTILE), WATERTILE__STATIC, WATERTILE__STATICRR }, + { "STATIC", DVPTR(STATIC), STATIC__STATIC, STATIC__STATICRR }, + { "W_SCREENBREAK", DVPTR(W_SCREENBREAK), W_SCREENBREAK__STATIC, W_SCREENBREAK__STATICRR }, + { "W_HITTECHWALL3", DVPTR(W_HITTECHWALL3), W_HITTECHWALL3__STATIC, W_HITTECHWALL3__STATICRR }, + { "W_HITTECHWALL4", DVPTR(W_HITTECHWALL4), W_HITTECHWALL4__STATIC, W_HITTECHWALL4__STATICRR }, + { "W_HITTECHWALL2", DVPTR(W_HITTECHWALL2), W_HITTECHWALL2__STATIC, W_HITTECHWALL2__STATICRR }, + { "W_HITTECHWALL1", DVPTR(W_HITTECHWALL1), W_HITTECHWALL1__STATIC, W_HITTECHWALL1__STATICRR }, + { "MASKWALL10", DVPTR(MASKWALL10), MASKWALL10__STATIC, MASKWALL10__STATICRR }, + { "MASKWALL11", DVPTR(MASKWALL11), MASKWALL11__STATIC, MASKWALL11__STATICRR }, + { "DOORTILE22", DVPTR(DOORTILE22), DOORTILE22__STATIC, DOORTILE22__STATICRR }, + { "FANSPRITE", DVPTR(FANSPRITE), FANSPRITE__STATIC, FANSPRITE__STATICRR }, + { "FANSPRITEBROKE", DVPTR(FANSPRITEBROKE), FANSPRITEBROKE__STATIC, FANSPRITEBROKE__STATICRR }, + { "FANSHADOW", DVPTR(FANSHADOW), FANSHADOW__STATIC, FANSHADOW__STATICRR }, + { "FANSHADOWBROKE", DVPTR(FANSHADOWBROKE), FANSHADOWBROKE__STATIC, FANSHADOWBROKE__STATICRR }, + { "DOORTILE18", DVPTR(DOORTILE18), DOORTILE18__STATIC, DOORTILE18__STATICRR }, + { "DOORTILE19", DVPTR(DOORTILE19), DOORTILE19__STATIC, DOORTILE19__STATICRR }, + { "DOORTILE20", DVPTR(DOORTILE20), DOORTILE20__STATIC, DOORTILE20__STATICRR }, + { "SATELLITE", DVPTR(SATELLITE), SATELLITE__STATIC, SATELLITE__STATICRR }, + { "VIEWSCREEN2", DVPTR(VIEWSCREEN2), VIEWSCREEN2__STATIC, VIEWSCREEN2__STATICRR }, + { "VIEWSCREENBROKE", DVPTR(VIEWSCREENBROKE), VIEWSCREENBROKE__STATIC, VIEWSCREENBROKE__STATICRR }, + { "VIEWSCREEN", DVPTR(VIEWSCREEN), VIEWSCREEN__STATIC, VIEWSCREEN__STATICRR }, + { "GLASS", DVPTR(GLASS), GLASS__STATIC, GLASS__STATICRR }, + { "GLASS2", DVPTR(GLASS2), GLASS2__STATIC, GLASS2__STATICRR }, + { "STAINGLASS1", DVPTR(STAINGLASS1), STAINGLASS1__STATIC, STAINGLASS1__STATICRR }, + { "MASKWALL5", DVPTR(MASKWALL5), MASKWALL5__STATIC, MASKWALL5__STATICRR }, + { "SATELITE", DVPTR(SATELITE), SATELITE__STATIC, SATELITE__STATICRR }, + { "FUELPOD", DVPTR(FUELPOD), FUELPOD__STATIC, FUELPOD__STATICRR }, + { "SLIMEPIPE", DVPTR(SLIMEPIPE), SLIMEPIPE__STATIC, SLIMEPIPE__STATICRR }, + { "CRACK1", DVPTR(CRACK1), CRACK1__STATIC, CRACK1__STATICRR }, + { "CRACK2", DVPTR(CRACK2), CRACK2__STATIC, CRACK2__STATICRR }, + { "CRACK3", DVPTR(CRACK3), CRACK3__STATIC, CRACK3__STATICRR }, + { "CRACK4", DVPTR(CRACK4), CRACK4__STATIC, CRACK4__STATICRR }, + { "FOOTPRINTS", DVPTR(FOOTPRINTS), FOOTPRINTS__STATIC, FOOTPRINTS__STATICRR }, + { "DOMELITE", DVPTR(DOMELITE), DOMELITE__STATIC, DOMELITE__STATICRR }, + { "CAMERAPOLE", DVPTR(CAMERAPOLE), CAMERAPOLE__STATIC, CAMERAPOLE__STATICRR }, + { "CHAIR1", DVPTR(CHAIR1), CHAIR1__STATIC, CHAIR1__STATICRR }, + { "CHAIR2", DVPTR(CHAIR2), CHAIR2__STATIC, CHAIR2__STATICRR }, + { "BROKENCHAIR", DVPTR(BROKENCHAIR), BROKENCHAIR__STATIC, BROKENCHAIR__STATICRR }, + { "MIRROR", DVPTR(MIRROR), MIRROR__STATIC, MIRROR__STATICRR }, + { "WATERFOUNTAIN", DVPTR(WATERFOUNTAIN), WATERFOUNTAIN__STATIC, WATERFOUNTAIN__STATICRR }, + { "WATERFOUNTAINBROKE", DVPTR(WATERFOUNTAINBROKE), WATERFOUNTAINBROKE__STATIC, WATERFOUNTAINBROKE__STATICRR }, + { "FEMMAG1", DVPTR(FEMMAG1), FEMMAG1__STATIC, FEMMAG1__STATICRR }, + { "TOILET", DVPTR(TOILET), TOILET__STATIC, TOILET__STATICRR }, + { "STALL", DVPTR(STALL), STALL__STATIC, STALL__STATICRR }, + { "STALLBROKE", DVPTR(STALLBROKE), STALLBROKE__STATIC, STALLBROKE__STATICRR }, + { "FEMMAG2", DVPTR(FEMMAG2), FEMMAG2__STATIC, FEMMAG2__STATICRR }, + { "REACTOR2", DVPTR(REACTOR2), REACTOR2__STATIC, REACTOR2__STATICRR }, + { "REACTOR2BURNT", DVPTR(REACTOR2BURNT), REACTOR2BURNT__STATIC, REACTOR2BURNT__STATICRR }, + { "REACTOR2SPARK", DVPTR(REACTOR2SPARK), REACTOR2SPARK__STATIC, REACTOR2SPARK__STATICRR }, + { "GRATE1", DVPTR(GRATE1), GRATE1__STATIC, GRATE1__STATICRR }, + { "BGRATE1", DVPTR(BGRATE1), BGRATE1__STATIC, BGRATE1__STATICRR }, + { "SOLARPANNEL", DVPTR(SOLARPANNEL), SOLARPANNEL__STATIC, SOLARPANNEL__STATICRR }, + { "NAKED1", DVPTR(NAKED1), NAKED1__STATIC, NAKED1__STATICRR }, + { "ANTENNA", DVPTR(ANTENNA), ANTENNA__STATIC, ANTENNA__STATICRR }, + { "MASKWALL12", DVPTR(MASKWALL12), MASKWALL12__STATIC, MASKWALL12__STATICRR }, + { "TOILETBROKE", DVPTR(TOILETBROKE), TOILETBROKE__STATIC, TOILETBROKE__STATICRR }, + { "PIPE2", DVPTR(PIPE2), PIPE2__STATIC, PIPE2__STATICRR }, + { "PIPE1B", DVPTR(PIPE1B), PIPE1B__STATIC, PIPE1B__STATICRR }, + { "PIPE3", DVPTR(PIPE3), PIPE3__STATIC, PIPE3__STATICRR }, + { "PIPE1", DVPTR(PIPE1), PIPE1__STATIC, PIPE1__STATICRR }, + { "CAMERA1", DVPTR(CAMERA1), CAMERA1__STATIC, CAMERA1__STATICRR }, + { "BRICK", DVPTR(BRICK), BRICK__STATIC, BRICK__STATICRR }, + { "SPLINTERWOOD", DVPTR(SPLINTERWOOD), SPLINTERWOOD__STATIC, SPLINTERWOOD__STATICRR }, + { "PIPE2B", DVPTR(PIPE2B), PIPE2B__STATIC, PIPE2B__STATICRR }, + { "BOLT1", DVPTR(BOLT1), BOLT1__STATIC, BOLT1__STATICRR }, + { "W_NUMBERS", DVPTR(W_NUMBERS), W_NUMBERS__STATIC, W_NUMBERS__STATICRR }, + { "WATERDRIP", DVPTR(WATERDRIP), WATERDRIP__STATIC, WATERDRIP__STATICRR }, + { "WATERBUBBLE", DVPTR(WATERBUBBLE), WATERBUBBLE__STATIC, WATERBUBBLE__STATICRR }, + { "WATERBUBBLEMAKER", DVPTR(WATERBUBBLEMAKER), WATERBUBBLEMAKER__STATIC, WATERBUBBLEMAKER__STATICRR }, + { "W_FORCEFIELD", DVPTR(W_FORCEFIELD), W_FORCEFIELD__STATIC, W_FORCEFIELD__STATICRR }, + { "VACUUM", DVPTR(VACUUM), VACUUM__STATIC, VACUUM__STATICRR }, + { "FOOTPRINTS2", DVPTR(FOOTPRINTS2), FOOTPRINTS2__STATIC, FOOTPRINTS2__STATICRR }, + { "FOOTPRINTS3", DVPTR(FOOTPRINTS3), FOOTPRINTS3__STATIC, FOOTPRINTS3__STATICRR }, + { "FOOTPRINTS4", DVPTR(FOOTPRINTS4), FOOTPRINTS4__STATIC, FOOTPRINTS4__STATICRR }, + { "EGG", DVPTR(EGG), EGG__STATIC, EGG__STATICRR }, + { "SCALE", DVPTR(SCALE), SCALE__STATIC, SCALE__STATICRR }, + { "CHAIR3", DVPTR(CHAIR3), CHAIR3__STATIC, CHAIR3__STATICRR }, + { "CAMERALIGHT", DVPTR(CAMERALIGHT), CAMERALIGHT__STATIC, CAMERALIGHT__STATICRR }, + { "MOVIECAMERA", DVPTR(MOVIECAMERA), MOVIECAMERA__STATIC, MOVIECAMERA__STATICRR }, + { "IVUNIT", DVPTR(IVUNIT), IVUNIT__STATIC, IVUNIT__STATICRR }, + { "POT1", DVPTR(POT1), POT1__STATIC, POT1__STATICRR }, + { "POT2", DVPTR(POT2), POT2__STATIC, POT2__STATICRR }, + { "POT3", DVPTR(POT3), POT3__STATIC, POT3__STATICRR }, + { "PIPE3B", DVPTR(PIPE3B), PIPE3B__STATIC, PIPE3B__STATICRR }, + { "WALLLIGHT3", DVPTR(WALLLIGHT3), WALLLIGHT3__STATIC, WALLLIGHT3__STATICRR }, + { "WALLLIGHTBUST3", DVPTR(WALLLIGHTBUST3), WALLLIGHTBUST3__STATIC, WALLLIGHTBUST3__STATICRR }, + { "WALLLIGHT1", DVPTR(WALLLIGHT1), WALLLIGHT1__STATIC, WALLLIGHT1__STATICRR }, + { "WALLLIGHTBUST1", DVPTR(WALLLIGHTBUST1), WALLLIGHTBUST1__STATIC, WALLLIGHTBUST1__STATICRR }, + { "WALLLIGHT2", DVPTR(WALLLIGHT2), WALLLIGHT2__STATIC, WALLLIGHT2__STATICRR }, + { "WALLLIGHTBUST2", DVPTR(WALLLIGHTBUST2), WALLLIGHTBUST2__STATIC, WALLLIGHTBUST2__STATICRR }, + { "LIGHTSWITCH2", DVPTR(LIGHTSWITCH2), LIGHTSWITCH2__STATIC, LIGHTSWITCH2__STATICRR }, + { "WAITTOBESEATED", DVPTR(WAITTOBESEATED), WAITTOBESEATED__STATIC, WAITTOBESEATED__STATICRR }, + { "DOORTILE14", DVPTR(DOORTILE14), DOORTILE14__STATIC, DOORTILE14__STATICRR }, + { "STATUE", DVPTR(STATUE), STATUE__STATIC, STATUE__STATICRR }, + { "MIKE", DVPTR(MIKE), MIKE__STATIC, MIKE__STATICRR }, + { "VASE", DVPTR(VASE), VASE__STATIC, VASE__STATICRR }, + { "SUSHIPLATE1", DVPTR(SUSHIPLATE1), SUSHIPLATE1__STATIC, SUSHIPLATE1__STATICRR }, + { "SUSHIPLATE2", DVPTR(SUSHIPLATE2), SUSHIPLATE2__STATIC, SUSHIPLATE2__STATICRR }, + { "SUSHIPLATE3", DVPTR(SUSHIPLATE3), SUSHIPLATE3__STATIC, SUSHIPLATE3__STATICRR }, + { "SUSHIPLATE4", DVPTR(SUSHIPLATE4), SUSHIPLATE4__STATIC, SUSHIPLATE4__STATICRR }, + { "DOORTILE16", DVPTR(DOORTILE16), DOORTILE16__STATIC, DOORTILE16__STATICRR }, + { "SUSHIPLATE5", DVPTR(SUSHIPLATE5), SUSHIPLATE5__STATIC, SUSHIPLATE5__STATICRR }, + { "OJ", DVPTR(OJ), OJ__STATIC, OJ__STATICRR }, + { "MASKWALL13", DVPTR(MASKWALL13), MASKWALL13__STATIC, MASKWALL13__STATICRR }, + { "HURTRAIL", DVPTR(HURTRAIL), HURTRAIL__STATIC, HURTRAIL__STATICRR }, + { "POWERSWITCH1", DVPTR(POWERSWITCH1), POWERSWITCH1__STATIC, POWERSWITCH1__STATICRR }, + { "LOCKSWITCH1", DVPTR(LOCKSWITCH1), LOCKSWITCH1__STATIC, LOCKSWITCH1__STATICRR }, + { "POWERSWITCH2", DVPTR(POWERSWITCH2), POWERSWITCH2__STATIC, POWERSWITCH2__STATICRR }, + { "ATM", DVPTR(ATM), ATM__STATIC, ATM__STATICRR }, + { "STATUEFLASH", DVPTR(STATUEFLASH), STATUEFLASH__STATIC, STATUEFLASH__STATICRR }, + { "ATMBROKE", DVPTR(ATMBROKE), ATMBROKE__STATIC, ATMBROKE__STATICRR }, + { "BIGHOLE2", DVPTR(BIGHOLE2), BIGHOLE2__STATIC, BIGHOLE2__STATICRR }, + { "STRIPEBALL", DVPTR(STRIPEBALL), STRIPEBALL__STATIC, STRIPEBALL__STATICRR }, + { "QUEBALL", DVPTR(QUEBALL), QUEBALL__STATIC, QUEBALL__STATICRR }, + { "POCKET", DVPTR(POCKET), POCKET__STATIC, POCKET__STATICRR }, + { "WOODENHORSE", DVPTR(WOODENHORSE), WOODENHORSE__STATIC, WOODENHORSE__STATICRR }, + { "TREE1", DVPTR(TREE1), TREE1__STATIC, TREE1__STATICRR }, + { "TREE2", DVPTR(TREE2), TREE2__STATIC, TREE2__STATICRR }, + { "CACTUS", DVPTR(CACTUS), CACTUS__STATIC, CACTUS__STATICRR }, + { "MASKWALL2", DVPTR(MASKWALL2), MASKWALL2__STATIC, MASKWALL2__STATICRR }, + { "MASKWALL3", DVPTR(MASKWALL3), MASKWALL3__STATIC, MASKWALL3__STATICRR }, + { "MASKWALL4", DVPTR(MASKWALL4), MASKWALL4__STATIC, MASKWALL4__STATICRR }, + { "FIREEXT", DVPTR(FIREEXT), FIREEXT__STATIC, FIREEXT__STATICRR }, + { "TOILETWATER", DVPTR(TOILETWATER), TOILETWATER__STATIC, TOILETWATER__STATICRR }, + { "NEON1", DVPTR(NEON1), NEON1__STATIC, NEON1__STATICRR }, + { "NEON2", DVPTR(NEON2), NEON2__STATIC, NEON2__STATICRR }, + { "CACTUSBROKE", DVPTR(CACTUSBROKE), CACTUSBROKE__STATIC, CACTUSBROKE__STATICRR }, + { "BOUNCEMINE", DVPTR(BOUNCEMINE), BOUNCEMINE__STATIC, BOUNCEMINE__STATICRR }, + { "BROKEFIREHYDRENT", DVPTR(BROKEFIREHYDRENT), BROKEFIREHYDRENT__STATIC, BROKEFIREHYDRENT__STATICRR }, + { "BOX", DVPTR(BOX), BOX__STATIC, BOX__STATICRR }, + { "BULLETHOLE", DVPTR(BULLETHOLE), BULLETHOLE__STATIC, BULLETHOLE__STATICRR }, + { "BOTTLE1", DVPTR(BOTTLE1), BOTTLE1__STATIC, BOTTLE1__STATICRR }, + { "BOTTLE2", DVPTR(BOTTLE2), BOTTLE2__STATIC, BOTTLE2__STATICRR }, + { "BOTTLE3", DVPTR(BOTTLE3), BOTTLE3__STATIC, BOTTLE3__STATICRR }, + { "BOTTLE4", DVPTR(BOTTLE4), BOTTLE4__STATIC, BOTTLE4__STATICRR }, + { "FEMPIC5", DVPTR(FEMPIC5), FEMPIC5__STATIC, FEMPIC5__STATICRR }, + { "FEMPIC6", DVPTR(FEMPIC6), FEMPIC6__STATIC, FEMPIC6__STATICRR }, + { "FEMPIC7", DVPTR(FEMPIC7), FEMPIC7__STATIC, FEMPIC7__STATICRR }, + { "HYDROPLANT", DVPTR(HYDROPLANT), HYDROPLANT__STATIC, HYDROPLANT__STATICRR }, + { "OCEANSPRITE1", DVPTR(OCEANSPRITE1), OCEANSPRITE1__STATIC, OCEANSPRITE1__STATICRR }, + { "OCEANSPRITE2", DVPTR(OCEANSPRITE2), OCEANSPRITE2__STATIC, OCEANSPRITE2__STATICRR }, + { "OCEANSPRITE3", DVPTR(OCEANSPRITE3), OCEANSPRITE3__STATIC, OCEANSPRITE3__STATICRR }, + { "OCEANSPRITE4", DVPTR(OCEANSPRITE4), OCEANSPRITE4__STATIC, OCEANSPRITE4__STATICRR }, + { "OCEANSPRITE5", DVPTR(OCEANSPRITE5), OCEANSPRITE5__STATIC, OCEANSPRITE5__STATICRR }, + { "GENERICPOLE", DVPTR(GENERICPOLE), GENERICPOLE__STATIC, GENERICPOLE__STATICRR }, + { "CONE", DVPTR(CONE), CONE__STATIC, CONE__STATICRR }, + { "HANGLIGHT", DVPTR(HANGLIGHT), HANGLIGHT__STATIC, HANGLIGHT__STATICRR }, + { "HYDRENT", DVPTR(HYDRENT), HYDRENT__STATIC, HYDRENT__STATICRR }, + { "MASKWALL14", DVPTR(MASKWALL14), MASKWALL14__STATIC, MASKWALL14__STATICRR }, + { "TIRE", DVPTR(TIRE), TIRE__STATIC, TIRE__STATICRR }, + { "PIPE5", DVPTR(PIPE5), PIPE5__STATIC, PIPE5__STATICRR }, + { "PIPE6", DVPTR(PIPE6), PIPE6__STATIC, PIPE6__STATICRR }, + { "PIPE4", DVPTR(PIPE4), PIPE4__STATIC, PIPE4__STATICRR }, + { "PIPE4B", DVPTR(PIPE4B), PIPE4B__STATIC, PIPE4B__STATICRR }, + { "BROKEHYDROPLANT", DVPTR(BROKEHYDROPLANT), BROKEHYDROPLANT__STATIC, BROKEHYDROPLANT__STATICRR }, + { "PIPE5B", DVPTR(PIPE5B), PIPE5B__STATIC, PIPE5B__STATICRR }, + { "NEON3", DVPTR(NEON3), NEON3__STATIC, NEON3__STATICRR }, + { "NEON4", DVPTR(NEON4), NEON4__STATIC, NEON4__STATICRR }, + { "NEON5", DVPTR(NEON5), NEON5__STATIC, NEON5__STATICRR }, + { "BOTTLE5", DVPTR(BOTTLE5), BOTTLE5__STATIC, BOTTLE5__STATICRR }, + { "BOTTLE6", DVPTR(BOTTLE6), BOTTLE6__STATIC, BOTTLE6__STATICRR }, + { "BOTTLE8", DVPTR(BOTTLE8), BOTTLE8__STATIC, BOTTLE8__STATICRR }, + { "SPOTLITE", DVPTR(SPOTLITE), SPOTLITE__STATIC, SPOTLITE__STATICRR }, + { "HANGOOZ", DVPTR(HANGOOZ), HANGOOZ__STATIC, HANGOOZ__STATICRR }, + { "MASKWALL15", DVPTR(MASKWALL15), MASKWALL15__STATIC, MASKWALL15__STATICRR }, + { "BOTTLE7", DVPTR(BOTTLE7), BOTTLE7__STATIC, BOTTLE7__STATICRR }, + { "HORSEONSIDE", DVPTR(HORSEONSIDE), HORSEONSIDE__STATIC, HORSEONSIDE__STATICRR }, + { "GLASSPIECES", DVPTR(GLASSPIECES), GLASSPIECES__STATIC, GLASSPIECES__STATICRR }, + { "HORSELITE", DVPTR(HORSELITE), HORSELITE__STATIC, HORSELITE__STATICRR }, + { "DONUTS", DVPTR(DONUTS), DONUTS__STATIC, DONUTS__STATICRR }, + { "NEON6", DVPTR(NEON6), NEON6__STATIC, NEON6__STATICRR }, + { "MASKWALL6", DVPTR(MASKWALL6), MASKWALL6__STATIC, MASKWALL6__STATICRR }, + { "CLOCK", DVPTR(CLOCK), CLOCK__STATIC, CLOCK__STATICRR }, + { "RUBBERCAN", DVPTR(RUBBERCAN), RUBBERCAN__STATIC, RUBBERCAN__STATICRR }, + { "BROKENCLOCK", DVPTR(BROKENCLOCK), BROKENCLOCK__STATIC, BROKENCLOCK__STATICRR }, + { "PLUG", DVPTR(PLUG), PLUG__STATIC, PLUG__STATICRR }, + { "OOZFILTER", DVPTR(OOZFILTER), OOZFILTER__STATIC, OOZFILTER__STATICRR }, + { "FLOORPLASMA", DVPTR(FLOORPLASMA), FLOORPLASMA__STATIC, FLOORPLASMA__STATICRR }, + { "REACTOR", DVPTR(REACTOR), REACTOR__STATIC, REACTOR__STATICRR }, + { "REACTORSPARK", DVPTR(REACTORSPARK), REACTORSPARK__STATIC, REACTORSPARK__STATICRR }, + { "REACTORBURNT", DVPTR(REACTORBURNT), REACTORBURNT__STATIC, REACTORBURNT__STATICRR }, + { "DOORTILE15", DVPTR(DOORTILE15), DOORTILE15__STATIC, DOORTILE15__STATICRR }, + { "HANDSWITCH", DVPTR(HANDSWITCH), HANDSWITCH__STATIC, HANDSWITCH__STATICRR }, + { "CIRCLEPANNEL", DVPTR(CIRCLEPANNEL), CIRCLEPANNEL__STATIC, CIRCLEPANNEL__STATICRR }, + { "CIRCLEPANNELBROKE", DVPTR(CIRCLEPANNELBROKE), CIRCLEPANNELBROKE__STATIC, CIRCLEPANNELBROKE__STATICRR }, + { "PULLSWITCH", DVPTR(PULLSWITCH), PULLSWITCH__STATIC, PULLSWITCH__STATICRR }, + { "MASKWALL8", DVPTR(MASKWALL8), MASKWALL8__STATIC, MASKWALL8__STATICRR }, + { "BIGHOLE", DVPTR(BIGHOLE), BIGHOLE__STATIC, BIGHOLE__STATICRR }, + { "ALIENSWITCH", DVPTR(ALIENSWITCH), ALIENSWITCH__STATIC, ALIENSWITCH__STATICRR }, + { "DOORTILE21", DVPTR(DOORTILE21), DOORTILE21__STATIC, DOORTILE21__STATICRR }, + { "HANDPRINTSWITCH", DVPTR(HANDPRINTSWITCH), HANDPRINTSWITCH__STATIC, HANDPRINTSWITCH__STATICRR }, + { "BOTTLE10", DVPTR(BOTTLE10), BOTTLE10__STATIC, BOTTLE10__STATICRR }, + { "BOTTLE11", DVPTR(BOTTLE11), BOTTLE11__STATIC, BOTTLE11__STATICRR }, + { "BOTTLE12", DVPTR(BOTTLE12), BOTTLE12__STATIC, BOTTLE12__STATICRR }, + { "BOTTLE13", DVPTR(BOTTLE13), BOTTLE13__STATIC, BOTTLE13__STATICRR }, + { "BOTTLE14", DVPTR(BOTTLE14), BOTTLE14__STATIC, BOTTLE14__STATICRR }, + { "BOTTLE15", DVPTR(BOTTLE15), BOTTLE15__STATIC, BOTTLE15__STATICRR }, + { "BOTTLE16", DVPTR(BOTTLE16), BOTTLE16__STATIC, BOTTLE16__STATICRR }, + { "BOTTLE17", DVPTR(BOTTLE17), BOTTLE17__STATIC, BOTTLE17__STATICRR }, + { "BOTTLE18", DVPTR(BOTTLE18), BOTTLE18__STATIC, BOTTLE18__STATICRR }, + { "BOTTLE19", DVPTR(BOTTLE19), BOTTLE19__STATIC, BOTTLE19__STATICRR }, + { "DOORTILE17", DVPTR(DOORTILE17), DOORTILE17__STATIC, DOORTILE17__STATICRR }, + { "MASKWALL7", DVPTR(MASKWALL7), MASKWALL7__STATIC, MASKWALL7__STATICRR }, + { "JAILBARBREAK", DVPTR(JAILBARBREAK), JAILBARBREAK__STATIC, JAILBARBREAK__STATICRR }, + { "DOORTILE11", DVPTR(DOORTILE11), DOORTILE11__STATIC, DOORTILE11__STATICRR }, + { "DOORTILE12", DVPTR(DOORTILE12), DOORTILE12__STATIC, DOORTILE12__STATICRR }, + { "VENDMACHINE", DVPTR(VENDMACHINE), VENDMACHINE__STATIC, VENDMACHINE__STATICRR }, + { "VENDMACHINEBROKE", DVPTR(VENDMACHINEBROKE), VENDMACHINEBROKE__STATIC, VENDMACHINEBROKE__STATICRR }, + { "COLAMACHINE", DVPTR(COLAMACHINE), COLAMACHINE__STATIC, COLAMACHINE__STATICRR }, + { "COLAMACHINEBROKE", DVPTR(COLAMACHINEBROKE), COLAMACHINEBROKE__STATIC, COLAMACHINEBROKE__STATICRR }, + { "CRANEPOLE", DVPTR(CRANEPOLE), CRANEPOLE__STATIC, CRANEPOLE__STATICRR }, + { "CRANE", DVPTR(CRANE), CRANE__STATIC, CRANE__STATICRR }, + { "BARBROKE", DVPTR(BARBROKE), BARBROKE__STATIC, BARBROKE__STATICRR }, + { "BLOODPOOL", DVPTR(BLOODPOOL), BLOODPOOL__STATIC, BLOODPOOL__STATICRR }, + { "NUKEBARREL", DVPTR(NUKEBARREL), NUKEBARREL__STATIC, NUKEBARREL__STATICRR }, + { "NUKEBARRELDENTED", DVPTR(NUKEBARRELDENTED), NUKEBARRELDENTED__STATIC, NUKEBARRELDENTED__STATICRR }, + { "NUKEBARRELLEAKED", DVPTR(NUKEBARRELLEAKED), NUKEBARRELLEAKED__STATIC, NUKEBARRELLEAKED__STATICRR }, + { "CANWITHSOMETHING", DVPTR(CANWITHSOMETHING), CANWITHSOMETHING__STATIC, CANWITHSOMETHING__STATICRR }, + { "MONEY", DVPTR(MONEY), MONEY__STATIC, MONEY__STATICRR }, + { "BANNER", DVPTR(BANNER), BANNER__STATIC, BANNER__STATICRR }, + { "EXPLODINGBARREL", DVPTR(EXPLODINGBARREL), EXPLODINGBARREL__STATIC, EXPLODINGBARREL__STATICRR }, + { "EXPLODINGBARREL2", DVPTR(EXPLODINGBARREL2), EXPLODINGBARREL2__STATIC, EXPLODINGBARREL2__STATICRR }, + { "FIREBARREL", DVPTR(FIREBARREL), FIREBARREL__STATIC, FIREBARREL__STATICRR }, + { "SEENINE", DVPTR(SEENINE), SEENINE__STATIC, SEENINE__STATICRR }, + { "SEENINEDEAD", DVPTR(SEENINEDEAD), SEENINEDEAD__STATIC, SEENINEDEAD__STATICRR }, + { "STEAM", DVPTR(STEAM), STEAM__STATIC, STEAM__STATICRR }, + { "CEILINGSTEAM", DVPTR(CEILINGSTEAM), CEILINGSTEAM__STATIC, CEILINGSTEAM__STATICRR }, + { "PIPE6B", DVPTR(PIPE6B), PIPE6B__STATIC, PIPE6B__STATICRR }, + { "TRANSPORTERBEAM", DVPTR(TRANSPORTERBEAM), TRANSPORTERBEAM__STATIC, TRANSPORTERBEAM__STATICRR }, + { "RAT", DVPTR(RAT), RAT__STATIC, RAT__STATICRR }, + { "TRASH", DVPTR(TRASH), TRASH__STATIC, TRASH__STATICRR }, + { "FEMPIC1", DVPTR(FEMPIC1), FEMPIC1__STATIC, FEMPIC1__STATICRR }, + { "FEMPIC2", DVPTR(FEMPIC2), FEMPIC2__STATIC, FEMPIC2__STATICRR }, + { "BLANKSCREEN", DVPTR(BLANKSCREEN), BLANKSCREEN__STATIC, BLANKSCREEN__STATICRR }, + { "PODFEM1", DVPTR(PODFEM1), PODFEM1__STATIC, PODFEM1__STATICRR }, + { "FEMPIC3", DVPTR(FEMPIC3), FEMPIC3__STATIC, FEMPIC3__STATICRR }, + { "FEMPIC4", DVPTR(FEMPIC4), FEMPIC4__STATIC, FEMPIC4__STATICRR }, + { "FEM1", DVPTR(FEM1), FEM1__STATIC, FEM1__STATICRR }, + { "FEM2", DVPTR(FEM2), FEM2__STATIC, FEM2__STATICRR }, + { "FEM3", DVPTR(FEM3), FEM3__STATIC, FEM3__STATICRR }, + { "FEM5", DVPTR(FEM5), FEM5__STATIC, FEM5__STATICRR }, + { "BLOODYPOLE", DVPTR(BLOODYPOLE), BLOODYPOLE__STATIC, BLOODYPOLE__STATICRR }, + { "FEM4", DVPTR(FEM4), FEM4__STATIC, FEM4__STATICRR }, + { "FEM6", DVPTR(FEM6), FEM6__STATIC, FEM6__STATICRR }, + { "FEM6PAD", DVPTR(FEM6PAD), FEM6PAD__STATIC, FEM6PAD__STATICRR }, + { "FEM8", DVPTR(FEM8), FEM8__STATIC, FEM8__STATICRR }, + { "HELECOPT", DVPTR(HELECOPT), HELECOPT__STATIC, HELECOPT__STATICRR }, + { "FETUSJIB", DVPTR(FETUSJIB), FETUSJIB__STATIC, FETUSJIB__STATICRR }, + { "HOLODUKE", DVPTR(HOLODUKE), HOLODUKE__STATIC, HOLODUKE__STATICRR }, + { "SPACEMARINE", DVPTR(SPACEMARINE), SPACEMARINE__STATIC, SPACEMARINE__STATICRR }, + { "INDY", DVPTR(INDY), INDY__STATIC, INDY__STATICRR }, + { "FETUS", DVPTR(FETUS), FETUS__STATIC, FETUS__STATICRR }, + { "FETUSBROKE", DVPTR(FETUSBROKE), FETUSBROKE__STATIC, FETUSBROKE__STATICRR }, + { "MONK", DVPTR(MONK), MONK__STATIC, MONK__STATICRR }, + { "LUKE", DVPTR(LUKE), LUKE__STATIC, LUKE__STATICRR }, + { "COOLEXPLOSION1", DVPTR(COOLEXPLOSION1), COOLEXPLOSION1__STATIC, COOLEXPLOSION1__STATICRR }, + { "WATERSPLASH2", DVPTR(WATERSPLASH2), WATERSPLASH2__STATIC, WATERSPLASH2__STATICRR }, + { "FIREVASE", DVPTR(FIREVASE), FIREVASE__STATIC, FIREVASE__STATICRR }, + { "SCRATCH", DVPTR(SCRATCH), SCRATCH__STATIC, SCRATCH__STATICRR }, + { "FEM7", DVPTR(FEM7), FEM7__STATIC, FEM7__STATICRR }, + { "APLAYERTOP", DVPTR(APLAYERTOP), APLAYERTOP__STATIC, APLAYERTOP__STATICRR }, + { "APLAYER", DVPTR(APLAYER), APLAYER__STATIC, APLAYER__STATICRR }, + { "PLAYERONWATER", DVPTR(PLAYERONWATER), PLAYERONWATER__STATIC, PLAYERONWATER__STATICRR }, + { "DUKELYINGDEAD", DVPTR(DUKELYINGDEAD), DUKELYINGDEAD__STATIC, DUKELYINGDEAD__STATICRR }, + { "DUKETORSO", DVPTR(DUKETORSO), DUKETORSO__STATIC, DUKETORSO__STATICRR }, + { "DUKEGUN", DVPTR(DUKEGUN), DUKEGUN__STATIC, DUKEGUN__STATICRR }, + { "DUKELEG", DVPTR(DUKELEG), DUKELEG__STATIC, DUKELEG__STATICRR }, + { "SHARK", DVPTR(SHARK), SHARK__STATIC, SHARK__STATICRR }, + { "BLOOD", DVPTR(BLOOD), BLOOD__STATIC, BLOOD__STATICRR }, + { "FIRELASER", DVPTR(FIRELASER), FIRELASER__STATIC, FIRELASER__STATICRR }, + { "TRANSPORTERSTAR", DVPTR(TRANSPORTERSTAR), TRANSPORTERSTAR__STATIC, TRANSPORTERSTAR__STATICRR }, + { "SPIT", DVPTR(SPIT), SPIT__STATIC, SPIT__STATICRR }, + { "LOOGIE", DVPTR(LOOGIE), LOOGIE__STATIC, LOOGIE__STATICRR }, + { "FIST", DVPTR(FIST), FIST__STATIC, FIST__STATICRR }, + { "FREEZEBLAST", DVPTR(FREEZEBLAST), FREEZEBLAST__STATIC, FREEZEBLAST__STATICRR }, + { "DEVISTATORBLAST", DVPTR(DEVISTATORBLAST), DEVISTATORBLAST__STATIC, DEVISTATORBLAST__STATICRR }, + { "SHRINKSPARK", DVPTR(SHRINKSPARK), SHRINKSPARK__STATIC, SHRINKSPARK__STATICRR }, + { "TONGUE", DVPTR(TONGUE), TONGUE__STATIC, TONGUE__STATICRR }, + { "MORTER", DVPTR(MORTER), MORTER__STATIC, MORTER__STATICRR }, + { "SHRINKEREXPLOSION", DVPTR(SHRINKEREXPLOSION), SHRINKEREXPLOSION__STATIC, SHRINKEREXPLOSION__STATICRR }, + { "RADIUSEXPLOSION", DVPTR(RADIUSEXPLOSION), RADIUSEXPLOSION__STATIC, RADIUSEXPLOSION__STATICRR }, + { "FORCERIPPLE", DVPTR(FORCERIPPLE), FORCERIPPLE__STATIC, FORCERIPPLE__STATICRR }, + { "LIZTROOP", DVPTR(LIZTROOP), LIZTROOP__STATIC, 0 }, + { "LIZTROOPRUNNING", DVPTR(LIZTROOPRUNNING), LIZTROOPRUNNING__STATIC, 0 }, + { "LIZTROOPSTAYPUT", DVPTR(LIZTROOPSTAYPUT), LIZTROOPSTAYPUT__STATIC, 0 }, + { "LIZTOP", DVPTR(LIZTOP), LIZTOP__STATIC, 0 }, + { "LIZTROOPSHOOT", DVPTR(LIZTROOPSHOOT), LIZTROOPSHOOT__STATIC, 0 }, + { "LIZTROOPJETPACK", DVPTR(LIZTROOPJETPACK), LIZTROOPJETPACK__STATIC, 0 }, + { "LIZTROOPDSPRITE", DVPTR(LIZTROOPDSPRITE), LIZTROOPDSPRITE__STATIC, 0 }, + { "LIZTROOPONTOILET", DVPTR(LIZTROOPONTOILET), LIZTROOPONTOILET__STATIC, 0 }, + { "LIZTROOPJUSTSIT", DVPTR(LIZTROOPJUSTSIT), LIZTROOPJUSTSIT__STATIC, 0 }, + { "LIZTROOPDUCKING", DVPTR(LIZTROOPDUCKING), LIZTROOPDUCKING__STATIC, 0 }, + { "HEADJIB1", DVPTR(HEADJIB1), HEADJIB1__STATIC, 0 }, + { "ARMJIB1", DVPTR(ARMJIB1), ARMJIB1__STATIC, 0 }, + { "LEGJIB1", DVPTR(LEGJIB1), LEGJIB1__STATIC, 0 }, + { "CANNONBALL", DVPTR(CANNONBALL), CANNONBALL__STATIC, CANNONBALL__STATICRR }, + { "OCTABRAIN", DVPTR(OCTABRAIN), OCTABRAIN__STATIC, 0 }, + { "OCTABRAINSTAYPUT", DVPTR(OCTABRAINSTAYPUT), OCTABRAINSTAYPUT__STATIC, 0 }, + { "OCTATOP", DVPTR(OCTATOP), OCTATOP__STATIC, 0 }, + { "OCTADEADSPRITE", DVPTR(OCTADEADSPRITE), OCTADEADSPRITE__STATIC, 0 }, + { "INNERJAW", DVPTR(INNERJAW), INNERJAW__STATIC, INNERJAW__STATICRR }, + { "DRONE", DVPTR(DRONE), DRONE__STATIC, DRONE__STATICRR }, + { "EXPLOSION2", DVPTR(EXPLOSION2), EXPLOSION2__STATIC, EXPLOSION2__STATICRR }, + { "COMMANDER", DVPTR(COMMANDER), COMMANDER__STATIC, 0 }, + { "COMMANDERSTAYPUT", DVPTR(COMMANDERSTAYPUT), COMMANDERSTAYPUT__STATIC, 0 }, + { "RECON", DVPTR(RECON), RECON__STATIC, RECON__STATICRR }, + { "TANK", DVPTR(TANK), TANK__STATIC, 0 }, + { "PIGCOP", DVPTR(PIGCOP), PIGCOP__STATIC, 0 }, + { "PIGCOPSTAYPUT", DVPTR(PIGCOPSTAYPUT), PIGCOPSTAYPUT__STATIC, 0 }, + { "PIGCOPDIVE", DVPTR(PIGCOPDIVE), PIGCOPDIVE__STATIC, 0 }, + { "PIGCOPDEADSPRITE", DVPTR(PIGCOPDEADSPRITE), PIGCOPDEADSPRITE__STATIC, 0 }, + { "PIGTOP", DVPTR(PIGTOP), PIGTOP__STATIC, 0 }, + { "LIZMAN", DVPTR(LIZMAN), LIZMAN__STATIC, 0 }, + { "LIZMANSTAYPUT", DVPTR(LIZMANSTAYPUT), LIZMANSTAYPUT__STATIC, 0 }, + { "LIZMANSPITTING", DVPTR(LIZMANSPITTING), LIZMANSPITTING__STATIC, 0 }, + { "LIZMANFEEDING", DVPTR(LIZMANFEEDING), LIZMANFEEDING__STATIC, 0 }, + { "LIZMANJUMP", DVPTR(LIZMANJUMP), LIZMANJUMP__STATIC, 0 }, + { "LIZMANDEADSPRITE", DVPTR(LIZMANDEADSPRITE), LIZMANDEADSPRITE__STATIC, 0 }, + { "FECES", DVPTR(FECES), FECES__STATIC, FECES__STATICRR }, + { "LIZMANHEAD1", DVPTR(LIZMANHEAD1), LIZMANHEAD1__STATIC, 0 }, + { "LIZMANARM1", DVPTR(LIZMANARM1), LIZMANARM1__STATIC, 0 }, + { "LIZMANLEG1", DVPTR(LIZMANLEG1), LIZMANLEG1__STATIC, 0 }, + { "EXPLOSION2BOT", DVPTR(EXPLOSION2BOT), EXPLOSION2BOT__STATIC, EXPLOSION2BOT__STATICRR }, + { "USERWEAPON", DVPTR(USERWEAPON), USERWEAPON__STATIC, USERWEAPON__STATICRR }, + { "HEADERBAR", DVPTR(HEADERBAR), HEADERBAR__STATIC, HEADERBAR__STATICRR }, + { "JIBS1", DVPTR(JIBS1), JIBS1__STATIC, JIBS1__STATICRR }, + { "JIBS2", DVPTR(JIBS2), JIBS2__STATIC, JIBS2__STATICRR }, + { "JIBS3", DVPTR(JIBS3), JIBS3__STATIC, JIBS3__STATICRR }, + { "JIBS4", DVPTR(JIBS4), JIBS4__STATIC, JIBS4__STATICRR }, + { "JIBS5", DVPTR(JIBS5), JIBS5__STATIC, JIBS5__STATICRR }, + { "BURNING", DVPTR(BURNING), BURNING__STATIC, BURNING__STATICRR }, + { "FIRE", DVPTR(FIRE), FIRE__STATIC, FIRE__STATICRR }, + { "JIBS6", DVPTR(JIBS6), JIBS6__STATIC, JIBS6__STATICRR }, + { "BLOODSPLAT1", DVPTR(BLOODSPLAT1), BLOODSPLAT1__STATIC, BLOODSPLAT1__STATICRR }, + { "BLOODSPLAT3", DVPTR(BLOODSPLAT3), BLOODSPLAT3__STATIC, BLOODSPLAT3__STATICRR }, + { "BLOODSPLAT2", DVPTR(BLOODSPLAT2), BLOODSPLAT2__STATIC, BLOODSPLAT2__STATICRR }, + { "BLOODSPLAT4", DVPTR(BLOODSPLAT4), BLOODSPLAT4__STATIC, BLOODSPLAT4__STATICRR }, + { "OOZ", DVPTR(OOZ), OOZ__STATIC, OOZ__STATICRR }, + { "OOZ2", DVPTR(OOZ2), OOZ2__STATIC, OOZ2__STATICRR }, + { "WALLBLOOD1", DVPTR(WALLBLOOD1), WALLBLOOD1__STATIC, WALLBLOOD1__STATICRR }, + { "WALLBLOOD2", DVPTR(WALLBLOOD2), WALLBLOOD2__STATIC, WALLBLOOD2__STATICRR }, + { "WALLBLOOD3", DVPTR(WALLBLOOD3), WALLBLOOD3__STATIC, WALLBLOOD3__STATICRR }, + { "WALLBLOOD4", DVPTR(WALLBLOOD4), WALLBLOOD4__STATIC, WALLBLOOD4__STATICRR }, + { "WALLBLOOD5", DVPTR(WALLBLOOD5), WALLBLOOD5__STATIC, WALLBLOOD5__STATICRR }, + { "WALLBLOOD6", DVPTR(WALLBLOOD6), WALLBLOOD6__STATIC, WALLBLOOD6__STATICRR }, + { "WALLBLOOD7", DVPTR(WALLBLOOD7), WALLBLOOD7__STATIC, WALLBLOOD7__STATICRR }, + { "WALLBLOOD8", DVPTR(WALLBLOOD8), WALLBLOOD8__STATIC, WALLBLOOD8__STATICRR }, + { "BURNING2", DVPTR(BURNING2), BURNING2__STATIC, BURNING2__STATICRR }, + { "FIRE2", DVPTR(FIRE2), FIRE2__STATIC, FIRE2__STATICRR }, + { "CRACKKNUCKLES", DVPTR(CRACKKNUCKLES), CRACKKNUCKLES__STATIC, CRACKKNUCKLES__STATICRR }, + { "SMALLSMOKE", DVPTR(SMALLSMOKE), SMALLSMOKE__STATIC, SMALLSMOKE__STATICRR }, + { "SMALLSMOKEMAKER", DVPTR(SMALLSMOKEMAKER), SMALLSMOKEMAKER__STATIC, SMALLSMOKEMAKER__STATICRR }, + { "FLOORFLAME", DVPTR(FLOORFLAME), FLOORFLAME__STATIC, FLOORFLAME__STATICRR }, + { "ROTATEGUN", DVPTR(ROTATEGUN), ROTATEGUN__STATIC, ROTATEGUN__STATICRR }, + { "GREENSLIME", DVPTR(GREENSLIME), GREENSLIME__STATIC, GREENSLIME__STATICRR }, + { "WATERDRIPSPLASH", DVPTR(WATERDRIPSPLASH), WATERDRIPSPLASH__STATIC, WATERDRIPSPLASH__STATICRR }, + { "SCRAP6", DVPTR(SCRAP6), SCRAP6__STATIC, SCRAP6__STATICRR }, + { "SCRAP1", DVPTR(SCRAP1), SCRAP1__STATIC, SCRAP1__STATICRR }, + { "SCRAP2", DVPTR(SCRAP2), SCRAP2__STATIC, SCRAP2__STATICRR }, + { "SCRAP3", DVPTR(SCRAP3), SCRAP3__STATIC, SCRAP3__STATICRR }, + { "SCRAP4", DVPTR(SCRAP4), SCRAP4__STATIC, SCRAP4__STATICRR }, + { "SCRAP5", DVPTR(SCRAP5), SCRAP5__STATIC, SCRAP5__STATICRR }, + { "ORGANTIC", DVPTR(ORGANTIC), ORGANTIC__STATIC, ORGANTIC__STATICRR }, + { "BETAVERSION", DVPTR(BETAVERSION), BETAVERSION__STATIC, BETAVERSION__STATICRR }, + { "PLAYERISHERE", DVPTR(PLAYERISHERE), PLAYERISHERE__STATIC, PLAYERISHERE__STATICRR }, + { "PLAYERWASHERE", DVPTR(PLAYERWASHERE), PLAYERWASHERE__STATIC, PLAYERWASHERE__STATICRR }, + { "SELECTDIR", DVPTR(SELECTDIR), SELECTDIR__STATIC, SELECTDIR__STATICRR }, + { "F1HELP", DVPTR(F1HELP), F1HELP__STATIC, F1HELP__STATICRR }, + { "NOTCHON", DVPTR(NOTCHON), NOTCHON__STATIC, NOTCHON__STATICRR }, + { "NOTCHOFF", DVPTR(NOTCHOFF), NOTCHOFF__STATIC, NOTCHOFF__STATICRR }, + { "GROWSPARK", DVPTR(GROWSPARK), GROWSPARK__STATIC, GROWSPARK__STATICRR }, + { "DUKEICON", DVPTR(DUKEICON), DUKEICON__STATIC, DUKEICON__STATICRR }, + { "BADGUYICON", DVPTR(BADGUYICON), BADGUYICON__STATIC, BADGUYICON__STATICRR }, + { "FOODICON", DVPTR(FOODICON), FOODICON__STATIC, FOODICON__STATICRR }, + { "GETICON", DVPTR(GETICON), GETICON__STATIC, GETICON__STATICRR }, + { "MENUSCREEN", DVPTR(MENUSCREEN), MENUSCREEN__STATIC, MENUSCREEN__STATICRR }, + { "MENUBAR", DVPTR(MENUBAR), MENUBAR__STATIC, MENUBAR__STATICRR }, + { "KILLSICON", DVPTR(KILLSICON), KILLSICON__STATIC, KILLSICON__STATICRR }, + { "FIRSTAID_ICON", DVPTR(FIRSTAID_ICON), FIRSTAID_ICON__STATIC, FIRSTAID_ICON__STATICRR }, + { "HEAT_ICON", DVPTR(HEAT_ICON), HEAT_ICON__STATIC, HEAT_ICON__STATICRR }, + { "BOTTOMSTATUSBAR", DVPTR(BOTTOMSTATUSBAR), BOTTOMSTATUSBAR__STATIC, BOTTOMSTATUSBAR__STATICRR }, + { "BOOT_ICON", DVPTR(BOOT_ICON), BOOT_ICON__STATIC, BOOT_ICON__STATICRR }, + { "FRAGBAR", DVPTR(FRAGBAR), FRAGBAR__STATIC, FRAGBAR__STATICRR }, + { "JETPACK_ICON", DVPTR(JETPACK_ICON), JETPACK_ICON__STATIC, JETPACK_ICON__STATICRR }, + { "AIRTANK_ICON", DVPTR(AIRTANK_ICON), AIRTANK_ICON__STATIC, AIRTANK_ICON__STATICRR }, + { "STEROIDS_ICON", DVPTR(STEROIDS_ICON), STEROIDS_ICON__STATIC, STEROIDS_ICON__STATICRR }, + { "HOLODUKE_ICON", DVPTR(HOLODUKE_ICON), HOLODUKE_ICON__STATIC, HOLODUKE_ICON__STATICRR }, + { "ACCESS_ICON", DVPTR(ACCESS_ICON), ACCESS_ICON__STATIC, ACCESS_ICON__STATICRR }, + { "DIGITALNUM", DVPTR(DIGITALNUM), DIGITALNUM__STATIC, DIGITALNUM__STATICRR }, + { "DUKECAR", DVPTR(DUKECAR), DUKECAR__STATIC, DUKECAR__STATICRR }, + { "CAMCORNER", DVPTR(CAMCORNER), CAMCORNER__STATIC, CAMCORNER__STATICRR }, + { "CAMLIGHT", DVPTR(CAMLIGHT), CAMLIGHT__STATIC, CAMLIGHT__STATICRR }, + { "LOGO", DVPTR(LOGO), LOGO__STATIC, LOGO__STATICRR }, + { "TITLE", DVPTR(TITLE), TITLE__STATIC, TITLE__STATICRR }, + { "NUKEWARNINGICON", DVPTR(NUKEWARNINGICON), NUKEWARNINGICON__STATIC, NUKEWARNINGICON__STATICRR }, + { "MOUSECURSOR", DVPTR(MOUSECURSOR), MOUSECURSOR__STATIC, MOUSECURSOR__STATICRR }, + { "SLIDEBAR", DVPTR(SLIDEBAR), SLIDEBAR__STATIC, SLIDEBAR__STATICRR }, + { "DREALMS", DVPTR(DREALMS), DREALMS__STATIC, DREALMS__STATICRR }, + { "BETASCREEN", DVPTR(BETASCREEN), BETASCREEN__STATIC, BETASCREEN__STATICRR }, + { "WINDOWBORDER1", DVPTR(WINDOWBORDER1), WINDOWBORDER1__STATIC, WINDOWBORDER1__STATICRR }, + { "TEXTBOX", DVPTR(TEXTBOX), TEXTBOX__STATIC, TEXTBOX__STATICRR }, + { "WINDOWBORDER2", DVPTR(WINDOWBORDER2), WINDOWBORDER2__STATIC, WINDOWBORDER2__STATICRR }, + { "DUKENUKEM", DVPTR(DUKENUKEM), DUKENUKEM__STATIC, DUKENUKEM__STATICRR }, + { "THREEDEE", DVPTR(THREEDEE), THREEDEE__STATIC, THREEDEE__STATICRR }, + { "INGAMEDUKETHREEDEE", DVPTR(INGAMEDUKETHREEDEE), INGAMEDUKETHREEDEE__STATIC, INGAMEDUKETHREEDEE__STATICRR }, + { "TENSCREEN", DVPTR(TENSCREEN), TENSCREEN__STATIC, TENSCREEN__STATICRR }, + { "PLUTOPAKSPRITE", DVPTR(PLUTOPAKSPRITE), PLUTOPAKSPRITE__STATIC, PLUTOPAKSPRITE__STATICRR }, + { "DEVISTATOR", DVPTR(DEVISTATOR), DEVISTATOR__STATIC, DEVISTATOR__STATICRR }, + { "KNEE", DVPTR(KNEE), KNEE__STATIC, KNEE__STATICRR }, + { "CROSSHAIR", DVPTR(CROSSHAIR), CROSSHAIR__STATIC, CROSSHAIR__STATICRR }, + { "FIRSTGUN", DVPTR(FIRSTGUN), FIRSTGUN__STATIC, FIRSTGUN__STATICRR }, + { "FIRSTGUNRELOAD", DVPTR(FIRSTGUNRELOAD), FIRSTGUNRELOAD__STATIC, FIRSTGUNRELOAD__STATICRR }, + { "FALLINGCLIP", DVPTR(FALLINGCLIP), FALLINGCLIP__STATIC, FALLINGCLIP__STATICRR }, + { "CLIPINHAND", DVPTR(CLIPINHAND), CLIPINHAND__STATIC, CLIPINHAND__STATICRR }, + { "HAND", DVPTR(HAND), HAND__STATIC, HAND__STATICRR }, + { "SHELL", DVPTR(SHELL), SHELL__STATIC, SHELL__STATICRR }, + { "SHOTGUNSHELL", DVPTR(SHOTGUNSHELL), SHOTGUNSHELL__STATIC, SHOTGUNSHELL__STATICRR }, + { "CHAINGUN", DVPTR(CHAINGUN), CHAINGUN__STATIC, CHAINGUN__STATICRR }, + { "RPGGUN", DVPTR(RPGGUN), RPGGUN__STATIC, RPGGUN__STATICRR }, + { "RPGMUZZLEFLASH", DVPTR(RPGMUZZLEFLASH), RPGMUZZLEFLASH__STATIC, RPGMUZZLEFLASH__STATICRR }, + { "FREEZE", DVPTR(FREEZE), FREEZE__STATIC, FREEZE__STATICRR }, + { "CATLITE", DVPTR(CATLITE), CATLITE__STATIC, CATLITE__STATICRR }, + { "SHRINKER", DVPTR(SHRINKER), SHRINKER__STATIC, SHRINKER__STATICRR }, + { "HANDHOLDINGLASER", DVPTR(HANDHOLDINGLASER), HANDHOLDINGLASER__STATIC, HANDHOLDINGLASER__STATICRR }, + { "TRIPBOMB", DVPTR(TRIPBOMB), TRIPBOMB__STATIC, TRIPBOMB__STATICRR }, + { "LASERLINE", DVPTR(LASERLINE), LASERLINE__STATIC, LASERLINE__STATICRR }, + { "HANDHOLDINGACCESS", DVPTR(HANDHOLDINGACCESS), HANDHOLDINGACCESS__STATIC, HANDHOLDINGACCESS__STATICRR }, + { "HANDREMOTE", DVPTR(HANDREMOTE), HANDREMOTE__STATIC, HANDREMOTE__STATICRR }, + { "HANDTHROW", DVPTR(HANDTHROW), HANDTHROW__STATIC, HANDTHROW__STATICRR }, + { "TIP", DVPTR(TIP), TIP__STATIC, TIP__STATICRR }, + { "GLAIR", DVPTR(GLAIR), GLAIR__STATIC, GLAIR__STATICRR }, + { "SCUBAMASK", DVPTR(SCUBAMASK), SCUBAMASK__STATIC, SCUBAMASK__STATICRR }, + { "SPACEMASK", DVPTR(SPACEMASK), SPACEMASK__STATIC, SPACEMASK__STATICRR }, + { "FORCESPHERE", DVPTR(FORCESPHERE), FORCESPHERE__STATIC, FORCESPHERE__STATICRR }, + { "SHOTSPARK1", DVPTR(SHOTSPARK1), SHOTSPARK1__STATIC, SHOTSPARK1__STATICRR }, + { "RPG", DVPTR(RPG), RPG__STATIC, RPG__STATICRR }, + { "LASERSITE", DVPTR(LASERSITE), LASERSITE__STATIC, 0 }, + { "SHOTGUN", DVPTR(SHOTGUN), SHOTGUN__STATIC, SHOTGUN__STATICRR }, + { "BOSS1", DVPTR(BOSS1), BOSS1__STATIC, BOSS1__STATICRR }, + { "BOSS1STAYPUT", DVPTR(BOSS1STAYPUT), BOSS1STAYPUT__STATIC, 0 }, + { "BOSS1SHOOT", DVPTR(BOSS1SHOOT), BOSS1SHOOT__STATIC, 0 }, + { "BOSS1LOB", DVPTR(BOSS1LOB), BOSS1LOB__STATIC, 0 }, + { "BOSSTOP", DVPTR(BOSSTOP), BOSSTOP__STATIC, 0 }, + { "BOSS2", DVPTR(BOSS2), BOSS2__STATIC, BOSS2__STATICRR }, + { "BOSS3", DVPTR(BOSS3), BOSS3__STATIC, BOSS3__STATICRR }, + { "SPINNINGNUKEICON", DVPTR(SPINNINGNUKEICON), SPINNINGNUKEICON__STATIC, SPINNINGNUKEICON__STATICRR }, + { "BIGFNTCURSOR", DVPTR(BIGFNTCURSOR), BIGFNTCURSOR__STATIC, BIGFNTCURSOR__STATICRR }, + { "SMALLFNTCURSOR", DVPTR(SMALLFNTCURSOR), SMALLFNTCURSOR__STATIC, SMALLFNTCURSOR__STATICRR }, + { "STARTALPHANUM", DVPTR(STARTALPHANUM), STARTALPHANUM__STATIC, STARTALPHANUM__STATICRR }, + { "ENDALPHANUM", DVPTR(ENDALPHANUM), ENDALPHANUM__STATIC, ENDALPHANUM__STATICRR }, + { "BIGALPHANUM", DVPTR(BIGALPHANUM), BIGALPHANUM__STATIC, BIGALPHANUM__STATICRR }, + { "BIGPERIOD", DVPTR(BIGPERIOD), BIGPERIOD__STATIC, BIGPERIOD__STATICRR }, + { "BIGCOMMA", DVPTR(BIGCOMMA), BIGCOMMA__STATIC, BIGCOMMA__STATICRR }, + { "BIGX", DVPTR(BIGX_), BIGX__STATIC, BIGX__STATICRR }, + { "BIGQ", DVPTR(BIGQ), BIGQ__STATIC, BIGQ__STATICRR }, + { "BIGSEMI", DVPTR(BIGSEMI), BIGSEMI__STATIC, BIGSEMI__STATICRR }, + { "BIGCOLIN", DVPTR(BIGCOLIN), BIGCOLIN__STATIC, BIGCOLIN__STATICRR }, + { "THREEBYFIVE", DVPTR(THREEBYFIVE), THREEBYFIVE__STATIC, THREEBYFIVE__STATICRR }, + { "BIGAPPOS", DVPTR(BIGAPPOS), BIGAPPOS__STATIC, BIGAPPOS__STATICRR }, + { "BLANK", DVPTR(BLANK), BLANK__STATIC, BLANK__STATICRR }, + { "MINIFONT", DVPTR(MINIFONT), MINIFONT__STATIC, MINIFONT__STATICRR }, + { "BUTTON1", DVPTR(BUTTON1), BUTTON1__STATIC, BUTTON1__STATICRR }, + { "GLASS3", DVPTR(GLASS3), GLASS3__STATIC, GLASS3__STATICRR }, + { "RESPAWNMARKERRED", DVPTR(RESPAWNMARKERRED), RESPAWNMARKERRED__STATIC, RESPAWNMARKERRED__STATICRR }, + { "RESPAWNMARKERYELLOW", DVPTR(RESPAWNMARKERYELLOW), RESPAWNMARKERYELLOW__STATIC, RESPAWNMARKERYELLOW__STATICRR }, + { "RESPAWNMARKERGREEN", DVPTR(RESPAWNMARKERGREEN), RESPAWNMARKERGREEN__STATIC, RESPAWNMARKERGREEN__STATICRR }, + { "BONUSSCREEN", DVPTR(BONUSSCREEN), BONUSSCREEN__STATIC, BONUSSCREEN__STATICRR }, + { "VIEWBORDER", DVPTR(VIEWBORDER), VIEWBORDER__STATIC, VIEWBORDER__STATICRR }, + { "VICTORY1", DVPTR(VICTORY1), VICTORY1__STATIC, VICTORY1__STATICRR }, + { "ORDERING", DVPTR(ORDERING), ORDERING__STATIC, ORDERING__STATICRR }, + { "TEXTSTORY", DVPTR(TEXTSTORY), TEXTSTORY__STATIC, TEXTSTORY__STATICRR }, + { "LOADSCREEN", DVPTR(LOADSCREEN), LOADSCREEN__STATIC, LOADSCREEN__STATICRR }, + { "BORNTOBEWILDSCREEN", DVPTR(BORNTOBEWILDSCREEN), BORNTOBEWILDSCREEN__STATIC, BORNTOBEWILDSCREEN__STATICRR }, + { "BLIMP", DVPTR(BLIMP), BLIMP__STATIC, BLIMP__STATICRR }, + { "FEM9", DVPTR(FEM9), FEM9__STATIC, FEM9__STATICRR }, + { "FOOTPRINT", DVPTR(FOOTPRINT), FOOTPRINT__STATIC, FOOTPRINT__STATICRR }, + { "POOP", DVPTR(POOP), POOP__STATIC, POOP__STATICRR }, + { "FRAMEEFFECT1", DVPTR(FRAMEEFFECT1), FRAMEEFFECT1__STATIC, FRAMEEFFECT1__STATICRR }, + { "PANNEL3", DVPTR(PANNEL3), PANNEL3__STATIC, PANNEL3__STATICRR }, + { "SCREENBREAK14", DVPTR(SCREENBREAK14), SCREENBREAK14__STATIC, SCREENBREAK14__STATICRR }, + { "SCREENBREAK15", DVPTR(SCREENBREAK15), SCREENBREAK15__STATIC, SCREENBREAK15__STATICRR }, + { "SCREENBREAK19", DVPTR(SCREENBREAK19), SCREENBREAK19__STATIC, SCREENBREAK19__STATICRR }, + { "SCREENBREAK16", DVPTR(SCREENBREAK16), SCREENBREAK16__STATIC, SCREENBREAK16__STATICRR }, + { "SCREENBREAK17", DVPTR(SCREENBREAK17), SCREENBREAK17__STATIC, SCREENBREAK17__STATICRR }, + { "SCREENBREAK18", DVPTR(SCREENBREAK18), SCREENBREAK18__STATIC, SCREENBREAK18__STATICRR }, + { "W_TECHWALL11", DVPTR(W_TECHWALL11), W_TECHWALL11__STATIC, W_TECHWALL11__STATICRR }, + { "W_TECHWALL12", DVPTR(W_TECHWALL12), W_TECHWALL12__STATIC, W_TECHWALL12__STATICRR }, + { "W_TECHWALL13", DVPTR(W_TECHWALL13), W_TECHWALL13__STATIC, W_TECHWALL13__STATICRR }, + { "W_TECHWALL14", DVPTR(W_TECHWALL14), W_TECHWALL14__STATIC, W_TECHWALL14__STATICRR }, + { "W_TECHWALL5", DVPTR(W_TECHWALL5), W_TECHWALL5__STATIC, W_TECHWALL5__STATICRR }, + { "W_TECHWALL6", DVPTR(W_TECHWALL6), W_TECHWALL6__STATIC, W_TECHWALL6__STATICRR }, + { "W_TECHWALL7", DVPTR(W_TECHWALL7), W_TECHWALL7__STATIC, W_TECHWALL7__STATICRR }, + { "W_TECHWALL8", DVPTR(W_TECHWALL8), W_TECHWALL8__STATIC, W_TECHWALL8__STATICRR }, + { "W_TECHWALL9", DVPTR(W_TECHWALL9), W_TECHWALL9__STATIC, W_TECHWALL9__STATICRR }, + { "BPANNEL3", DVPTR(BPANNEL3), BPANNEL3__STATIC, BPANNEL3__STATICRR }, + { "W_HITTECHWALL16", DVPTR(W_HITTECHWALL16), W_HITTECHWALL16__STATIC, W_HITTECHWALL16__STATICRR }, + { "W_HITTECHWALL10", DVPTR(W_HITTECHWALL10), W_HITTECHWALL10__STATIC, W_HITTECHWALL10__STATICRR }, + { "W_HITTECHWALL15", DVPTR(W_HITTECHWALL15), W_HITTECHWALL15__STATIC, W_HITTECHWALL15__STATICRR }, + { "W_MILKSHELF", DVPTR(W_MILKSHELF), W_MILKSHELF__STATIC, W_MILKSHELF__STATICRR }, + { "W_MILKSHELFBROKE", DVPTR(W_MILKSHELFBROKE), W_MILKSHELFBROKE__STATIC, W_MILKSHELFBROKE__STATICRR }, + { "PURPLELAVA", DVPTR(PURPLELAVA), PURPLELAVA__STATIC, PURPLELAVA__STATICRR }, + { "LAVABUBBLE", DVPTR(LAVABUBBLE), LAVABUBBLE__STATIC, LAVABUBBLE__STATICRR }, + { "DUKECUTOUT", DVPTR(DUKECUTOUT), DUKECUTOUT__STATIC, DUKECUTOUT__STATICRR }, + { "TARGET", DVPTR(TARGET), TARGET__STATIC, TARGET__STATICRR }, + { "GUNPOWDERBARREL", DVPTR(GUNPOWDERBARREL), GUNPOWDERBARREL__STATIC, GUNPOWDERBARREL__STATICRR }, + { "DUCK", DVPTR(DUCK), DUCK__STATIC, DUCK__STATICRR }, + { "HATRACK", DVPTR(HATRACK), HATRACK__STATIC, HATRACK__STATICRR }, + { "DESKLAMP", DVPTR(DESKLAMP), DESKLAMP__STATIC, DESKLAMP__STATICRR }, + { "COFFEEMACHINE", DVPTR(COFFEEMACHINE), COFFEEMACHINE__STATIC, COFFEEMACHINE__STATICRR }, + { "CUPS", DVPTR(CUPS), CUPS__STATIC, CUPS__STATICRR }, + { "GAVALS", DVPTR(GAVALS), GAVALS__STATIC, GAVALS__STATICRR }, + { "GAVALS2", DVPTR(GAVALS2), GAVALS2__STATIC, GAVALS2__STATICRR }, + { "POLICELIGHTPOLE", DVPTR(POLICELIGHTPOLE), POLICELIGHTPOLE__STATIC, POLICELIGHTPOLE__STATICRR }, + { "FLOORBASKET", DVPTR(FLOORBASKET), FLOORBASKET__STATIC, FLOORBASKET__STATICRR }, + { "PUKE", DVPTR(PUKE), PUKE__STATIC, PUKE__STATICRR }, + { "DOORTILE23", DVPTR(DOORTILE23), DOORTILE23__STATIC, DOORTILE23__STATICRR }, + { "TOPSECRET", DVPTR(TOPSECRET), TOPSECRET__STATIC, TOPSECRET__STATICRR }, + { "SPEAKER", DVPTR(SPEAKER), SPEAKER__STATIC, SPEAKER__STATICRR }, + { "TEDDYBEAR", DVPTR(TEDDYBEAR), TEDDYBEAR__STATIC, TEDDYBEAR__STATICRR }, + { "ROBOTDOG", DVPTR(ROBOTDOG), ROBOTDOG__STATIC, ROBOTDOG__STATICRR }, + { "ROBOTPIRATE", DVPTR(ROBOTPIRATE), ROBOTPIRATE__STATIC, ROBOTPIRATE__STATICRR }, + { "ROBOTMOUSE", DVPTR(ROBOTMOUSE), ROBOTMOUSE__STATIC, ROBOTMOUSE__STATICRR }, + { "MAIL", DVPTR(MAIL), MAIL__STATIC, MAIL__STATICRR }, + { "MAILBAG", DVPTR(MAILBAG), MAILBAG__STATIC, MAILBAG__STATICRR }, + { "HOTMEAT", DVPTR(HOTMEAT), HOTMEAT__STATIC, HOTMEAT__STATICRR }, + { "COFFEEMUG", DVPTR(COFFEEMUG), COFFEEMUG__STATIC, COFFEEMUG__STATICRR }, + { "DONUTS2", DVPTR(DONUTS2), DONUTS2__STATIC, DONUTS2__STATICRR }, + { "TRIPODCAMERA", DVPTR(TRIPODCAMERA), TRIPODCAMERA__STATIC, TRIPODCAMERA__STATICRR }, + { "METER", DVPTR(METER), METER__STATIC, METER__STATICRR }, + { "DESKPHONE", DVPTR(DESKPHONE), DESKPHONE__STATIC, DESKPHONE__STATICRR }, + { "GUMBALLMACHINE", DVPTR(GUMBALLMACHINE), GUMBALLMACHINE__STATIC, GUMBALLMACHINE__STATICRR }, + { "GUMBALLMACHINEBROKE", DVPTR(GUMBALLMACHINEBROKE), GUMBALLMACHINEBROKE__STATIC, GUMBALLMACHINEBROKE__STATICRR }, + { "PAPER", DVPTR(PAPER), PAPER__STATIC, PAPER__STATICRR }, + { "MACE", DVPTR(MACE), MACE__STATIC, MACE__STATICRR }, + { "GENERICPOLE2", DVPTR(GENERICPOLE2), GENERICPOLE2__STATIC, GENERICPOLE2__STATICRR }, + { "XXXSTACY", DVPTR(XXXSTACY), XXXSTACY__STATIC, XXXSTACY__STATICRR }, + { "WETFLOOR", DVPTR(WETFLOOR), WETFLOOR__STATIC, WETFLOOR__STATICRR }, + { "BROOM", DVPTR(BROOM), BROOM__STATIC, BROOM__STATICRR }, + { "MOP", DVPTR(MOP), MOP__STATIC, MOP__STATICRR }, + { "LETTER", DVPTR(LETTER), LETTER__STATIC, 0 }, + { "PIRATE1A", DVPTR(PIRATE1A), PIRATE1A__STATIC, PIRATE1A__STATICRR }, + { "PIRATE4A", DVPTR(PIRATE4A), PIRATE4A__STATIC, PIRATE4A__STATICRR }, + { "PIRATE2A", DVPTR(PIRATE2A), PIRATE2A__STATIC, PIRATE2A__STATICRR }, + { "PIRATE5A", DVPTR(PIRATE5A), PIRATE5A__STATIC, PIRATE5A__STATICRR }, + { "PIRATE3A", DVPTR(PIRATE3A), PIRATE3A__STATIC, PIRATE3A__STATICRR }, + { "PIRATE6A", DVPTR(PIRATE6A), PIRATE6A__STATIC, PIRATE6A__STATICRR }, + { "PIRATEHALF", DVPTR(PIRATEHALF), PIRATEHALF__STATIC, PIRATEHALF__STATICRR }, + { "CHESTOFGOLD", DVPTR(CHESTOFGOLD), CHESTOFGOLD__STATIC, CHESTOFGOLD__STATICRR }, + { "SIDEBOLT1", DVPTR(SIDEBOLT1), SIDEBOLT1__STATIC, SIDEBOLT1__STATICRR }, + { "FOODOBJECT1", DVPTR(FOODOBJECT1), FOODOBJECT1__STATIC, FOODOBJECT1__STATICRR }, + { "FOODOBJECT2", DVPTR(FOODOBJECT2), FOODOBJECT2__STATIC, FOODOBJECT2__STATICRR }, + { "FOODOBJECT3", DVPTR(FOODOBJECT3), FOODOBJECT3__STATIC, FOODOBJECT3__STATICRR }, + { "FOODOBJECT4", DVPTR(FOODOBJECT4), FOODOBJECT4__STATIC, FOODOBJECT4__STATICRR }, + { "FOODOBJECT5", DVPTR(FOODOBJECT5), FOODOBJECT5__STATIC, FOODOBJECT5__STATICRR }, + { "FOODOBJECT6", DVPTR(FOODOBJECT6), FOODOBJECT6__STATIC, FOODOBJECT6__STATICRR }, + { "FOODOBJECT7", DVPTR(FOODOBJECT7), FOODOBJECT7__STATIC, FOODOBJECT7__STATICRR }, + { "FOODOBJECT8", DVPTR(FOODOBJECT8), FOODOBJECT8__STATIC, FOODOBJECT8__STATICRR }, + { "FOODOBJECT9", DVPTR(FOODOBJECT9), FOODOBJECT9__STATIC, FOODOBJECT9__STATICRR }, + { "FOODOBJECT10", DVPTR(FOODOBJECT10), FOODOBJECT10__STATIC, FOODOBJECT10__STATICRR }, + { "FOODOBJECT11", DVPTR(FOODOBJECT11), FOODOBJECT11__STATIC, FOODOBJECT11__STATICRR }, + { "FOODOBJECT12", DVPTR(FOODOBJECT12), FOODOBJECT12__STATIC, FOODOBJECT12__STATICRR }, + { "FOODOBJECT13", DVPTR(FOODOBJECT13), FOODOBJECT13__STATIC, FOODOBJECT13__STATICRR }, + { "FOODOBJECT14", DVPTR(FOODOBJECT14), FOODOBJECT14__STATIC, FOODOBJECT14__STATICRR }, + { "FOODOBJECT15", DVPTR(FOODOBJECT15), FOODOBJECT15__STATIC, FOODOBJECT15__STATICRR }, + { "FOODOBJECT16", DVPTR(FOODOBJECT16), FOODOBJECT16__STATIC, FOODOBJECT16__STATICRR }, + { "FOODOBJECT17", DVPTR(FOODOBJECT17), FOODOBJECT17__STATIC, FOODOBJECT17__STATICRR }, + { "FOODOBJECT18", DVPTR(FOODOBJECT18), FOODOBJECT18__STATIC, FOODOBJECT18__STATICRR }, + { "FOODOBJECT19", DVPTR(FOODOBJECT19), FOODOBJECT19__STATIC, FOODOBJECT19__STATICRR }, + { "FOODOBJECT20", DVPTR(FOODOBJECT20), FOODOBJECT20__STATIC, FOODOBJECT20__STATICRR }, + { "HEADLAMP", DVPTR(HEADLAMP), HEADLAMP__STATIC, HEADLAMP__STATICRR }, + { "TAMPON", DVPTR(TAMPON), TAMPON__STATIC, TAMPON__STATICRR }, + { "SKINNEDCHICKEN", DVPTR(SKINNEDCHICKEN), SKINNEDCHICKEN__STATIC, SKINNEDCHICKEN__STATICRR }, + { "FEATHEREDCHICKEN", DVPTR(FEATHEREDCHICKEN), FEATHEREDCHICKEN__STATIC, FEATHEREDCHICKEN__STATICRR }, + { "ROBOTDOG2", DVPTR(ROBOTDOG2), ROBOTDOG2__STATIC, ROBOTDOG2__STATICRR }, + { "JOLLYMEAL", DVPTR(JOLLYMEAL), JOLLYMEAL__STATIC, JOLLYMEAL__STATICRR }, + { "DUKEBURGER", DVPTR(DUKEBURGER), DUKEBURGER__STATIC, DUKEBURGER__STATICRR }, + { "SHOPPINGCART", DVPTR(SHOPPINGCART), SHOPPINGCART__STATIC, SHOPPINGCART__STATICRR }, + { "CANWITHSOMETHING2", DVPTR(CANWITHSOMETHING2), CANWITHSOMETHING2__STATIC, CANWITHSOMETHING2__STATICRR }, + { "CANWITHSOMETHING3", DVPTR(CANWITHSOMETHING3), CANWITHSOMETHING3__STATIC, CANWITHSOMETHING3__STATICRR }, + { "CANWITHSOMETHING4", DVPTR(CANWITHSOMETHING4), CANWITHSOMETHING4__STATIC, CANWITHSOMETHING4__STATICRR }, + { "SNAKEP", DVPTR(SNAKEP), SNAKEP__STATIC, SNAKEP__STATICRR }, + { "DOLPHIN1", DVPTR(DOLPHIN1), DOLPHIN1__STATIC, DOLPHIN1__STATICRR }, + { "DOLPHIN2", DVPTR(DOLPHIN2), DOLPHIN2__STATIC, DOLPHIN2__STATICRR }, + { "NEWBEAST", DVPTR(NEWBEAST), NEWBEAST__STATIC, 0 }, + { "NEWBEASTSTAYPUT", DVPTR(NEWBEASTSTAYPUT), NEWBEASTSTAYPUT__STATIC, 0 }, + { "NEWBEASTJUMP", DVPTR(NEWBEASTJUMP), NEWBEASTJUMP__STATIC, 0 }, + { "NEWBEASTHANG", DVPTR(NEWBEASTHANG), NEWBEASTHANG__STATIC, 0 }, + { "NEWBEASTHANGDEAD", DVPTR(NEWBEASTHANGDEAD), NEWBEASTHANGDEAD__STATIC, 0 }, + { "BOSS4", DVPTR(BOSS4), BOSS4__STATIC, BOSS4__STATICRR }, + { "BOSS4STAYPUT", DVPTR(BOSS4STAYPUT), BOSS4STAYPUT__STATIC, 0 }, + { "FEM10", DVPTR(FEM10), FEM10__STATIC, FEM10__STATICRR }, + { "TOUGHGAL", DVPTR(TOUGHGAL), TOUGHGAL__STATIC, TOUGHGAL__STATICRR }, + { "MAN", DVPTR(MAN), MAN__STATIC, MAN__STATICRR }, + { "MAN2", DVPTR(MAN2), MAN2__STATIC, MAN2__STATICRR }, + { "WOMAN", DVPTR(WOMAN), WOMAN__STATIC, WOMAN__STATICRR }, + { "PLEASEWAIT", DVPTR(PLEASEWAIT), PLEASEWAIT__STATIC, PLEASEWAIT__STATICRR }, + { "NATURALLIGHTNING", DVPTR(NATURALLIGHTNING), NATURALLIGHTNING__STATIC, 0 }, + { "WEATHERWARN", DVPTR(WEATHERWARN), WEATHERWARN__STATIC, 0 }, + { "DUKETAG", DVPTR(DUKETAG), DUKETAG__STATIC, DUKETAG__STATICRR }, + { "SIGN1", DVPTR(SIGN1), SIGN1__STATIC, SIGN1__STATICRR }, + { "SIGN2", DVPTR(SIGN2), SIGN2__STATIC, SIGN2__STATICRR }, + { "JURYGUY", DVPTR(JURYGUY), JURYGUY__STATIC, JURYGUY__STATICRR }, + { "RRTILE11", DVPTR(RRTILE11), 0, RRTILE11__STATICRR }, + { "RPG2SPRITE", DVPTR(RPG2SPRITE), 0, RPG2SPRITE__STATICRR }, + { "RRTILE18", DVPTR(RRTILE18), 0, RRTILE18__STATICRR }, + { "RRTILE19", DVPTR(RRTILE19), 0, RRTILE19__STATICRR }, + { "RRTILE34", DVPTR(RRTILE34), 0, RRTILE34__STATICRR }, + { "RRTILE35", DVPTR(RRTILE35), 0, RRTILE35__STATICRR }, + { "DESTRUCTO", DVPTR(DESTRUCTO), 0, DESTRUCTO__STATICRR }, + { "RRTILE38", DVPTR(RRTILE38), 0, RRTILE38__STATICRR }, + { "RRTILE43", DVPTR(RRTILE43), 0, RRTILE43__STATICRR }, + { "GUTMETER", DVPTR(GUTMETER), 0, GUTMETER__STATICRR }, + { "RRTILE63", DVPTR(RRTILE63), 0, RRTILE63__STATICRR }, + { "RRTILE64", DVPTR(RRTILE64), 0, RRTILE64__STATICRR }, + { "RRTILE65", DVPTR(RRTILE65), 0, RRTILE65__STATICRR }, + { "RRTILE66", DVPTR(RRTILE66), 0, RRTILE66__STATICRR }, + { "RRTILE67", DVPTR(RRTILE67), 0, RRTILE67__STATICRR }, + { "RRTILE68", DVPTR(RRTILE68), 0, RRTILE68__STATICRR }, + { "SOUNDFX", DVPTR(SOUNDFX), 0, SOUNDFX__STATICRR }, + { "MOTOAMMO", DVPTR(MOTOAMMO), 0, MOTOAMMO__STATICRR }, + { "UFOBEAM", DVPTR(UFOBEAM), 0, UFOBEAM__STATICRR }, + { "RRTILE280", DVPTR(RRTILE280), 0, RRTILE280__STATICRR }, + { "RRTILE281", DVPTR(RRTILE281), 0, RRTILE281__STATICRR }, + { "RRTILE282", DVPTR(RRTILE282), 0, RRTILE282__STATICRR }, + { "RRTILE283", DVPTR(RRTILE283), 0, RRTILE283__STATICRR }, + { "RRTILE285", DVPTR(RRTILE285), 0, RRTILE285__STATICRR }, + { "RRTILE286", DVPTR(RRTILE286), 0, RRTILE286__STATICRR }, + { "RRTILE287", DVPTR(RRTILE287), 0, RRTILE287__STATICRR }, + { "RRTILE288", DVPTR(RRTILE288), 0, RRTILE288__STATICRR }, + { "RRTILE289", DVPTR(RRTILE289), 0, RRTILE289__STATICRR }, + { "RRTILE290", DVPTR(RRTILE290), 0, RRTILE290__STATICRR }, + { "RRTILE291", DVPTR(RRTILE291), 0, RRTILE291__STATICRR }, + { "RRTILE292", DVPTR(RRTILE292), 0, RRTILE292__STATICRR }, + { "RRTILE293", DVPTR(RRTILE293), 0, RRTILE293__STATICRR }, + { "RRTILE295", DVPTR(RRTILE295), 0, RRTILE295__STATICRR }, + { "RRTILE296", DVPTR(RRTILE296), 0, RRTILE296__STATICRR }, + { "RRTILE297", DVPTR(RRTILE297), 0, RRTILE297__STATICRR }, + { "CDPLAYER", DVPTR(CDPLAYER), 0, CDPLAYER__STATICRR }, + { "RRTILE380", DVPTR(RRTILE380), 0, RRTILE380__STATICRR }, + { "RRTILE403", DVPTR(RRTILE403), 0, RRTILE403__STATICRR }, + { "RRTILE409", DVPTR(RRTILE409), 0, RRTILE409__STATICRR }, + { "GUTMETER_LIGHT1", DVPTR(GUTMETER_LIGHT1), 0, GUTMETER_LIGHT1__STATICRR }, + { "GUTMETER_LIGHT2", DVPTR(GUTMETER_LIGHT2), 0, GUTMETER_LIGHT2__STATICRR }, + { "GUTMETER_LIGHT3", DVPTR(GUTMETER_LIGHT3), 0, GUTMETER_LIGHT3__STATICRR }, + { "GUTMETER_LIGHT4", DVPTR(GUTMETER_LIGHT4), 0, GUTMETER_LIGHT4__STATICRR }, + { "AMMO_ICON", DVPTR(AMMO_ICON), 0, AMMO_ICON__STATICRR }, + { "RRTILE409", DVPTR(RRTILE1076), 0, RRTILE1076__STATICRR }, + { "MUD", DVPTR(MUD), 0, MUD__STATICRR }, + { "EXPLOSION3", DVPTR(EXPLOSION3), 0, EXPLOSION3__STATICRR }, + { "RRTILE1636", DVPTR(RRTILE1636), 0, RRTILE1636__STATICRR }, + { "WEAPONBAR", DVPTR(WEAPONBAR), 0, WEAPONBAR__STATICRR }, + { "RRTILE1752", DVPTR(RRTILE1752), 0, RRTILE1752__STATICRR }, + { "RPG2", DVPTR(RPG2), 0, RPG2__STATICRR }, + { "RRTILE1790", DVPTR(RRTILE1790), 0, RRTILE1790__STATICRR }, + { "RRTILE1792", DVPTR(RRTILE1792), 0, RRTILE1792__STATICRR }, + { "RRTILE1801", DVPTR(RRTILE1801), 0, RRTILE1801__STATICRR }, + { "RRTILE1805", DVPTR(RRTILE1805), 0, RRTILE1805__STATICRR }, + { "RRTILE1807", DVPTR(RRTILE1807), 0, RRTILE1807__STATICRR }, + { "RRTILE1808", DVPTR(RRTILE1808), 0, RRTILE1808__STATICRR }, + { "RRTILE1812", DVPTR(RRTILE1812), 0, RRTILE1812__STATICRR }, + { "RRTILE1814", DVPTR(RRTILE1814), 0, RRTILE1814__STATICRR }, + { "RRTILE1817", DVPTR(RRTILE1817), 0, RRTILE1817__STATICRR }, + { "RRTILE1821", DVPTR(RRTILE1821), 0, RRTILE1821__STATICRR }, + { "RRTILE1824", DVPTR(RRTILE1824), 0, RRTILE1824__STATICRR }, + { "RRTILE1826", DVPTR(RRTILE1826), 0, RRTILE1826__STATICRR }, + { "RRTILE1850", DVPTR(RRTILE1850), 0, RRTILE1850__STATICRR }, + { "RRTILE1851", DVPTR(RRTILE1851), 0, RRTILE1851__STATICRR }, + { "RRTILE1856", DVPTR(RRTILE1856), 0, RRTILE1856__STATICRR }, + { "RRTILE1877", DVPTR(RRTILE1877), 0, RRTILE1877__STATICRR }, + { "RRTILE1878", DVPTR(RRTILE1878), 0, RRTILE1878__STATICRR }, + { "RRTILE1938", DVPTR(RRTILE1938), 0, RRTILE1938__STATICRR }, + { "RRTILE1939", DVPTR(RRTILE1939), 0, RRTILE1939__STATICRR }, + { "RRTILE1942", DVPTR(RRTILE1942), 0, RRTILE1942__STATICRR }, + { "RRTILE1944", DVPTR(RRTILE1944), 0, RRTILE1944__STATICRR }, + { "RRTILE1945", DVPTR(RRTILE1945), 0, RRTILE1945__STATICRR }, + { "RRTILE1947", DVPTR(RRTILE1947), 0, RRTILE1947__STATICRR }, + { "RRTILE1951", DVPTR(RRTILE1951), 0, RRTILE1951__STATICRR }, + { "RRTILE1952", DVPTR(RRTILE1952), 0, RRTILE1952__STATICRR }, + { "RRTILE1953", DVPTR(RRTILE1953), 0, RRTILE1953__STATICRR }, + { "RRTILE1961", DVPTR(RRTILE1961), 0, RRTILE1961__STATICRR }, + { "RRTILE1964", DVPTR(RRTILE1964), 0, RRTILE1964__STATICRR }, + { "RRTILE1973", DVPTR(RRTILE1973), 0, RRTILE1973__STATICRR }, + { "RRTILE1985", DVPTR(RRTILE1985), 0, RRTILE1985__STATICRR }, + { "RRTILE1986", DVPTR(RRTILE1986), 0, RRTILE1986__STATICRR }, + { "RRTILE1987", DVPTR(RRTILE1987), 0, RRTILE1987__STATICRR }, + { "RRTILE1988", DVPTR(RRTILE1988), 0, RRTILE1988__STATICRR }, + { "RRTILE1990", DVPTR(RRTILE1990), 0, RRTILE1990__STATICRR }, + { "RRTILE1995", DVPTR(RRTILE1995), 0, RRTILE1995__STATICRR }, + { "RRTILE1996", DVPTR(RRTILE1996), 0, RRTILE1996__STATICRR }, + { "RRTILE2004", DVPTR(RRTILE2004), 0, RRTILE2004__STATICRR }, + { "RRTILE2005", DVPTR(RRTILE2005), 0, RRTILE2005__STATICRR }, + { "POPCORN", DVPTR(POPCORN), 0, POPCORN__STATICRR }, + { "RRTILE2022", DVPTR(RRTILE2022), 0, RRTILE2022__STATICRR }, + { "LANEPICS", DVPTR(LANEPICS), 0, LANEPICS__STATICRR }, + { "RRTILE2025", DVPTR(RRTILE2025), 0, RRTILE2025__STATICRR }, + { "RRTILE2026", DVPTR(RRTILE2026), 0, RRTILE2026__STATICRR }, + { "RRTILE2027", DVPTR(RRTILE2027), 0, RRTILE2027__STATICRR }, + { "RRTILE2028", DVPTR(RRTILE2028), 0, RRTILE2028__STATICRR }, + { "RRTILE2034", DVPTR(RRTILE2034), 0, RRTILE2034__STATICRR }, + { "RRTILE2050", DVPTR(RRTILE2050), 0, RRTILE2050__STATICRR }, + { "RRTILE2052", DVPTR(RRTILE2052), 0, RRTILE2052__STATICRR }, + { "RRTILE2053", DVPTR(RRTILE2053), 0, RRTILE2053__STATICRR }, + { "RRTILE2056", DVPTR(RRTILE2056), 0, RRTILE2056__STATICRR }, + { "RRTILE2060", DVPTR(RRTILE2060), 0, RRTILE2060__STATICRR }, + { "RRTILE2072", DVPTR(RRTILE2072), 0, RRTILE2072__STATICRR }, + { "RRTILE2074", DVPTR(RRTILE2074), 0, RRTILE2074__STATICRR }, + { "RRTILE2075", DVPTR(RRTILE2075), 0, RRTILE2075__STATICRR }, + { "RRTILE2083", DVPTR(RRTILE2083), 0, RRTILE2083__STATICRR }, + { "RRTILE2097", DVPTR(RRTILE2097), 0, RRTILE2097__STATICRR }, + { "RRTILE2121", DVPTR(RRTILE2121), 0, RRTILE2121__STATICRR }, + { "RRTILE2122", DVPTR(RRTILE2122), 0, RRTILE2122__STATICRR }, + { "RRTILE2123", DVPTR(RRTILE2123), 0, RRTILE2123__STATICRR }, + { "RRTILE2124", DVPTR(RRTILE2124), 0, RRTILE2124__STATICRR }, + { "RRTILE2125", DVPTR(RRTILE2125), 0, RRTILE2125__STATICRR }, + { "RRTILE2126", DVPTR(RRTILE2126), 0, RRTILE2126__STATICRR }, + { "RRTILE2137", DVPTR(RRTILE2137), 0, RRTILE2137__STATICRR }, + { "RRTILE2132", DVPTR(RRTILE2132), 0, RRTILE2132__STATICRR }, + { "RRTILE2136", DVPTR(RRTILE2136), 0, RRTILE2136__STATICRR }, + { "RRTILE2139", DVPTR(RRTILE2139), 0, RRTILE2139__STATICRR }, + { "RRTILE2150", DVPTR(RRTILE2150), 0, RRTILE2150__STATICRR }, + { "RRTILE2151", DVPTR(RRTILE2151), 0, RRTILE2151__STATICRR }, + { "RRTILE2152", DVPTR(RRTILE2152), 0, RRTILE2152__STATICRR }, + { "RRTILE2156", DVPTR(RRTILE2156), 0, RRTILE2156__STATICRR }, + { "RRTILE2157", DVPTR(RRTILE2157), 0, RRTILE2157__STATICRR }, + { "RRTILE2158", DVPTR(RRTILE2158), 0, RRTILE2158__STATICRR }, + { "RRTILE2159", DVPTR(RRTILE2159), 0, RRTILE2159__STATICRR }, + { "RRTILE2160", DVPTR(RRTILE2160), 0, RRTILE2160__STATICRR }, + { "RRTILE2161", DVPTR(RRTILE2161), 0, RRTILE2161__STATICRR }, + { "RRTILE2175", DVPTR(RRTILE2175), 0, RRTILE2175__STATICRR }, + { "RRTILE2176", DVPTR(RRTILE2176), 0, RRTILE2176__STATICRR }, + { "RRTILE2178", DVPTR(RRTILE2178), 0, RRTILE2178__STATICRR }, + { "RRTILE2186", DVPTR(RRTILE2186), 0, RRTILE2186__STATICRR }, + { "RRTILE2214", DVPTR(RRTILE2214), 0, RRTILE2214__STATICRR }, + { "RRTILE2319", DVPTR(RRTILE2319), 0, RRTILE2319__STATICRR }, + { "RRTILE2321", DVPTR(RRTILE2321), 0, RRTILE2321__STATICRR }, + { "RRTILE2326", DVPTR(RRTILE2326), 0, RRTILE2326__STATICRR }, + { "RRTILE2329", DVPTR(RRTILE2329), 0, RRTILE2329__STATICRR }, + { "RRTILE2357", DVPTR(RRTILE2357), 0, RRTILE2357__STATICRR }, + { "RRTILE2382", DVPTR(RRTILE2382), 0, RRTILE2382__STATICRR }, + { "RRTILE2430", DVPTR(RRTILE2430), 0, RRTILE2430__STATICRR }, + { "RRTILE2431", DVPTR(RRTILE2431), 0, RRTILE2431__STATICRR }, + { "RRTILE2432", DVPTR(RRTILE2432), 0, RRTILE2432__STATICRR }, + { "RRTILE2437", DVPTR(RRTILE2437), 0, RRTILE2437__STATICRR }, + { "RRTILE2443", DVPTR(RRTILE2443), 0, RRTILE2443__STATICRR }, + { "RRTILE2445", DVPTR(RRTILE2445), 0, RRTILE2445__STATICRR }, + { "RRTILE2446", DVPTR(RRTILE2446), 0, RRTILE2446__STATICRR }, + { "RRTILE2450", DVPTR(RRTILE2450), 0, RRTILE2450__STATICRR }, + { "RRTILE2451", DVPTR(RRTILE2451), 0, RRTILE2451__STATICRR }, + { "RRTILE2455", DVPTR(RRTILE2455), 0, RRTILE2455__STATICRR }, + { "RRTILE2460", DVPTR(RRTILE2460), 0, RRTILE2460__STATICRR }, + { "RRTILE2465", DVPTR(RRTILE2465), 0, RRTILE2465__STATICRR }, + { "RRTILE2560", DVPTR(RRTILE2560), 0, RRTILE2560__STATICRR }, + { "RRTILE2562", DVPTR(RRTILE2562), 0, RRTILE2562__STATICRR }, + { "RRTILE2564", DVPTR(RRTILE2564), 0, RRTILE2564__STATICRR }, + { "RRTILE2573", DVPTR(RRTILE2573), 0, RRTILE2573__STATICRR }, + { "RRTILE2574", DVPTR(RRTILE2574), 0, RRTILE2574__STATICRR }, + { "RRTILE2577", DVPTR(RRTILE2577), 0, RRTILE2577__STATICRR }, + { "RRTILE2578", DVPTR(RRTILE2578), 0, RRTILE2578__STATICRR }, + { "RRTILE2581", DVPTR(RRTILE2581), 0, RRTILE2581__STATICRR }, + { "RRTILE2583", DVPTR(RRTILE2583), 0, RRTILE2583__STATICRR }, + { "RRTILE2604", DVPTR(RRTILE2604), 0, RRTILE2604__STATICRR }, + { "RRTILE2610", DVPTR(RRTILE2610), 0, RRTILE2610__STATICRR }, + { "RRTILE2613", DVPTR(RRTILE2613), 0, RRTILE2613__STATICRR }, + { "RRTILE2621", DVPTR(RRTILE2621), 0, RRTILE2621__STATICRR }, + { "RRTILE2622", DVPTR(RRTILE2622), 0, RRTILE2622__STATICRR }, + { "RRTILE2636", DVPTR(RRTILE2636), 0, RRTILE2636__STATICRR }, + { "RRTILE2637", DVPTR(RRTILE2637), 0, RRTILE2637__STATICRR }, + { "RRTILE2654", DVPTR(RRTILE2654), 0, RRTILE2654__STATICRR }, + { "RRTILE2656", DVPTR(RRTILE2656), 0, RRTILE2656__STATICRR }, + { "RRTILE2676", DVPTR(RRTILE2676), 0, RRTILE2676__STATICRR }, + { "RRTILE2689", DVPTR(RRTILE2689), 0, RRTILE2689__STATICRR }, + { "RRTILE2697", DVPTR(RRTILE2697), 0, RRTILE2697__STATICRR }, + { "RRTILE2702", DVPTR(RRTILE2702), 0, RRTILE2702__STATICRR }, + { "RRTILE2707", DVPTR(RRTILE2707), 0, RRTILE2707__STATICRR }, + { "RRTILE2732", DVPTR(RRTILE2732), 0, RRTILE2732__STATICRR }, + { "RRTILE2030", DVPTR(RRTILE2030), 0, RRTILE2030__STATICRR }, + { "RRTILE2831", DVPTR(RRTILE2831), 0, RRTILE2831__STATICRR }, + { "RRTILE2832", DVPTR(RRTILE2832), 0, RRTILE2832__STATICRR }, + { "RRTILE2842", DVPTR(RRTILE2842), 0, RRTILE2842__STATICRR }, + { "RRTILE2859", DVPTR(RRTILE2859), 0, RRTILE2859__STATICRR }, + { "RRTILE2876", DVPTR(RRTILE2876), 0, RRTILE2876__STATICRR }, + { "RRTILE2878", DVPTR(RRTILE2878), 0, RRTILE2878__STATICRR }, + { "RRTILE2879", DVPTR(RRTILE2879), 0, RRTILE2879__STATICRR }, + { "RRTILE2893", DVPTR(RRTILE2893), 0, RRTILE2893__STATICRR }, + { "RRTILE2894", DVPTR(RRTILE2894), 0, RRTILE2894__STATICRR }, + { "RRTILE2898", DVPTR(RRTILE2898), 0, RRTILE2898__STATICRR }, + { "RRTILE2899", DVPTR(RRTILE2899), 0, RRTILE2899__STATICRR }, + { "RRTILE2915", DVPTR(RRTILE2915), 0, RRTILE2915__STATICRR }, + { "RRTILE2940", DVPTR(RRTILE2940), 0, RRTILE2940__STATICRR }, + { "RRTILE2944", DVPTR(RRTILE2944), 0, RRTILE2944__STATICRR }, + { "RRTILE2945", DVPTR(RRTILE2945), 0, RRTILE2945__STATICRR }, + { "RRTILE2946", DVPTR(RRTILE2946), 0, RRTILE2946__STATICRR }, + { "RRTILE2947", DVPTR(RRTILE2947), 0, RRTILE2947__STATICRR }, + { "RRTILE2948", DVPTR(RRTILE2948), 0, RRTILE2948__STATICRR }, + { "RRTILE2949", DVPTR(RRTILE2949), 0, RRTILE2949__STATICRR }, + { "RRTILE2961", DVPTR(RRTILE2961), 0, RRTILE2961__STATICRR }, + { "RRTILE2970", DVPTR(RRTILE2970), 0, RRTILE2970__STATICRR }, + { "RRTILE2977", DVPTR(RRTILE2977), 0, RRTILE2977__STATICRR }, + { "RRTILE2978", DVPTR(RRTILE2978), 0, RRTILE2978__STATICRR }, + { "RRTILE2990", DVPTR(RRTILE2990), 0, RRTILE2990__STATICRR }, + { "RRTILE3073", DVPTR(RRTILE3073), 0, RRTILE3073__STATICRR }, + { "RRTILE3083", DVPTR(RRTILE3083), 0, RRTILE3083__STATICRR }, + { "RRTILE3100", DVPTR(RRTILE3100), 0, RRTILE3100__STATICRR }, + { "RRTILE3114", DVPTR(RRTILE3114), 0, RRTILE3114__STATICRR }, + { "RRTILE3115", DVPTR(RRTILE3115), 0, RRTILE3115__STATICRR }, + { "RRTILE3116", DVPTR(RRTILE3116), 0, RRTILE3116__STATICRR }, + { "RRTILE3117", DVPTR(RRTILE3117), 0, RRTILE3117__STATICRR }, + { "RRTILE3120", DVPTR(RRTILE3120), 0, RRTILE3120__STATICRR }, + { "RRTILE3121", DVPTR(RRTILE3121), 0, RRTILE3121__STATICRR }, + { "RRTILE3122", DVPTR(RRTILE3122), 0, RRTILE3122__STATICRR }, + { "RRTILE3123", DVPTR(RRTILE3123), 0, RRTILE3123__STATICRR }, + { "RRTILE3124", DVPTR(RRTILE3124), 0, RRTILE3124__STATICRR }, + { "RRTILE3132", DVPTR(RRTILE3132), 0, RRTILE3132__STATICRR }, + { "RRTILE3139", DVPTR(RRTILE3139), 0, RRTILE3139__STATICRR }, + { "RRTILE3144", DVPTR(RRTILE3144), 0, RRTILE3144__STATICRR }, + { "RRTILE3152", DVPTR(RRTILE3152), 0, RRTILE3152__STATICRR }, + { "RRTILE3153", DVPTR(RRTILE3153), 0, RRTILE3153__STATICRR }, + { "RRTILE3155", DVPTR(RRTILE3155), 0, RRTILE3155__STATICRR }, + { "RRTILE3171", DVPTR(RRTILE3171), 0, RRTILE3171__STATICRR }, + { "RRTILE3172", DVPTR(RRTILE3172), 0, RRTILE3172__STATICRR }, + { "RRTILE3190", DVPTR(RRTILE3190), 0, RRTILE3190__STATICRR }, + { "RRTILE3191", DVPTR(RRTILE3191), 0, RRTILE3191__STATICRR }, + { "RRTILE3192", DVPTR(RRTILE3192), 0, RRTILE3192__STATICRR }, + { "RRTILE3195", DVPTR(RRTILE3195), 0, RRTILE3195__STATICRR }, + { "RRTILE3200", DVPTR(RRTILE3200), 0, RRTILE3200__STATICRR }, + { "RRTILE3201", DVPTR(RRTILE3201), 0, RRTILE3201__STATICRR }, + { "RRTILE3202", DVPTR(RRTILE3202), 0, RRTILE3202__STATICRR }, + { "RRTILE3203", DVPTR(RRTILE3203), 0, RRTILE3203__STATICRR }, + { "RRTILE3204", DVPTR(RRTILE3204), 0, RRTILE3204__STATICRR }, + { "RRTILE3205", DVPTR(RRTILE3205), 0, RRTILE3205__STATICRR }, + { "RRTILE3206", DVPTR(RRTILE3206), 0, RRTILE3206__STATICRR }, + { "RRTILE3207", DVPTR(RRTILE3207), 0, RRTILE3207__STATICRR }, + { "RRTILE3208", DVPTR(RRTILE3208), 0, RRTILE3208__STATICRR }, + { "RRTILE3209", DVPTR(RRTILE3209), 0, RRTILE3209__STATICRR }, + { "RRTILE3216", DVPTR(RRTILE3216), 0, RRTILE3216__STATICRR }, + { "RRTILE3218", DVPTR(RRTILE3218), 0, RRTILE3218__STATICRR }, + { "RRTILE3219", DVPTR(RRTILE3219), 0, RRTILE3219__STATICRR }, + { "RRTILE3232", DVPTR(RRTILE3232), 0, RRTILE3232__STATICRR }, + { "SHOTGUNSHELLS", DVPTR(SHOTGUNSHELLS), 0, SHOTGUNSHELLS__STATICRR }, + { "CIRCLESTUCK", DVPTR(CIRCLESTUCK), 0, CIRCLESTUCK__STATICRR }, + { "RRTILE3410", DVPTR(RRTILE3410), 0, RRTILE3410__STATICRR }, + { "LUMBERBLADE", DVPTR(LUMBERBLADE), 0, LUMBERBLADE__STATICRR }, + { "BOWLINGBALLH", DVPTR(BOWLINGBALLH), 0, BOWLINGBALLH__STATICRR }, + { "BOWLINGBALL", DVPTR(BOWLINGBALL), 0, BOWLINGBALL__STATICRR }, + { "BOWLINGBALLSPRITE", DVPTR(BOWLINGBALLSPRITE), 0, BOWLINGBALLSPRITE__STATICRR }, + { "POWDERH", DVPTR(POWDERH), 0, POWDERH__STATICRR }, + { "RRTILE3440", DVPTR(RRTILE3440), 0, RRTILE3440__STATICRR }, + { "RRTILE3462", DVPTR(RRTILE3462), 0, RRTILE3462__STATICRR }, + { "OWHIP", DVPTR(OWHIP), 0, OWHIP__STATICRR }, + { "UWHIP", DVPTR(UWHIP), 0, UWHIP__STATICRR }, + { "RPGGUN2", DVPTR(RPGGUN2), 0, RPGGUN2__STATICRR }, + { "RRTILE3497", DVPTR(RRTILE3497), 0, RRTILE3497__STATICRR }, + { "RRTILE3498", DVPTR(RRTILE3498), 0, RRTILE3498__STATICRR }, + { "RRTILE3499", DVPTR(RRTILE3499), 0, RRTILE3499__STATICRR }, + { "RRTILE3500", DVPTR(RRTILE3500), 0, RRTILE3500__STATICRR }, + { "SLINGBLADE", DVPTR(SLINGBLADE), 0, SLINGBLADE__STATICRR }, + { "RRTILE3584", DVPTR(RRTILE3584), 0, RRTILE3584__STATICRR }, + { "RRTILE3586", DVPTR(RRTILE3586), 0, RRTILE3586__STATICRR }, + { "RRTILE3587", DVPTR(RRTILE3587), 0, RRTILE3587__STATICRR }, + { "RRTILE3600", DVPTR(RRTILE3600), 0, RRTILE3600__STATICRR }, + { "RRTILE3631", DVPTR(RRTILE3631), 0, RRTILE3631__STATICRR }, + { "RRTILE3635", DVPTR(RRTILE3635), 0, RRTILE3635__STATICRR }, + { "RRTILE3637", DVPTR(RRTILE3637), 0, RRTILE3637__STATICRR }, + { "RRTILE3643", DVPTR(RRTILE3643), 0, RRTILE3643__STATICRR }, + { "RRTILE3647", DVPTR(RRTILE3647), 0, RRTILE3647__STATICRR }, + { "RRTILE3652", DVPTR(RRTILE3652), 0, RRTILE3652__STATICRR }, + { "RRTILE3653", DVPTR(RRTILE3653), 0, RRTILE3653__STATICRR }, + { "RRTILE3668", DVPTR(RRTILE3668), 0, RRTILE3668__STATICRR }, + { "RRTILE3671", DVPTR(RRTILE3671), 0, RRTILE3671__STATICRR }, + { "RRTILE3673", DVPTR(RRTILE3673), 0, RRTILE3673__STATICRR }, + { "RRTILE3677", DVPTR(RRTILE3677), 0, RRTILE3677__STATICRR }, + { "RRTILE3684", DVPTR(RRTILE3684), 0, RRTILE3684__STATICRR }, + { "RRTILE3708", DVPTR(RRTILE3708), 0, RRTILE3708__STATICRR }, + { "RRTILE3714", DVPTR(RRTILE3714), 0, RRTILE3714__STATICRR }, + { "RRTILE3716", DVPTR(RRTILE3716), 0, RRTILE3716__STATICRR }, + { "RRTILE3720", DVPTR(RRTILE3720), 0, RRTILE3720__STATICRR }, + { "RRTILE3723", DVPTR(RRTILE3723), 0, RRTILE3723__STATICRR }, + { "RRTILE3725", DVPTR(RRTILE3725), 0, RRTILE3725__STATICRR }, + { "RRTILE3737", DVPTR(RRTILE3737), 0, RRTILE3737__STATICRR }, + { "RRTILE3754", DVPTR(RRTILE3754), 0, RRTILE3754__STATICRR }, + { "RRTILE3762", DVPTR(RRTILE3762), 0, RRTILE3762__STATICRR }, + { "RRTILE3763", DVPTR(RRTILE3763), 0, RRTILE3763__STATICRR }, + { "RRTILE3764", DVPTR(RRTILE3764), 0, RRTILE3764__STATICRR }, + { "RRTILE3765", DVPTR(RRTILE3765), 0, RRTILE3765__STATICRR }, + { "RRTILE3767", DVPTR(RRTILE3767), 0, RRTILE3767__STATICRR }, + { "RRTILE3773", DVPTR(RRTILE3773), 0, RRTILE3773__STATICRR }, + { "RRTILE3774", DVPTR(RRTILE3774), 0, RRTILE3774__STATICRR }, + { "RRTILE3793", DVPTR(RRTILE3793), 0, RRTILE3793__STATICRR }, + { "RRTILE3795", DVPTR(RRTILE3795), 0, RRTILE3795__STATICRR }, + { "RRTILE3804", DVPTR(RRTILE3804), 0, RRTILE3804__STATICRR }, + { "RRTILE3814", DVPTR(RRTILE3814), 0, RRTILE3814__STATICRR }, + { "RRTILE3815", DVPTR(RRTILE3815), 0, RRTILE3815__STATICRR }, + { "RRTILE3819", DVPTR(RRTILE3819), 0, RRTILE3819__STATICRR }, + { "RRTILE3827", DVPTR(RRTILE3827), 0, RRTILE3827__STATICRR }, + { "RRTILE3837", DVPTR(RRTILE3837), 0, RRTILE3837__STATICRR }, + { "RRTILE5014", DVPTR(RRTILE5014), 0, RRTILE5014__STATICRR }, + { "RRTILE5016", DVPTR(RRTILE5016), 0, RRTILE5016__STATICRR }, + { "RRTILE5017", DVPTR(RRTILE5017), 0, RRTILE5017__STATICRR }, + { "RRTILE5018", DVPTR(RRTILE5018), 0, RRTILE5018__STATICRR }, + { "RRTILE5019", DVPTR(RRTILE5019), 0, RRTILE5019__STATICRR }, + { "RRTILE5020", DVPTR(RRTILE5020), 0, RRTILE5020__STATICRR }, + { "RRTILE5021", DVPTR(RRTILE5021), 0, RRTILE5021__STATICRR }, + { "RRTILE5022", DVPTR(RRTILE5022), 0, RRTILE5022__STATICRR }, + { "RRTILE5023", DVPTR(RRTILE5023), 0, RRTILE5023__STATICRR }, + { "RRTILE5024", DVPTR(RRTILE5024), 0, RRTILE5024__STATICRR }, + { "RRTILE5025", DVPTR(RRTILE5025), 0, RRTILE5025__STATICRR }, + { "RRTILE5026", DVPTR(RRTILE5026), 0, RRTILE5026__STATICRR }, + { "RRTILE5027", DVPTR(RRTILE5027), 0, RRTILE5027__STATICRR }, + { "RRTILE5029", DVPTR(RRTILE5029), 0, RRTILE5029__STATICRR }, + { "RRTILE5030", DVPTR(RRTILE5030), 0, RRTILE5030__STATICRR }, + { "RRTILE5031", DVPTR(RRTILE5031), 0, RRTILE5031__STATICRR }, + { "RRTILE5032", DVPTR(RRTILE5032), 0, RRTILE5032__STATICRR }, + { "RRTILE5033", DVPTR(RRTILE5033), 0, RRTILE5033__STATICRR }, + { "RRTILE5034", DVPTR(RRTILE5034), 0, RRTILE5034__STATICRR }, + { "RRTILE5035", DVPTR(RRTILE5035), 0, RRTILE5035__STATICRR }, + { "RRTILE5036", DVPTR(RRTILE5036), 0, RRTILE5036__STATICRR }, + { "RRTILE5037", DVPTR(RRTILE5037), 0, RRTILE5037__STATICRR }, + { "RRTILE5038", DVPTR(RRTILE5038), 0, RRTILE5038__STATICRR }, + { "RRTILE5039", DVPTR(RRTILE5039), 0, RRTILE5039__STATICRR }, + { "RRTILE5040", DVPTR(RRTILE5040), 0, RRTILE5040__STATICRR }, + { "RRTILE5041", DVPTR(RRTILE5041), 0, RRTILE5041__STATICRR }, + { "RRTILE5043", DVPTR(RRTILE5043), 0, RRTILE5043__STATICRR }, + { "RRTILE5044", DVPTR(RRTILE5044), 0, RRTILE5044__STATICRR }, + { "RRTILE5045", DVPTR(RRTILE5045), 0, RRTILE5045__STATICRR }, + { "RRTILE5046", DVPTR(RRTILE5046), 0, RRTILE5046__STATICRR }, + { "RRTILE5047", DVPTR(RRTILE5047), 0, RRTILE5047__STATICRR }, + { "RRTILE5048", DVPTR(RRTILE5048), 0, RRTILE5048__STATICRR }, + { "RRTILE5049", DVPTR(RRTILE5049), 0, RRTILE5049__STATICRR }, + { "RRTILE5050", DVPTR(RRTILE5050), 0, RRTILE5050__STATICRR }, + { "RRTILE5051", DVPTR(RRTILE5051), 0, RRTILE5051__STATICRR }, + { "RRTILE5052", DVPTR(RRTILE5052), 0, RRTILE5052__STATICRR }, + { "RRTILE5053", DVPTR(RRTILE5053), 0, RRTILE5053__STATICRR }, + { "RRTILE5054", DVPTR(RRTILE5054), 0, RRTILE5054__STATICRR }, + { "RRTILE5055", DVPTR(RRTILE5055), 0, RRTILE5055__STATICRR }, + { "RRTILE5056", DVPTR(RRTILE5056), 0, RRTILE5056__STATICRR }, + { "RRTILE5057", DVPTR(RRTILE5057), 0, RRTILE5057__STATICRR }, + { "RRTILE5058", DVPTR(RRTILE5058), 0, RRTILE5058__STATICRR }, + { "RRTILE5059", DVPTR(RRTILE5059), 0, RRTILE5059__STATICRR }, + { "RRTILE5061", DVPTR(RRTILE5061), 0, RRTILE5061__STATICRR }, + { "RRTILE5062", DVPTR(RRTILE5062), 0, RRTILE5062__STATICRR }, + { "RRTILE5063", DVPTR(RRTILE5063), 0, RRTILE5063__STATICRR }, + { "RRTILE5064", DVPTR(RRTILE5064), 0, RRTILE5064__STATICRR }, + { "RRTILE5065", DVPTR(RRTILE5065), 0, RRTILE5065__STATICRR }, + { "RRTILE5066", DVPTR(RRTILE5066), 0, RRTILE5066__STATICRR }, + { "RRTILE5067", DVPTR(RRTILE5067), 0, RRTILE5067__STATICRR }, + { "RRTILE5068", DVPTR(RRTILE5068), 0, RRTILE5068__STATICRR }, + { "RRTILE5069", DVPTR(RRTILE5069), 0, RRTILE5069__STATICRR }, + { "RRTILE5070", DVPTR(RRTILE5070), 0, RRTILE5070__STATICRR }, + { "RRTILE5071", DVPTR(RRTILE5071), 0, RRTILE5071__STATICRR }, + { "RRTILE5072", DVPTR(RRTILE5072), 0, RRTILE5072__STATICRR }, + { "RRTILE5073", DVPTR(RRTILE5073), 0, RRTILE5073__STATICRR }, + { "RRTILE5074", DVPTR(RRTILE5074), 0, RRTILE5074__STATICRR }, + { "RRTILE5075", DVPTR(RRTILE5075), 0, RRTILE5075__STATICRR }, + { "RRTILE5076", DVPTR(RRTILE5076), 0, RRTILE5076__STATICRR }, + { "RRTILE5077", DVPTR(RRTILE5077), 0, RRTILE5077__STATICRR }, + { "RRTILE5078", DVPTR(RRTILE5078), 0, RRTILE5078__STATICRR }, + { "RRTILE5079", DVPTR(RRTILE5079), 0, RRTILE5079__STATICRR }, + { "RRTILE5080", DVPTR(RRTILE5080), 0, RRTILE5080__STATICRR }, + { "RRTILE5081", DVPTR(RRTILE5081), 0, RRTILE5081__STATICRR }, + { "RRTILE5082", DVPTR(RRTILE5082), 0, RRTILE5082__STATICRR }, + { "RRTILE5083", DVPTR(RRTILE5083), 0, RRTILE5083__STATICRR }, + { "RRTILE5084", DVPTR(RRTILE5084), 0, RRTILE5084__STATICRR }, + { "RRTILE5085", DVPTR(RRTILE5085), 0, RRTILE5085__STATICRR }, + { "RRTILE5086", DVPTR(RRTILE5086), 0, RRTILE5086__STATICRR }, + { "RRTILE5087", DVPTR(RRTILE5087), 0, RRTILE5087__STATICRR }, + { "RRTILE5088", DVPTR(RRTILE5088), 0, RRTILE5088__STATICRR }, + { "RRTILE5090", DVPTR(RRTILE5090), 0, RRTILE5090__STATICRR }, + { "RRTILE6144", DVPTR(RRTILE6144), 0, RRTILE6144__STATICRR }, + { "RRTILE7010", DVPTR(RRTILE7110), 0, RRTILE7110__STATICRR }, + { "RRTILE7011", DVPTR(RRTILE7111), 0, RRTILE7111__STATICRR }, + { "RRTILE7012", DVPTR(RRTILE7112), 0, RRTILE7112__STATICRR }, + { "RRTILE7013", DVPTR(RRTILE7113), 0, RRTILE7113__STATICRR }, + { "MOTOGUN", DVPTR(MOTOGUN), 0, MOTOGUN__STATICRR }, + { "RRTILE7169", DVPTR(RRTILE7169), 0, RRTILE7169__STATICRR }, + { "MOTOHIT", DVPTR(MOTOHIT), 0, MOTOHIT__STATICRR }, + { "BOATHIT", DVPTR(BOATHIT), 0, BOATHIT__STATICRR }, + { "RRTILE7184", DVPTR(RRTILE7184), 0, RRTILE7184__STATICRR }, + { "RRTILE7190", DVPTR(RRTILE7190), 0, RRTILE7190__STATICRR }, + { "RRTILE7191", DVPTR(RRTILE7191), 0, RRTILE7191__STATICRR }, + { "RRTILE7213", DVPTR(RRTILE7213), 0, RRTILE7213__STATICRR }, + { "RRTILE7219", DVPTR(RRTILE7219), 0, RRTILE7219__STATICRR }, + { "EMPTYBIKE", DVPTR(EMPTYBIKE), 0, EMPTYBIKE__STATICRR }, + { "EMPTYBOAT", DVPTR(EMPTYBOAT), 0, EMPTYBOAT__STATICRR }, + { "RRTILE7424", DVPTR(RRTILE7424), 0, RRTILE7424__STATICRR }, + { "RRTILE7430", DVPTR(RRTILE7430), 0, RRTILE7430__STATICRR }, + { "RRTILE7433", DVPTR(RRTILE7433), 0, RRTILE7433__STATICRR }, + { "RRTILE7441", DVPTR(RRTILE7441), 0, RRTILE7441__STATICRR }, + { "RRTILE7547", DVPTR(RRTILE7547), 0, RRTILE7547__STATICRR }, + { "RRTILE7467", DVPTR(RRTILE7467), 0, RRTILE7467__STATICRR }, + { "RRTILE7469", DVPTR(RRTILE7469), 0, RRTILE7469__STATICRR }, + { "RRTILE7470", DVPTR(RRTILE7470), 0, RRTILE7470__STATICRR }, + { "RRTILE7475", DVPTR(RRTILE7475), 0, RRTILE7475__STATICRR }, + { "RRTILE7478", DVPTR(RRTILE7478), 0, RRTILE7478__STATICRR }, + { "RRTILE7505", DVPTR(RRTILE7505), 0, RRTILE7505__STATICRR }, + { "RRTILE7506", DVPTR(RRTILE7506), 0, RRTILE7506__STATICRR }, + { "RRTILE7534", DVPTR(RRTILE7534), 0, RRTILE7534__STATICRR }, + { "RRTILE7540", DVPTR(RRTILE7540), 0, RRTILE7540__STATICRR }, + { "RRTILE7533", DVPTR(RRTILE7533), 0, RRTILE7533__STATICRR }, + { "RRTILE7545", DVPTR(RRTILE7545), 0, RRTILE7545__STATICRR }, + { "RRTILE7552", DVPTR(RRTILE7552), 0, RRTILE7552__STATICRR }, + { "RRTILE7553", DVPTR(RRTILE7553), 0, RRTILE7553__STATICRR }, + { "RRTILE7554", DVPTR(RRTILE7554), 0, RRTILE7554__STATICRR }, + { "RRTILE7555", DVPTR(RRTILE7555), 0, RRTILE7555__STATICRR }, + { "RRTILE7557", DVPTR(RRTILE7557), 0, RRTILE7557__STATICRR }, + { "RRTILE7558", DVPTR(RRTILE7558), 0, RRTILE7558__STATICRR }, + { "RRTILE7559", DVPTR(RRTILE7559), 0, RRTILE7559__STATICRR }, + { "RRTILE7561", DVPTR(RRTILE7561), 0, RRTILE7561__STATICRR }, + { "RRTILE7566", DVPTR(RRTILE7566), 0, RRTILE7566__STATICRR }, + { "RRTILE7568", DVPTR(RRTILE7568), 0, RRTILE7568__STATICRR }, + { "RRTILE7574", DVPTR(RRTILE7574), 0, RRTILE7574__STATICRR }, + { "RRTILE7575", DVPTR(RRTILE7575), 0, RRTILE7575__STATICRR }, + { "RRTILE7576", DVPTR(RRTILE7576), 0, RRTILE7576__STATICRR }, + { "RRTILE7578", DVPTR(RRTILE7578), 0, RRTILE7578__STATICRR }, + { "RRTILE7579", DVPTR(RRTILE7579), 0, RRTILE7579__STATICRR }, + { "RRTILE7580", DVPTR(RRTILE7580), 0, RRTILE7580__STATICRR }, + { "RRTILE7595", DVPTR(RRTILE7595), 0, RRTILE7595__STATICRR }, + { "RRTILE7629", DVPTR(RRTILE7629), 0, RRTILE7629__STATICRR }, + { "RRTILE7636", DVPTR(RRTILE7636), 0, RRTILE7636__STATICRR }, + { "RRTILE7638", DVPTR(RRTILE7638), 0, RRTILE7638__STATICRR }, + { "RRTILE7640", DVPTR(RRTILE7640), 0, RRTILE7640__STATICRR }, + { "RRTILE7644", DVPTR(RRTILE7644), 0, RRTILE7644__STATICRR }, + { "RRTILE7646", DVPTR(RRTILE7646), 0, RRTILE7646__STATICRR }, + { "RRTILE7648", DVPTR(RRTILE7648), 0, RRTILE7648__STATICRR }, + { "RRTILE7650", DVPTR(RRTILE7650), 0, RRTILE7650__STATICRR }, + { "RRTILE7653", DVPTR(RRTILE7653), 0, RRTILE7653__STATICRR }, + { "RRTILE7655", DVPTR(RRTILE7655), 0, RRTILE7655__STATICRR }, + { "RRTILE7657", DVPTR(RRTILE7657), 0, RRTILE7657__STATICRR }, + { "RRTILE7659", DVPTR(RRTILE7659), 0, RRTILE7659__STATICRR }, + { "RRTILE7691", DVPTR(RRTILE7691), 0, RRTILE7691__STATICRR }, + { "RRTILE7694", DVPTR(RRTILE7694), 0, RRTILE7694__STATICRR }, + { "RRTILE7696", DVPTR(RRTILE7696), 0, RRTILE7696__STATICRR }, + { "RRTILE7697", DVPTR(RRTILE7697), 0, RRTILE7697__STATICRR }, + { "RRTILE7700", DVPTR(RRTILE7700), 0, RRTILE7700__STATICRR }, + { "RRTILE7702", DVPTR(RRTILE7702), 0, RRTILE7702__STATICRR }, + { "RRTILE7704", DVPTR(RRTILE7704), 0, RRTILE7704__STATICRR }, + { "RRTILE7705", DVPTR(RRTILE7705), 0, RRTILE7705__STATICRR }, + { "RRTILE7711", DVPTR(RRTILE7711), 0, RRTILE7711__STATICRR }, + { "RRTILE7716", DVPTR(RRTILE7716), 0, RRTILE7716__STATICRR }, + { "RRTILE7756", DVPTR(RRTILE7756), 0, RRTILE7756__STATICRR }, + { "RRTILE7768", DVPTR(RRTILE7768), 0, RRTILE7768__STATICRR }, + { "RRTILE7806", DVPTR(RRTILE7806), 0, RRTILE7806__STATICRR }, + { "RRTILE7820", DVPTR(RRTILE7820), 0, RRTILE7820__STATICRR }, + { "RRTILE7859", DVPTR(RRTILE7859), 0, RRTILE7859__STATICRR }, + { "RRTILE7870", DVPTR(RRTILE7870), 0, RRTILE7870__STATICRR }, + { "RRTILE7873", DVPTR(RRTILE7873), 0, RRTILE7873__STATICRR }, + { "RRTILE7875", DVPTR(RRTILE7875), 0, RRTILE7875__STATICRR }, + { "RRTILE7876", DVPTR(RRTILE7876), 0, RRTILE7876__STATICRR }, + { "RRTILE7879", DVPTR(RRTILE7879), 0, RRTILE7879__STATICRR }, + { "RRTILE7881", DVPTR(RRTILE7881), 0, RRTILE7881__STATICRR }, + { "RRTILE7883", DVPTR(RRTILE7883), 0, RRTILE7883__STATICRR }, + { "RRTILE7885", DVPTR(RRTILE7885), 0, RRTILE7885__STATICRR }, + { "RRTILE7886", DVPTR(RRTILE7886), 0, RRTILE7886__STATICRR }, + { "RRTILE7887", DVPTR(RRTILE7887), 0, RRTILE7887__STATICRR }, + { "RRTILE7888", DVPTR(RRTILE7888), 0, RRTILE7888__STATICRR }, + { "RRTILE7889", DVPTR(RRTILE7889), 0, RRTILE7889__STATICRR }, + { "RRTILE7890", DVPTR(RRTILE7890), 0, RRTILE7890__STATICRR }, + { "RRTILE7900", DVPTR(RRTILE7900), 0, RRTILE7900__STATICRR }, + { "RRTILE7901", DVPTR(RRTILE7901), 0, RRTILE7901__STATICRR }, + { "RRTILE7906", DVPTR(RRTILE7906), 0, RRTILE7906__STATICRR }, + { "RRTILE7912", DVPTR(RRTILE7912), 0, RRTILE7912__STATICRR }, + { "RRTILE7913", DVPTR(RRTILE7913), 0, RRTILE7913__STATICRR }, + { "RRTILE7936", DVPTR(RRTILE7936), 0, RRTILE7936__STATICRR }, + { "RRTILE8047", DVPTR(RRTILE8047), 0, RRTILE8047__STATICRR }, + { "MULTISWITCH2", DVPTR(MULTISWITCH2), 0, MULTISWITCH2__STATICRR }, + { "RRTILE8059", DVPTR(RRTILE8059), 0, RRTILE8059__STATICRR }, + { "RRTILE8060", DVPTR(RRTILE8060), 0, RRTILE8060__STATICRR }, + { "RRTILE8063", DVPTR(RRTILE8063), 0, RRTILE8063__STATICRR }, + { "RRTILE8067", DVPTR(RRTILE8067), 0, RRTILE8067__STATICRR }, + { "RRTILE8076", DVPTR(RRTILE8076), 0, RRTILE8076__STATICRR }, + { "RRTILE8094", DVPTR(RRTILE8094), 0, RRTILE8094__STATICRR }, + { "RRTILE8096", DVPTR(RRTILE8096), 0, RRTILE8096__STATICRR }, + { "RRTILE8099", DVPTR(RRTILE8099), 0, RRTILE8099__STATICRR }, + { "RRTILE8106", DVPTR(RRTILE8106), 0, RRTILE8106__STATICRR }, + { "RRTILE8162", DVPTR(RRTILE8162), 0, RRTILE8162__STATICRR }, + { "RRTILE8163", DVPTR(RRTILE8163), 0, RRTILE8163__STATICRR }, + { "RRTILE8164", DVPTR(RRTILE8164), 0, RRTILE8164__STATICRR }, + { "RRTILE8165", DVPTR(RRTILE8165), 0, RRTILE8165__STATICRR }, + { "RRTILE8166", DVPTR(RRTILE8166), 0, RRTILE8166__STATICRR }, + { "RRTILE8167", DVPTR(RRTILE8167), 0, RRTILE8167__STATICRR }, + { "RRTILE8168", DVPTR(RRTILE8168), 0, RRTILE8168__STATICRR }, + { "RRTILE8192", DVPTR(RRTILE8192), 0, RRTILE8192__STATICRR }, + { "RRTILE8193", DVPTR(RRTILE8193), 0, RRTILE8193__STATICRR }, + { "RRTILE8215", DVPTR(RRTILE8215), 0, RRTILE8215__STATICRR }, + { "RRTILE8216", DVPTR(RRTILE8216), 0, RRTILE8216__STATICRR }, + { "RRTILE8217", DVPTR(RRTILE8217), 0, RRTILE8217__STATICRR }, + { "RRTILE8218", DVPTR(RRTILE8218), 0, RRTILE8218__STATICRR }, + { "RRTILE8220", DVPTR(RRTILE8220), 0, RRTILE8220__STATICRR }, + { "RRTILE8221", DVPTR(RRTILE8221), 0, RRTILE8221__STATICRR }, + { "RRTILE8222", DVPTR(RRTILE8222), 0, RRTILE8222__STATICRR }, + { "RRTILE8223", DVPTR(RRTILE8223), 0, RRTILE8223__STATICRR }, + { "RRTILE8224", DVPTR(RRTILE8224), 0, RRTILE8224__STATICRR }, + { "RRTILE8227", DVPTR(RRTILE8227), 0, RRTILE8227__STATICRR }, + { "RRTILE8312", DVPTR(RRTILE8312), 0, RRTILE8312__STATICRR }, + { "RRTILE8370", DVPTR(RRTILE8370), 0, RRTILE8370__STATICRR }, + { "RRTILE8371", DVPTR(RRTILE8371), 0, RRTILE8371__STATICRR }, + { "RRTILE8372", DVPTR(RRTILE8372), 0, RRTILE8372__STATICRR }, + { "RRTILE8373", DVPTR(RRTILE8373), 0, RRTILE8373__STATICRR }, + { "RRTILE8379", DVPTR(RRTILE8379), 0, RRTILE8379__STATICRR }, + { "RRTILE8380", DVPTR(RRTILE8380), 0, RRTILE8380__STATICRR }, + { "RRTILE8385", DVPTR(RRTILE8385), 0, RRTILE8385__STATICRR }, + { "RRTILE8386", DVPTR(RRTILE8386), 0, RRTILE8386__STATICRR }, + { "RRTILE8387", DVPTR(RRTILE8387), 0, RRTILE8387__STATICRR }, + { "RRTILE8388", DVPTR(RRTILE8388), 0, RRTILE8388__STATICRR }, + { "RRTILE8389", DVPTR(RRTILE8389), 0, RRTILE8389__STATICRR }, + { "RRTILE8390", DVPTR(RRTILE8390), 0, RRTILE8390__STATICRR }, + { "RRTILE8391", DVPTR(RRTILE8391), 0, RRTILE8391__STATICRR }, + { "RRTILE8392", DVPTR(RRTILE8392), 0, RRTILE8392__STATICRR }, + { "RRTILE8394", DVPTR(RRTILE8394), 0, RRTILE8394__STATICRR }, + { "RRTILE8395", DVPTR(RRTILE8395), 0, RRTILE8395__STATICRR }, + { "RRTILE8396", DVPTR(RRTILE8396), 0, RRTILE8396__STATICRR }, + { "RRTILE8397", DVPTR(RRTILE8397), 0, RRTILE8397__STATICRR }, + { "RRTILE8398", DVPTR(RRTILE8398), 0, RRTILE8398__STATICRR }, + { "RRTILE8399", DVPTR(RRTILE8399), 0, RRTILE8399__STATICRR }, + { "RRTILE8423", DVPTR(RRTILE8423), 0, RRTILE8423__STATICRR }, + { "RRTILE8448", DVPTR(RRTILE8448), 0, RRTILE8448__STATICRR }, + { "RRTILE8450", DVPTR(RRTILE8450), 0, RRTILE8450__STATICRR }, + { "BOATAMMO", DVPTR(BOATAMMO), 0, BOATAMMO__STATICRR }, + { "RRTILE8461", DVPTR(RRTILE8461), 0, RRTILE8461__STATICRR }, + { "RRTILE8462", DVPTR(RRTILE8462), 0, RRTILE8462__STATICRR }, + { "RRTILE8464", DVPTR(RRTILE8464), 0, RRTILE8464__STATICRR }, + { "RRTILE8475", DVPTR(RRTILE8475), 0, RRTILE8475__STATICRR }, + { "RRTILE8487", DVPTR(RRTILE8487), 0, RRTILE8487__STATICRR }, + { "RRTILE8488", DVPTR(RRTILE8488), 0, RRTILE8488__STATICRR }, + { "RRTILE8489", DVPTR(RRTILE8489), 0, RRTILE8489__STATICRR }, + { "RRTILE8490", DVPTR(RRTILE8490), 0, RRTILE8490__STATICRR }, + { "RRTILE8496", DVPTR(RRTILE8496), 0, RRTILE8496__STATICRR }, + { "RRTILE8497", DVPTR(RRTILE8497), 0, RRTILE8497__STATICRR }, + { "RRTILE8498", DVPTR(RRTILE8498), 0, RRTILE8498__STATICRR }, + { "RRTILE8499", DVPTR(RRTILE8499), 0, RRTILE8499__STATICRR }, + { "RRTILE8503", DVPTR(RRTILE8503), 0, RRTILE8503__STATICRR }, + { "RRTILE8525", DVPTR(RRTILE8525), 0, RRTILE8525__STATICRR }, + { "RRTILE8537", DVPTR(RRTILE8537), 0, RRTILE8537__STATICRR }, + { "RRTILE8565", DVPTR(RRTILE8565), 0, RRTILE8565__STATICRR }, + { "RRTILE8567", DVPTR(RRTILE8567), 0, RRTILE8567__STATICRR }, + { "RRTILE8568", DVPTR(RRTILE8568), 0, RRTILE8568__STATICRR }, + { "RRTILE8569", DVPTR(RRTILE8569), 0, RRTILE8569__STATICRR }, + { "RRTILE8570", DVPTR(RRTILE8570), 0, RRTILE8570__STATICRR }, + { "RRTILE8571", DVPTR(RRTILE8571), 0, RRTILE8571__STATICRR }, + { "RRTILE8579", DVPTR(RRTILE8579), 0, RRTILE8579__STATICRR }, + { "RRTILE8588", DVPTR(RRTILE8588), 0, RRTILE8588__STATICRR }, + { "RRTILE8589", DVPTR(RRTILE8589), 0, RRTILE8589__STATICRR }, + { "RRTILE8590", DVPTR(RRTILE8590), 0, RRTILE8590__STATICRR }, + { "RRTILE8591", DVPTR(RRTILE8591), 0, RRTILE8591__STATICRR }, + { "RRTILE8592", DVPTR(RRTILE8592), 0, RRTILE8592__STATICRR }, + { "RRTILE8593", DVPTR(RRTILE8593), 0, RRTILE8593__STATICRR }, + { "RRTILE8594", DVPTR(RRTILE8594), 0, RRTILE8594__STATICRR }, + { "RRTILE8595", DVPTR(RRTILE8595), 0, RRTILE8595__STATICRR }, + { "RRTILE8596", DVPTR(RRTILE8596), 0, RRTILE8596__STATICRR }, + { "RRTILE8598", DVPTR(RRTILE8598), 0, RRTILE8598__STATICRR }, + { "RRTILE8605", DVPTR(RRTILE8605), 0, RRTILE8605__STATICRR }, + { "RRTILE8608", DVPTR(RRTILE8608), 0, RRTILE8608__STATICRR }, + { "RRTILE8609", DVPTR(RRTILE8609), 0, RRTILE8609__STATICRR }, + { "RRTILE8611", DVPTR(RRTILE8611), 0, RRTILE8611__STATICRR }, + { "RRTILE8617", DVPTR(RRTILE8617), 0, RRTILE8617__STATICRR }, + { "RRTILE8618", DVPTR(RRTILE8618), 0, RRTILE8618__STATICRR }, + { "RRTILE8620", DVPTR(RRTILE8620), 0, RRTILE8620__STATICRR }, + { "RRTILE8621", DVPTR(RRTILE8621), 0, RRTILE8621__STATICRR }, + { "RRTILE8622", DVPTR(RRTILE8622), 0, RRTILE8622__STATICRR }, + { "RRTILE8623", DVPTR(RRTILE8623), 0, RRTILE8623__STATICRR }, + { "RRTILE8624", DVPTR(RRTILE8624), 0, RRTILE8624__STATICRR }, + { "RRTILE8640", DVPTR(RRTILE8640), 0, RRTILE8640__STATICRR }, + { "RRTILE8651", DVPTR(RRTILE8651), 0, RRTILE8651__STATICRR }, + { "RRTILE8660", DVPTR(RRTILE8660), 0, RRTILE8660__STATICRR }, + { "RRTILE8677", DVPTR(RRTILE8677), 0, RRTILE8677__STATICRR }, + { "RRTILE8679", DVPTR(RRTILE8679), 0, RRTILE8679__STATICRR }, + { "RRTILE8680", DVPTR(RRTILE8680), 0, RRTILE8680__STATICRR }, + { "RRTILE8681", DVPTR(RRTILE8681), 0, RRTILE8681__STATICRR }, + { "RRTILE8682", DVPTR(RRTILE8682), 0, RRTILE8682__STATICRR }, + { "RRTILE8683", DVPTR(RRTILE8683), 0, RRTILE8683__STATICRR }, + { "RRTILE8704", DVPTR(RRTILE8704), 0, RRTILE8704__STATICRR }, + { "BOULDER", DVPTR(BOULDER), 0, BOULDER__STATICRR }, + { "BOULDER1", DVPTR(BOULDER1), 0, BOULDER1__STATICRR }, + { "TORNADO", DVPTR(TORNADO), 0, TORNADO__STATICRR }, + { "CHEERBOMB", DVPTR(CHEERBOMB), 0, CHEERBOMB__STATICRR }, + { "CHEERBLADE", DVPTR(CHEERBLADE), 0, CHEERBLADE__STATICRR }, + { "DOGATTACK", DVPTR(DOGATTACK), 0, DOGATTACK__STATICRR }, + { "BILLYWALK", DVPTR(BILLYWALK), 0, BILLYWALK__STATICRR }, + { "BILLYDIE", DVPTR(BILLYDIE), 0, BILLYDIE__STATICRR }, + { "BILLYCOCK", DVPTR(BILLYCOCK), 0, BILLYCOCK__STATICRR }, + { "BILLYRAY", DVPTR(BILLYRAY), 0, BILLYRAY__STATICRR }, + { "BILLYRAYSTAYPUT", DVPTR(BILLYRAYSTAYPUT), 0, BILLYRAYSTAYPUT__STATICRR }, + { "BILLYBUT", DVPTR(BILLYBUT), 0, BILLYBUT__STATICRR }, + { "BILLYSCRATCH", DVPTR(BILLYSCRATCH), 0, BILLYSCRATCH__STATICRR }, + { "BILLYSNIFF", DVPTR(BILLYSNIFF), 0, BILLYSNIFF__STATICRR }, + { "BILLYWOUND", DVPTR(BILLYWOUND), 0, BILLYWOUND__STATICRR }, + { "BILLYGORE", DVPTR(BILLYGORE), 0, BILLYGORE__STATICRR }, + { "BILLYJIBA", DVPTR(BILLYJIBA), 0, BILLYJIBA__STATICRR }, + { "BILLYJIBB", DVPTR(BILLYJIBB), 0, BILLYJIBB__STATICRR }, + { "BRAYSNIPER", DVPTR(BRAYSNIPER), 0, BRAYSNIPER__STATICRR }, + { "DOGRUN", DVPTR(DOGRUN), 0, DOGRUN__STATICRR }, + { "DOGDIE", DVPTR(DOGDIE), 0, DOGDIE__STATICRR }, + { "DOGDEAD", DVPTR(DOGDEAD), 0, DOGDEAD__STATICRR }, + { "DOGBARK", DVPTR(DOGBARK), 0, DOGBARK__STATICRR }, + { "LTH", DVPTR(LTH), 0, LTH__STATICRR }, + { "LTHSTRAFE", DVPTR(LTHSTRAFE), 0, LTHSTRAFE__STATICRR }, + { "HULKHANG", DVPTR(HULKHANG), 0, HULKHANG__STATICRR }, + { "HULKHANGDEAD", DVPTR(HULKHANGDEAD), 0, HULKHANGDEAD__STATICRR }, + { "HULKJUMP", DVPTR(HULKJUMP), 0, HULKJUMP__STATICRR }, + { "LTHLOAD", DVPTR(LTHLOAD), 0, LTHLOAD__STATICRR }, + { "LTHDIE", DVPTR(LTHDIE), 0, LTHDIE__STATICRR }, + { "BUBBASCRATCH", DVPTR(BUBBASCRATCH), 0, BUBBASCRATCH__STATICRR }, + { "BUBBANOSE", DVPTR(BUBBANOSE), 0, BUBBANOSE__STATICRR }, + { "BUBBAPISS", DVPTR(BUBBAPISS), 0, BUBBAPISS__STATICRR }, + { "BUBBASTAND", DVPTR(BUBBASTAND), 0, BUBBASTAND__STATICRR }, + { "BUBBAOUCH", DVPTR(BUBBAOUCH), 0, BUBBAOUCH__STATICRR }, + { "BUBBADIE", DVPTR(BUBBADIE), 0, BUBBADIE__STATICRR }, + { "BUBBADEAD", DVPTR(BUBBADEAD), 0, BUBBADEAD__STATICRR }, + { "HULK", DVPTR(HULK), 0, HULK__STATICRR }, + { "HULKSTAYPUT", DVPTR(HULKSTAYPUT), 0, HULKSTAYPUT__STATICRR }, + { "HULKA", DVPTR(HULKA), 0, HULKA__STATICRR }, + { "HULKB", DVPTR(HULKB), 0, HULKB__STATICRR }, + { "HULKC", DVPTR(HULKC), 0, HULKC__STATICRR }, + { "HULKJIBA", DVPTR(HULKJIBA), 0, HULKJIBA__STATICRR }, + { "HULKJIBB", DVPTR(HULKJIBB), 0, HULKJIBB__STATICRR }, + { "HULKJIBC", DVPTR(HULKJIBC), 0, HULKJIBC__STATICRR }, + { "SBSWIPE", DVPTR(SBSWIPE), 0, SBSWIPE__STATICRR }, + { "SBPAIN", DVPTR(SBPAIN), 0, SBPAIN__STATICRR }, + { "SBDIE", DVPTR(SBDIE), 0, SBDIE__STATICRR }, + { "HEN", DVPTR(HEN), 0, HEN__STATICRR }, + { "HENSTAYPUT", DVPTR(HENSTAYPUT), 0, HENSTAYPUT__STATICRR }, + { "HENSTAND", DVPTR(HENSTAND), 0, HENSTAND__STATICRR }, + { "PIG", DVPTR(PIG), 0, PIG__STATICRR }, + { "PIGSTAYPUT", DVPTR(PIGSTAYPUT), 0, PIGSTAYPUT__STATICRR }, + { "PIGEAT", DVPTR(PIGEAT), 0, PIGEAT__STATICRR }, + { "SBMOVE", DVPTR(SBMOVE), 0, SBMOVE__STATICRR }, + { "SBSPIT", DVPTR(SBSPIT), 0, SBSPIT__STATICRR }, + { "SBDIP", DVPTR(SBDIP), 0, SBDIP__STATICRR }, + { "MINION", DVPTR(MINION), 0, MINION__STATICRR }, + { "MINIONSTAYPUT", DVPTR(MINIONSTAYPUT), 0, MINIONSTAYPUT__STATICRR }, + { "UFO1", DVPTR(UFO1), 0, UFO1__STATICRR }, + { "UFO2", DVPTR(UFO2), 0, UFO2__STATICRR }, + { "UFO3", DVPTR(UFO3), 0, UFO3__STATICRR }, + { "UFO4", DVPTR(UFO4), 0, UFO4__STATICRR }, + { "UFO5", DVPTR(UFO5), 0, UFO5__STATICRR }, + { "MINJIBA", DVPTR(MINJIBA), 0, MINJIBA__STATICRR }, + { "MINJIBB", DVPTR(MINJIBB), 0, MINJIBB__STATICRR }, + { "MINJIBC", DVPTR(MINJIBC), 0, MINJIBC__STATICRR }, + { "COW", DVPTR(COW), 0, COW__STATICRR }, + { "COOT", DVPTR(COOT), 0, COOT__STATICRR }, + { "COOTSTAYPUT", DVPTR(COOTSTAYPUT), 0, COOTSTAYPUT__STATICRR }, + { "COOTSHOOT", DVPTR(COOTSHOOT), 0, COOTSHOOT__STATICRR }, + { "COOTDIE", DVPTR(COOTDIE), 0, COOTDIE__STATICRR }, + { "COOTDUCK", DVPTR(COOTDUCK), 0, COOTDUCK__STATICRR }, + { "COOTPAIN", DVPTR(COOTPAIN), 0, COOTPAIN__STATICRR }, + { "COOTTRANS", DVPTR(COOTTRANS), 0, COOTTRANS__STATICRR }, + { "COOTGETUP", DVPTR(COOTGETUP), 0, COOTGETUP__STATICRR }, + { "COOTJIBA", DVPTR(COOTJIBA), 0, COOTJIBA__STATICRR }, + { "COOTJIBB", DVPTR(COOTJIBB), 0, COOTJIBB__STATICRR }, + { "COOTJIBC", DVPTR(COOTJIBC), 0, COOTJIBC__STATICRR }, + { "VIXEN", DVPTR(VIXEN), 0, VIXEN__STATICRR }, + { "VIXENPAIN", DVPTR(VIXENPAIN), 0, VIXENPAIN__STATICRR }, + { "VIXENDIE", DVPTR(VIXENDIE), 0, VIXENDIE__STATICRR }, + { "VIXENSHOOT", DVPTR(VIXENSHOOT), 0, VIXENSHOOT__STATICRR }, + { "VIXENWDN", DVPTR(VIXENWDN), 0, VIXENWDN__STATICRR }, + { "VIXENWUP", DVPTR(VIXENWUP), 0, VIXENWUP__STATICRR }, + { "VIXENKICK", DVPTR(VIXENKICK), 0, VIXENKICK__STATICRR }, + { "VIXENTELE", DVPTR(VIXENTELE), 0, VIXENTELE__STATICRR }, + { "VIXENTEAT", DVPTR(VIXENTEAT), 0, VIXENTEAT__STATICRR }, + { "BIKEJIBA", DVPTR(BIKEJIBA), 0, BIKEJIBA__STATICRR }, + { "BIKEJIBB", DVPTR(BIKEJIBB), 0, BIKEJIBB__STATICRR }, + { "BIKEJIBC", DVPTR(BIKEJIBC), 0, BIKEJIBC__STATICRR }, + { "BIKERB", DVPTR(BIKERB), 0, BIKERB__STATICRR }, + { "BIKERBV2", DVPTR(BIKERBV2), 0, BIKERBV2__STATICRR }, + { "BIKER", DVPTR(BIKER), 0, BIKER__STATICRR }, + { "BIKERJIBA", DVPTR(BIKERJIBA), 0, BIKERJIBA__STATICRR }, + { "BIKERJIBB", DVPTR(BIKERJIBB), 0, BIKERJIBB__STATICRR }, + { "BIKERJIBC", DVPTR(BIKERJIBC), 0, BIKERJIBC__STATICRR }, + { "BIKERJIBD", DVPTR(BIKERJIBD), 0, BIKERJIBD__STATICRR }, + { "MAKEOUT", DVPTR(MAKEOUT), 0, MAKEOUT__STATICRR }, + { "CHEERB", DVPTR(CHEERB), 0, CHEERB__STATICRR }, + { "CHEER", DVPTR(CHEER), 0, CHEER__STATICRR }, + { "CHEERSTAYPUT", DVPTR(CHEERSTAYPUT), 0, CHEERSTAYPUT__STATICRR }, + { "CHEERJIBA", DVPTR(CHEERJIBA), 0, CHEERJIBA__STATICRR }, + { "CHEERJIBB", DVPTR(CHEERJIBB), 0, CHEERJIBB__STATICRR }, + { "CHEERJIBC", DVPTR(CHEERJIBC), 0, CHEERJIBC__STATICRR }, + { "CHEERJIBD", DVPTR(CHEERJIBD), 0, CHEERJIBD__STATICRR }, + { "FBOATJIBA", DVPTR(FBOATJIBA), 0, FBOATJIBA__STATICRR }, + { "FBOATJIBB", DVPTR(FBOATJIBB), 0, FBOATJIBB__STATICRR }, + { "COOTPLAY", DVPTR(COOTPLAY), 0, COOTPLAY__STATICRR }, + { "BILLYPLAY", DVPTR(BILLYPLAY), 0, BILLYPLAY__STATICRR }, + { "MINIONBOAT", DVPTR(MINIONBOAT), 0, MINIONBOAT__STATICRR }, + { "HULKBOAT", DVPTR(HULKBOAT), 0, HULKBOAT__STATICRR }, + { "CHEERBOAT", DVPTR(CHEERBOAT), 0, CHEERBOAT__STATICRR }, + { "RRTILE7274", DVPTR(RRTILE7274), 0, RRTILE7274__STATICRR }, + { "RABBIT", DVPTR(RABBIT), 0, RABBIT__STATICRR }, + { "RABBITJIBA", DVPTR(RABBITJIBA), 0, RABBITJIBA__STATICRR }, + { "RABBITJIBB", DVPTR(RABBITJIBB), 0, RABBITJIBB__STATICRR }, + { "RABBITJIBC", DVPTR(RABBITJIBC), 0, RABBITJIBC__STATICRR }, + { "ROCK", DVPTR(ROCK), 0, ROCK__STATICRR }, + { "ROCK2", DVPTR(ROCK2), 0, ROCK2__STATICRR }, + { "MAMACLOUD", DVPTR(MAMACLOUD), 0, MAMACLOUD__STATICRR }, + { "MAMA", DVPTR(MAMA), 0, MAMA__STATICRR }, + { "MAMAJIBA", DVPTR(MAMAJIBA), 0, MAMAJIBA__STATICRR }, + { "MAMAJIBB", DVPTR(MAMAJIBB), 0, MAMAJIBB__STATICRR }, + { NULL, NULL, -1, -1 }, +}; + +int32_t SECTOREFFECTOR = SECTOREFFECTOR__STATIC; +int32_t ACTIVATOR = ACTIVATOR__STATIC; +int32_t TOUCHPLATE = TOUCHPLATE__STATIC; +int32_t ACTIVATORLOCKED = ACTIVATORLOCKED__STATIC; +int32_t MUSICANDSFX = MUSICANDSFX__STATIC; +int32_t LOCATORS = LOCATORS__STATIC; +int32_t CYCLER = CYCLER__STATIC; +int32_t MASTERSWITCH = MASTERSWITCH__STATIC; +int32_t RESPAWN = RESPAWN__STATIC; +int32_t GPSPEED = GPSPEED__STATIC; +int32_t FOF = FOF__STATIC; +int32_t ARROW = ARROW__STATIC; +int32_t FIRSTGUNSPRITE = FIRSTGUNSPRITE__STATIC; +int32_t CHAINGUNSPRITE = CHAINGUNSPRITE__STATIC; +int32_t RPGSPRITE = RPGSPRITE__STATIC; +int32_t FREEZESPRITE = FREEZESPRITE__STATIC; +int32_t SHRINKERSPRITE = SHRINKERSPRITE__STATIC; +int32_t HEAVYHBOMB = HEAVYHBOMB__STATIC; +int32_t TRIPBOMBSPRITE = TRIPBOMBSPRITE__STATIC; +int32_t SHOTGUNSPRITE = SHOTGUNSPRITE__STATIC; +int32_t DEVISTATORSPRITE = DEVISTATORSPRITE__STATIC; +int32_t HEALTHBOX = HEALTHBOX__STATIC; +int32_t AMMOBOX = AMMOBOX__STATIC; +int32_t GROWSPRITEICON = GROWSPRITEICON__STATIC; +int32_t INVENTORYBOX = INVENTORYBOX__STATIC; +int32_t FREEZEAMMO = FREEZEAMMO__STATIC; +int32_t AMMO = AMMO__STATIC; +int32_t BATTERYAMMO = BATTERYAMMO__STATIC; +int32_t DEVISTATORAMMO = DEVISTATORAMMO__STATIC; +int32_t RPGAMMO = RPGAMMO__STATIC; +int32_t GROWAMMO = GROWAMMO__STATIC; +int32_t CRYSTALAMMO = CRYSTALAMMO__STATIC; +int32_t HBOMBAMMO = HBOMBAMMO__STATIC; +int32_t AMMOLOTS = AMMOLOTS__STATIC; +int32_t SHOTGUNAMMO = SHOTGUNAMMO__STATIC; +int32_t COLA = COLA__STATIC; +int32_t SIXPAK = SIXPAK__STATIC; +int32_t FIRSTAID = FIRSTAID__STATIC; +int32_t SHIELD = SHIELD__STATIC; +int32_t STEROIDS = STEROIDS__STATIC; +int32_t AIRTANK = AIRTANK__STATIC; +int32_t JETPACK = JETPACK__STATIC; +int32_t HEATSENSOR = HEATSENSOR__STATIC; +int32_t ACCESSCARD = ACCESSCARD__STATIC; +int32_t BOOTS = BOOTS__STATIC; +int32_t MIRRORBROKE = MIRRORBROKE__STATIC; +int32_t CLOUDYOCEAN = CLOUDYOCEAN__STATIC; +int32_t CLOUDYSKIES = CLOUDYSKIES__STATIC; +int32_t MOONSKY1 = MOONSKY1__STATIC; +int32_t MOONSKY2 = MOONSKY2__STATIC; +int32_t MOONSKY3 = MOONSKY3__STATIC; +int32_t MOONSKY4 = MOONSKY4__STATIC; +int32_t BIGORBIT1 = BIGORBIT1__STATIC; +int32_t BIGORBIT2 = BIGORBIT2__STATIC; +int32_t BIGORBIT3 = BIGORBIT3__STATIC; +int32_t BIGORBIT4 = BIGORBIT4__STATIC; +int32_t BIGORBIT5 = BIGORBIT5__STATIC; +int32_t LA = LA__STATIC; +int32_t REDSKY1 = REDSKY1__STATIC; +int32_t REDSKY2 = REDSKY2__STATIC; +int32_t ATOMICHEALTH = ATOMICHEALTH__STATIC; +int32_t TECHLIGHT2 = TECHLIGHT2__STATIC; +int32_t TECHLIGHTBUST2 = TECHLIGHTBUST2__STATIC; +int32_t TECHLIGHT4 = TECHLIGHT4__STATIC; +int32_t TECHLIGHTBUST4 = TECHLIGHTBUST4__STATIC; +int32_t WALLLIGHT4 = WALLLIGHT4__STATIC; +int32_t WALLLIGHTBUST4 = WALLLIGHTBUST4__STATIC; +int32_t ACCESSSWITCH = ACCESSSWITCH__STATIC; +int32_t SLOTDOOR = SLOTDOOR__STATIC; +int32_t LIGHTSWITCH = LIGHTSWITCH__STATIC; +int32_t SPACEDOORSWITCH = SPACEDOORSWITCH__STATIC; +int32_t SPACELIGHTSWITCH = SPACELIGHTSWITCH__STATIC; +int32_t FRANKENSTINESWITCH = FRANKENSTINESWITCH__STATIC; +int32_t NUKEBUTTON = NUKEBUTTON__STATIC; +int32_t MULTISWITCH = MULTISWITCH__STATIC; +int32_t DOORTILE5 = DOORTILE5__STATIC; +int32_t DOORTILE6 = DOORTILE6__STATIC; +int32_t DOORTILE1 = DOORTILE1__STATIC; +int32_t DOORTILE2 = DOORTILE2__STATIC; +int32_t DOORTILE3 = DOORTILE3__STATIC; +int32_t DOORTILE4 = DOORTILE4__STATIC; +int32_t DOORTILE7 = DOORTILE7__STATIC; +int32_t DOORTILE8 = DOORTILE8__STATIC; +int32_t DOORTILE9 = DOORTILE9__STATIC; +int32_t DOORTILE10 = DOORTILE10__STATIC; +int32_t DOORSHOCK = DOORSHOCK__STATIC; +int32_t DIPSWITCH = DIPSWITCH__STATIC; +int32_t DIPSWITCH2 = DIPSWITCH2__STATIC; +int32_t TECHSWITCH = TECHSWITCH__STATIC; +int32_t DIPSWITCH3 = DIPSWITCH3__STATIC; +int32_t ACCESSSWITCH2 = ACCESSSWITCH2__STATIC; +int32_t REFLECTWATERTILE = REFLECTWATERTILE__STATIC; +int32_t FLOORSLIME = FLOORSLIME__STATIC; +int32_t BIGFORCE = BIGFORCE__STATIC; +int32_t EPISODE = EPISODE__STATIC; +int32_t MASKWALL9 = MASKWALL9__STATIC; +int32_t W_LIGHT = W_LIGHT__STATIC; +int32_t SCREENBREAK1 = SCREENBREAK1__STATIC; +int32_t SCREENBREAK2 = SCREENBREAK2__STATIC; +int32_t SCREENBREAK3 = SCREENBREAK3__STATIC; +int32_t SCREENBREAK4 = SCREENBREAK4__STATIC; +int32_t SCREENBREAK5 = SCREENBREAK5__STATIC; +int32_t SCREENBREAK6 = SCREENBREAK6__STATIC; +int32_t SCREENBREAK7 = SCREENBREAK7__STATIC; +int32_t SCREENBREAK8 = SCREENBREAK8__STATIC; +int32_t SCREENBREAK9 = SCREENBREAK9__STATIC; +int32_t SCREENBREAK10 = SCREENBREAK10__STATIC; +int32_t SCREENBREAK11 = SCREENBREAK11__STATIC; +int32_t SCREENBREAK12 = SCREENBREAK12__STATIC; +int32_t SCREENBREAK13 = SCREENBREAK13__STATIC; +int32_t MASKWALL1 = MASKWALL1__STATIC; +int32_t W_TECHWALL1 = W_TECHWALL1__STATIC; +int32_t W_TECHWALL2 = W_TECHWALL2__STATIC; +int32_t W_TECHWALL15 = W_TECHWALL15__STATIC; +int32_t W_TECHWALL3 = W_TECHWALL3__STATIC; +int32_t W_TECHWALL4 = W_TECHWALL4__STATIC; +int32_t W_TECHWALL10 = W_TECHWALL10__STATIC; +int32_t W_TECHWALL16 = W_TECHWALL16__STATIC; +int32_t WATERTILE2 = WATERTILE2__STATIC; +int32_t BPANNEL1 = BPANNEL1__STATIC; +int32_t PANNEL1 = PANNEL1__STATIC; +int32_t PANNEL2 = PANNEL2__STATIC; +int32_t WATERTILE = WATERTILE__STATIC; +int32_t STATIC = STATIC__STATIC; +int32_t W_SCREENBREAK = W_SCREENBREAK__STATIC; +int32_t W_HITTECHWALL3 = W_HITTECHWALL3__STATIC; +int32_t W_HITTECHWALL4 = W_HITTECHWALL4__STATIC; +int32_t W_HITTECHWALL2 = W_HITTECHWALL2__STATIC; +int32_t W_HITTECHWALL1 = W_HITTECHWALL1__STATIC; +int32_t MASKWALL10 = MASKWALL10__STATIC; +int32_t MASKWALL11 = MASKWALL11__STATIC; +int32_t DOORTILE22 = DOORTILE22__STATIC; +int32_t FANSPRITE = FANSPRITE__STATIC; +int32_t FANSPRITEBROKE = FANSPRITEBROKE__STATIC; +int32_t FANSHADOW = FANSHADOW__STATIC; +int32_t FANSHADOWBROKE = FANSHADOWBROKE__STATIC; +int32_t DOORTILE18 = DOORTILE18__STATIC; +int32_t DOORTILE19 = DOORTILE19__STATIC; +int32_t DOORTILE20 = DOORTILE20__STATIC; +int32_t SATELLITE = SATELLITE__STATIC; +int32_t VIEWSCREEN2 = VIEWSCREEN2__STATIC; +int32_t VIEWSCREENBROKE = VIEWSCREENBROKE__STATIC; +int32_t VIEWSCREEN = VIEWSCREEN__STATIC; +int32_t GLASS = GLASS__STATIC; +int32_t GLASS2 = GLASS2__STATIC; +int32_t STAINGLASS1 = STAINGLASS1__STATIC; +int32_t MASKWALL5 = MASKWALL5__STATIC; +int32_t SATELITE = SATELITE__STATIC; +int32_t FUELPOD = FUELPOD__STATIC; +int32_t SLIMEPIPE = SLIMEPIPE__STATIC; +int32_t CRACK1 = CRACK1__STATIC; +int32_t CRACK2 = CRACK2__STATIC; +int32_t CRACK3 = CRACK3__STATIC; +int32_t CRACK4 = CRACK4__STATIC; +int32_t FOOTPRINTS = FOOTPRINTS__STATIC; +int32_t DOMELITE = DOMELITE__STATIC; +int32_t CAMERAPOLE = CAMERAPOLE__STATIC; +int32_t CHAIR1 = CHAIR1__STATIC; +int32_t CHAIR2 = CHAIR2__STATIC; +int32_t BROKENCHAIR = BROKENCHAIR__STATIC; +int32_t MIRROR = MIRROR__STATIC; +int32_t WATERFOUNTAIN = WATERFOUNTAIN__STATIC; +int32_t WATERFOUNTAINBROKE = WATERFOUNTAINBROKE__STATIC; +int32_t FEMMAG1 = FEMMAG1__STATIC; +int32_t TOILET = TOILET__STATIC; +int32_t STALL = STALL__STATIC; +int32_t STALLBROKE = STALLBROKE__STATIC; +int32_t FEMMAG2 = FEMMAG2__STATIC; +int32_t REACTOR2 = REACTOR2__STATIC; +int32_t REACTOR2BURNT = REACTOR2BURNT__STATIC; +int32_t REACTOR2SPARK = REACTOR2SPARK__STATIC; +int32_t GRATE1 = GRATE1__STATIC; +int32_t BGRATE1 = BGRATE1__STATIC; +int32_t SOLARPANNEL = SOLARPANNEL__STATIC; +int32_t NAKED1 = NAKED1__STATIC; +int32_t ANTENNA = ANTENNA__STATIC; +int32_t MASKWALL12 = MASKWALL12__STATIC; +int32_t TOILETBROKE = TOILETBROKE__STATIC; +int32_t PIPE2 = PIPE2__STATIC; +int32_t PIPE1B = PIPE1B__STATIC; +int32_t PIPE3 = PIPE3__STATIC; +int32_t PIPE1 = PIPE1__STATIC; +int32_t CAMERA1 = CAMERA1__STATIC; +int32_t BRICK = BRICK__STATIC; +int32_t SPLINTERWOOD = SPLINTERWOOD__STATIC; +int32_t PIPE2B = PIPE2B__STATIC; +int32_t BOLT1 = BOLT1__STATIC; +int32_t W_NUMBERS = W_NUMBERS__STATIC; +int32_t WATERDRIP = WATERDRIP__STATIC; +int32_t WATERBUBBLE = WATERBUBBLE__STATIC; +int32_t WATERBUBBLEMAKER = WATERBUBBLEMAKER__STATIC; +int32_t W_FORCEFIELD = W_FORCEFIELD__STATIC; +int32_t VACUUM = VACUUM__STATIC; +int32_t FOOTPRINTS2 = FOOTPRINTS2__STATIC; +int32_t FOOTPRINTS3 = FOOTPRINTS3__STATIC; +int32_t FOOTPRINTS4 = FOOTPRINTS4__STATIC; +int32_t EGG = EGG__STATIC; +int32_t SCALE = SCALE__STATIC; +int32_t CHAIR3 = CHAIR3__STATIC; +int32_t CAMERALIGHT = CAMERALIGHT__STATIC; +int32_t MOVIECAMERA = MOVIECAMERA__STATIC; +int32_t IVUNIT = IVUNIT__STATIC; +int32_t POT1 = POT1__STATIC; +int32_t POT2 = POT2__STATIC; +int32_t POT3 = POT3__STATIC; +int32_t PIPE3B = PIPE3B__STATIC; +int32_t WALLLIGHT3 = WALLLIGHT3__STATIC; +int32_t WALLLIGHTBUST3 = WALLLIGHTBUST3__STATIC; +int32_t WALLLIGHT1 = WALLLIGHT1__STATIC; +int32_t WALLLIGHTBUST1 = WALLLIGHTBUST1__STATIC; +int32_t WALLLIGHT2 = WALLLIGHT2__STATIC; +int32_t WALLLIGHTBUST2 = WALLLIGHTBUST2__STATIC; +int32_t LIGHTSWITCH2 = LIGHTSWITCH2__STATIC; +int32_t WAITTOBESEATED = WAITTOBESEATED__STATIC; +int32_t DOORTILE14 = DOORTILE14__STATIC; +int32_t STATUE = STATUE__STATIC; +int32_t MIKE = MIKE__STATIC; +int32_t VASE = VASE__STATIC; +int32_t SUSHIPLATE1 = SUSHIPLATE1__STATIC; +int32_t SUSHIPLATE2 = SUSHIPLATE2__STATIC; +int32_t SUSHIPLATE3 = SUSHIPLATE3__STATIC; +int32_t SUSHIPLATE4 = SUSHIPLATE4__STATIC; +int32_t DOORTILE16 = DOORTILE16__STATIC; +int32_t SUSHIPLATE5 = SUSHIPLATE5__STATIC; +int32_t OJ = OJ__STATIC; +int32_t MASKWALL13 = MASKWALL13__STATIC; +int32_t HURTRAIL = HURTRAIL__STATIC; +int32_t POWERSWITCH1 = POWERSWITCH1__STATIC; +int32_t LOCKSWITCH1 = LOCKSWITCH1__STATIC; +int32_t POWERSWITCH2 = POWERSWITCH2__STATIC; +int32_t ATM = ATM__STATIC; +int32_t STATUEFLASH = STATUEFLASH__STATIC; +int32_t ATMBROKE = ATMBROKE__STATIC; +int32_t BIGHOLE2 = BIGHOLE2__STATIC; +int32_t STRIPEBALL = STRIPEBALL__STATIC; +int32_t QUEBALL = QUEBALL__STATIC; +int32_t POCKET = POCKET__STATIC; +int32_t WOODENHORSE = WOODENHORSE__STATIC; +int32_t TREE1 = TREE1__STATIC; +int32_t TREE2 = TREE2__STATIC; +int32_t CACTUS = CACTUS__STATIC; +int32_t MASKWALL2 = MASKWALL2__STATIC; +int32_t MASKWALL3 = MASKWALL3__STATIC; +int32_t MASKWALL4 = MASKWALL4__STATIC; +int32_t FIREEXT = FIREEXT__STATIC; +int32_t TOILETWATER = TOILETWATER__STATIC; +int32_t NEON1 = NEON1__STATIC; +int32_t NEON2 = NEON2__STATIC; +int32_t CACTUSBROKE = CACTUSBROKE__STATIC; +int32_t BOUNCEMINE = BOUNCEMINE__STATIC; +int32_t BROKEFIREHYDRENT = BROKEFIREHYDRENT__STATIC; +int32_t BOX = BOX__STATIC; +int32_t BULLETHOLE = BULLETHOLE__STATIC; +int32_t BOTTLE1 = BOTTLE1__STATIC; +int32_t BOTTLE2 = BOTTLE2__STATIC; +int32_t BOTTLE3 = BOTTLE3__STATIC; +int32_t BOTTLE4 = BOTTLE4__STATIC; +int32_t FEMPIC5 = FEMPIC5__STATIC; +int32_t FEMPIC6 = FEMPIC6__STATIC; +int32_t FEMPIC7 = FEMPIC7__STATIC; +int32_t HYDROPLANT = HYDROPLANT__STATIC; +int32_t OCEANSPRITE1 = OCEANSPRITE1__STATIC; +int32_t OCEANSPRITE2 = OCEANSPRITE2__STATIC; +int32_t OCEANSPRITE3 = OCEANSPRITE3__STATIC; +int32_t OCEANSPRITE4 = OCEANSPRITE4__STATIC; +int32_t OCEANSPRITE5 = OCEANSPRITE5__STATIC; +int32_t GENERICPOLE = GENERICPOLE__STATIC; +int32_t CONE = CONE__STATIC; +int32_t HANGLIGHT = HANGLIGHT__STATIC; +int32_t HYDRENT = HYDRENT__STATIC; +int32_t MASKWALL14 = MASKWALL14__STATIC; +int32_t TIRE = TIRE__STATIC; +int32_t PIPE5 = PIPE5__STATIC; +int32_t PIPE6 = PIPE6__STATIC; +int32_t PIPE4 = PIPE4__STATIC; +int32_t PIPE4B = PIPE4B__STATIC; +int32_t BROKEHYDROPLANT = BROKEHYDROPLANT__STATIC; +int32_t PIPE5B = PIPE5B__STATIC; +int32_t NEON3 = NEON3__STATIC; +int32_t NEON4 = NEON4__STATIC; +int32_t NEON5 = NEON5__STATIC; +int32_t BOTTLE5 = BOTTLE5__STATIC; +int32_t BOTTLE6 = BOTTLE6__STATIC; +int32_t BOTTLE8 = BOTTLE8__STATIC; +int32_t SPOTLITE = SPOTLITE__STATIC; +int32_t HANGOOZ = HANGOOZ__STATIC; +int32_t MASKWALL15 = MASKWALL15__STATIC; +int32_t BOTTLE7 = BOTTLE7__STATIC; +int32_t HORSEONSIDE = HORSEONSIDE__STATIC; +int32_t GLASSPIECES = GLASSPIECES__STATIC; +int32_t HORSELITE = HORSELITE__STATIC; +int32_t DONUTS = DONUTS__STATIC; +int32_t NEON6 = NEON6__STATIC; +int32_t MASKWALL6 = MASKWALL6__STATIC; +int32_t CLOCK = CLOCK__STATIC; +int32_t RUBBERCAN = RUBBERCAN__STATIC; +int32_t BROKENCLOCK = BROKENCLOCK__STATIC; +int32_t PLUG = PLUG__STATIC; +int32_t OOZFILTER = OOZFILTER__STATIC; +int32_t FLOORPLASMA = FLOORPLASMA__STATIC; +int32_t REACTOR = REACTOR__STATIC; +int32_t REACTORSPARK = REACTORSPARK__STATIC; +int32_t REACTORBURNT = REACTORBURNT__STATIC; +int32_t DOORTILE15 = DOORTILE15__STATIC; +int32_t HANDSWITCH = HANDSWITCH__STATIC; +int32_t CIRCLEPANNEL = CIRCLEPANNEL__STATIC; +int32_t CIRCLEPANNELBROKE = CIRCLEPANNELBROKE__STATIC; +int32_t PULLSWITCH = PULLSWITCH__STATIC; +int32_t MASKWALL8 = MASKWALL8__STATIC; +int32_t BIGHOLE = BIGHOLE__STATIC; +int32_t ALIENSWITCH = ALIENSWITCH__STATIC; +int32_t DOORTILE21 = DOORTILE21__STATIC; +int32_t HANDPRINTSWITCH = HANDPRINTSWITCH__STATIC; +int32_t BOTTLE10 = BOTTLE10__STATIC; +int32_t BOTTLE11 = BOTTLE11__STATIC; +int32_t BOTTLE12 = BOTTLE12__STATIC; +int32_t BOTTLE13 = BOTTLE13__STATIC; +int32_t BOTTLE14 = BOTTLE14__STATIC; +int32_t BOTTLE15 = BOTTLE15__STATIC; +int32_t BOTTLE16 = BOTTLE16__STATIC; +int32_t BOTTLE17 = BOTTLE17__STATIC; +int32_t BOTTLE18 = BOTTLE18__STATIC; +int32_t BOTTLE19 = BOTTLE19__STATIC; +int32_t DOORTILE17 = DOORTILE17__STATIC; +int32_t MASKWALL7 = MASKWALL7__STATIC; +int32_t JAILBARBREAK = JAILBARBREAK__STATIC; +int32_t DOORTILE11 = DOORTILE11__STATIC; +int32_t DOORTILE12 = DOORTILE12__STATIC; +int32_t VENDMACHINE = VENDMACHINE__STATIC; +int32_t VENDMACHINEBROKE = VENDMACHINEBROKE__STATIC; +int32_t COLAMACHINE = COLAMACHINE__STATIC; +int32_t COLAMACHINEBROKE = COLAMACHINEBROKE__STATIC; +int32_t CRANEPOLE = CRANEPOLE__STATIC; +int32_t CRANE = CRANE__STATIC; +int32_t BARBROKE = BARBROKE__STATIC; +int32_t BLOODPOOL = BLOODPOOL__STATIC; +int32_t NUKEBARREL = NUKEBARREL__STATIC; +int32_t NUKEBARRELDENTED = NUKEBARRELDENTED__STATIC; +int32_t NUKEBARRELLEAKED = NUKEBARRELLEAKED__STATIC; +int32_t CANWITHSOMETHING = CANWITHSOMETHING__STATIC; +int32_t MONEY = MONEY__STATIC; +int32_t BANNER = BANNER__STATIC; +int32_t EXPLODINGBARREL = EXPLODINGBARREL__STATIC; +int32_t EXPLODINGBARREL2 = EXPLODINGBARREL2__STATIC; +int32_t FIREBARREL = FIREBARREL__STATIC; +int32_t SEENINE = SEENINE__STATIC; +int32_t SEENINEDEAD = SEENINEDEAD__STATIC; +int32_t STEAM = STEAM__STATIC; +int32_t CEILINGSTEAM = CEILINGSTEAM__STATIC; +int32_t PIPE6B = PIPE6B__STATIC; +int32_t TRANSPORTERBEAM = TRANSPORTERBEAM__STATIC; +int32_t RAT = RAT__STATIC; +int32_t TRASH = TRASH__STATIC; +int32_t FEMPIC1 = FEMPIC1__STATIC; +int32_t FEMPIC2 = FEMPIC2__STATIC; +int32_t BLANKSCREEN = BLANKSCREEN__STATIC; +int32_t PODFEM1 = PODFEM1__STATIC; +int32_t FEMPIC3 = FEMPIC3__STATIC; +int32_t FEMPIC4 = FEMPIC4__STATIC; +int32_t FEM1 = FEM1__STATIC; +int32_t FEM2 = FEM2__STATIC; +int32_t FEM3 = FEM3__STATIC; +int32_t FEM5 = FEM5__STATIC; +int32_t BLOODYPOLE = BLOODYPOLE__STATIC; +int32_t FEM4 = FEM4__STATIC; +int32_t FEM6 = FEM6__STATIC; +int32_t FEM6PAD = FEM6PAD__STATIC; +int32_t FEM8 = FEM8__STATIC; +int32_t HELECOPT = HELECOPT__STATIC; +int32_t FETUSJIB = FETUSJIB__STATIC; +int32_t HOLODUKE = HOLODUKE__STATIC; +int32_t SPACEMARINE = SPACEMARINE__STATIC; +int32_t INDY = INDY__STATIC; +int32_t FETUS = FETUS__STATIC; +int32_t FETUSBROKE = FETUSBROKE__STATIC; +int32_t MONK = MONK__STATIC; +int32_t LUKE = LUKE__STATIC; +int32_t COOLEXPLOSION1 = COOLEXPLOSION1__STATIC; +int32_t WATERSPLASH2 = WATERSPLASH2__STATIC; +int32_t FIREVASE = FIREVASE__STATIC; +int32_t SCRATCH = SCRATCH__STATIC; +int32_t FEM7 = FEM7__STATIC; +int32_t APLAYERTOP = APLAYERTOP__STATIC; +int32_t APLAYER = APLAYER__STATIC; +int32_t PLAYERONWATER = PLAYERONWATER__STATIC; +int32_t DUKELYINGDEAD = DUKELYINGDEAD__STATIC; +int32_t DUKETORSO = DUKETORSO__STATIC; +int32_t DUKEGUN = DUKEGUN__STATIC; +int32_t DUKELEG = DUKELEG__STATIC; +int32_t SHARK = SHARK__STATIC; +int32_t BLOOD = BLOOD__STATIC; +int32_t FIRELASER = FIRELASER__STATIC; +int32_t TRANSPORTERSTAR = TRANSPORTERSTAR__STATIC; +int32_t SPIT = SPIT__STATIC; +int32_t LOOGIE = LOOGIE__STATIC; +int32_t FIST = FIST__STATIC; +int32_t FREEZEBLAST = FREEZEBLAST__STATIC; +int32_t DEVISTATORBLAST = DEVISTATORBLAST__STATIC; +int32_t SHRINKSPARK = SHRINKSPARK__STATIC; +int32_t TONGUE = TONGUE__STATIC; +int32_t MORTER = MORTER__STATIC; +int32_t SHRINKEREXPLOSION = SHRINKEREXPLOSION__STATIC; +int32_t RADIUSEXPLOSION = RADIUSEXPLOSION__STATIC; +int32_t FORCERIPPLE = FORCERIPPLE__STATIC; +int32_t LIZTROOP = LIZTROOP__STATIC; +int32_t LIZTROOPRUNNING = LIZTROOPRUNNING__STATIC; +int32_t LIZTROOPSTAYPUT = LIZTROOPSTAYPUT__STATIC; +int32_t LIZTOP = LIZTOP__STATIC; +int32_t LIZTROOPSHOOT = LIZTROOPSHOOT__STATIC; +int32_t LIZTROOPJETPACK = LIZTROOPJETPACK__STATIC; +int32_t LIZTROOPDSPRITE = LIZTROOPDSPRITE__STATIC; +int32_t LIZTROOPONTOILET = LIZTROOPONTOILET__STATIC; +int32_t LIZTROOPJUSTSIT = LIZTROOPJUSTSIT__STATIC; +int32_t LIZTROOPDUCKING = LIZTROOPDUCKING__STATIC; +int32_t HEADJIB1 = HEADJIB1__STATIC; +int32_t ARMJIB1 = ARMJIB1__STATIC; +int32_t LEGJIB1 = LEGJIB1__STATIC; +int32_t CANNONBALL = CANNONBALL__STATIC; +int32_t OCTABRAIN = OCTABRAIN__STATIC; +int32_t OCTABRAINSTAYPUT = OCTABRAINSTAYPUT__STATIC; +int32_t OCTATOP = OCTATOP__STATIC; +int32_t OCTADEADSPRITE = OCTADEADSPRITE__STATIC; +int32_t INNERJAW = INNERJAW__STATIC; +int32_t DRONE = DRONE__STATIC; +int32_t EXPLOSION2 = EXPLOSION2__STATIC; +int32_t COMMANDER = COMMANDER__STATIC; +int32_t COMMANDERSTAYPUT = COMMANDERSTAYPUT__STATIC; +int32_t RECON = RECON__STATIC; +int32_t TANK = TANK__STATIC; +int32_t PIGCOP = PIGCOP__STATIC; +int32_t PIGCOPSTAYPUT = PIGCOPSTAYPUT__STATIC; +int32_t PIGCOPDIVE = PIGCOPDIVE__STATIC; +int32_t PIGCOPDEADSPRITE = PIGCOPDEADSPRITE__STATIC; +int32_t PIGTOP = PIGTOP__STATIC; +int32_t LIZMAN = LIZMAN__STATIC; +int32_t LIZMANSTAYPUT = LIZMANSTAYPUT__STATIC; +int32_t LIZMANSPITTING = LIZMANSPITTING__STATIC; +int32_t LIZMANFEEDING = LIZMANFEEDING__STATIC; +int32_t LIZMANJUMP = LIZMANJUMP__STATIC; +int32_t LIZMANDEADSPRITE = LIZMANDEADSPRITE__STATIC; +int32_t FECES = FECES__STATIC; +int32_t LIZMANHEAD1 = LIZMANHEAD1__STATIC; +int32_t LIZMANARM1 = LIZMANARM1__STATIC; +int32_t LIZMANLEG1 = LIZMANLEG1__STATIC; +int32_t EXPLOSION2BOT = EXPLOSION2BOT__STATIC; +int32_t USERWEAPON = USERWEAPON__STATIC; +int32_t HEADERBAR = HEADERBAR__STATIC; +int32_t JIBS1 = JIBS1__STATIC; +int32_t JIBS2 = JIBS2__STATIC; +int32_t JIBS3 = JIBS3__STATIC; +int32_t JIBS4 = JIBS4__STATIC; +int32_t JIBS5 = JIBS5__STATIC; +int32_t BURNING = BURNING__STATIC; +int32_t FIRE = FIRE__STATIC; +int32_t JIBS6 = JIBS6__STATIC; +int32_t BLOODSPLAT1 = BLOODSPLAT1__STATIC; +int32_t BLOODSPLAT3 = BLOODSPLAT3__STATIC; +int32_t BLOODSPLAT2 = BLOODSPLAT2__STATIC; +int32_t BLOODSPLAT4 = BLOODSPLAT4__STATIC; +int32_t OOZ = OOZ__STATIC; +int32_t OOZ2 = OOZ2__STATIC; +int32_t WALLBLOOD1 = WALLBLOOD1__STATIC; +int32_t WALLBLOOD2 = WALLBLOOD2__STATIC; +int32_t WALLBLOOD3 = WALLBLOOD3__STATIC; +int32_t WALLBLOOD4 = WALLBLOOD4__STATIC; +int32_t WALLBLOOD5 = WALLBLOOD5__STATIC; +int32_t WALLBLOOD6 = WALLBLOOD6__STATIC; +int32_t WALLBLOOD7 = WALLBLOOD7__STATIC; +int32_t WALLBLOOD8 = WALLBLOOD8__STATIC; +int32_t BURNING2 = BURNING2__STATIC; +int32_t FIRE2 = FIRE2__STATIC; +int32_t CRACKKNUCKLES = CRACKKNUCKLES__STATIC; +int32_t SMALLSMOKE = SMALLSMOKE__STATIC; +int32_t SMALLSMOKEMAKER = SMALLSMOKEMAKER__STATIC; +int32_t FLOORFLAME = FLOORFLAME__STATIC; +int32_t ROTATEGUN = ROTATEGUN__STATIC; +int32_t GREENSLIME = GREENSLIME__STATIC; +int32_t WATERDRIPSPLASH = WATERDRIPSPLASH__STATIC; +int32_t SCRAP6 = SCRAP6__STATIC; +int32_t SCRAP1 = SCRAP1__STATIC; +int32_t SCRAP2 = SCRAP2__STATIC; +int32_t SCRAP3 = SCRAP3__STATIC; +int32_t SCRAP4 = SCRAP4__STATIC; +int32_t SCRAP5 = SCRAP5__STATIC; +int32_t ORGANTIC = ORGANTIC__STATIC; +int32_t BETAVERSION = BETAVERSION__STATIC; +int32_t PLAYERISHERE = PLAYERISHERE__STATIC; +int32_t PLAYERWASHERE = PLAYERWASHERE__STATIC; +int32_t SELECTDIR = SELECTDIR__STATIC; +int32_t F1HELP = F1HELP__STATIC; +int32_t NOTCHON = NOTCHON__STATIC; +int32_t NOTCHOFF = NOTCHOFF__STATIC; +int32_t GROWSPARK = GROWSPARK__STATIC; +int32_t DUKEICON = DUKEICON__STATIC; +int32_t BADGUYICON = BADGUYICON__STATIC; +int32_t FOODICON = FOODICON__STATIC; +int32_t GETICON = GETICON__STATIC; +int32_t MENUSCREEN = MENUSCREEN__STATIC; +int32_t MENUBAR = MENUBAR__STATIC; +int32_t KILLSICON = KILLSICON__STATIC; +int32_t FIRSTAID_ICON = FIRSTAID_ICON__STATIC; +int32_t HEAT_ICON = HEAT_ICON__STATIC; +int32_t BOTTOMSTATUSBAR = BOTTOMSTATUSBAR__STATIC; +int32_t BOOT_ICON = BOOT_ICON__STATIC; +int32_t FRAGBAR = FRAGBAR__STATIC; +int32_t JETPACK_ICON = JETPACK_ICON__STATIC; +int32_t AIRTANK_ICON = AIRTANK_ICON__STATIC; +int32_t STEROIDS_ICON = STEROIDS_ICON__STATIC; +int32_t HOLODUKE_ICON = HOLODUKE_ICON__STATIC; +int32_t ACCESS_ICON = ACCESS_ICON__STATIC; +int32_t DIGITALNUM = DIGITALNUM__STATIC; +int32_t DUKECAR = DUKECAR__STATIC; +int32_t CAMCORNER = CAMCORNER__STATIC; +int32_t CAMLIGHT = CAMLIGHT__STATIC; +int32_t LOGO = LOGO__STATIC; +int32_t TITLE = TITLE__STATIC; +int32_t NUKEWARNINGICON = NUKEWARNINGICON__STATIC; +int32_t MOUSECURSOR = MOUSECURSOR__STATIC; +int32_t SLIDEBAR = SLIDEBAR__STATIC; +int32_t DREALMS = DREALMS__STATIC; +int32_t BETASCREEN = BETASCREEN__STATIC; +int32_t WINDOWBORDER1 = WINDOWBORDER1__STATIC; +int32_t TEXTBOX = TEXTBOX__STATIC; +int32_t WINDOWBORDER2 = WINDOWBORDER2__STATIC; +int32_t DUKENUKEM = DUKENUKEM__STATIC; +int32_t THREEDEE = THREEDEE__STATIC; +int32_t INGAMEDUKETHREEDEE = INGAMEDUKETHREEDEE__STATIC; +int32_t TENSCREEN = TENSCREEN__STATIC; +int32_t PLUTOPAKSPRITE = PLUTOPAKSPRITE__STATIC; +int32_t DEVISTATOR = DEVISTATOR__STATIC; +int32_t KNEE = KNEE__STATIC; +int32_t CROSSHAIR = CROSSHAIR__STATIC; +int32_t FIRSTGUN = FIRSTGUN__STATIC; +int32_t FIRSTGUNRELOAD = FIRSTGUNRELOAD__STATIC; +int32_t FALLINGCLIP = FALLINGCLIP__STATIC; +int32_t CLIPINHAND = CLIPINHAND__STATIC; +int32_t HAND = HAND__STATIC; +int32_t SHELL = SHELL__STATIC; +int32_t SHOTGUNSHELL = SHOTGUNSHELL__STATIC; +int32_t CHAINGUN = CHAINGUN__STATIC; +int32_t RPGGUN = RPGGUN__STATIC; +int32_t RPGMUZZLEFLASH = RPGMUZZLEFLASH__STATIC; +int32_t FREEZE = FREEZE__STATIC; +int32_t CATLITE = CATLITE__STATIC; +int32_t SHRINKER = SHRINKER__STATIC; +int32_t HANDHOLDINGLASER = HANDHOLDINGLASER__STATIC; +int32_t TRIPBOMB = TRIPBOMB__STATIC; +int32_t LASERLINE = LASERLINE__STATIC; +int32_t HANDHOLDINGACCESS = HANDHOLDINGACCESS__STATIC; +int32_t HANDREMOTE = HANDREMOTE__STATIC; +int32_t HANDTHROW = HANDTHROW__STATIC; +int32_t TIP = TIP__STATIC; +int32_t GLAIR = GLAIR__STATIC; +int32_t SCUBAMASK = SCUBAMASK__STATIC; +int32_t SPACEMASK = SPACEMASK__STATIC; +int32_t FORCESPHERE = FORCESPHERE__STATIC; +int32_t SHOTSPARK1 = SHOTSPARK1__STATIC; +int32_t RPG = RPG__STATIC; +int32_t LASERSITE = LASERSITE__STATIC; +int32_t SHOTGUN = SHOTGUN__STATIC; +int32_t BOSS1 = BOSS1__STATIC; +int32_t BOSS1STAYPUT = BOSS1STAYPUT__STATIC; +int32_t BOSS1SHOOT = BOSS1SHOOT__STATIC; +int32_t BOSS1LOB = BOSS1LOB__STATIC; +int32_t BOSSTOP = BOSSTOP__STATIC; +int32_t BOSS2 = BOSS2__STATIC; +int32_t BOSS3 = BOSS3__STATIC; +int32_t SPINNINGNUKEICON = SPINNINGNUKEICON__STATIC; +int32_t BIGFNTCURSOR = BIGFNTCURSOR__STATIC; +int32_t SMALLFNTCURSOR = SMALLFNTCURSOR__STATIC; +int32_t STARTALPHANUM = STARTALPHANUM__STATIC; +int32_t ENDALPHANUM = ENDALPHANUM__STATIC; +int32_t BIGALPHANUM = BIGALPHANUM__STATIC; +int32_t BIGPERIOD = BIGPERIOD__STATIC; +int32_t BIGCOMMA = BIGCOMMA__STATIC; +// "BIGX" clashes on the Wii? +int32_t BIGX_ = BIGX__STATIC; +int32_t BIGQ = BIGQ__STATIC; +int32_t BIGSEMI = BIGSEMI__STATIC; +int32_t BIGCOLIN = BIGCOLIN__STATIC; +int32_t THREEBYFIVE = THREEBYFIVE__STATIC; +int32_t BIGAPPOS = BIGAPPOS__STATIC; +int32_t BLANK = BLANK__STATIC; +int32_t MINIFONT = MINIFONT__STATIC; +int32_t BUTTON1 = BUTTON1__STATIC; +int32_t GLASS3 = GLASS3__STATIC; +int32_t RESPAWNMARKERRED = RESPAWNMARKERRED__STATIC; +int32_t RESPAWNMARKERYELLOW = RESPAWNMARKERYELLOW__STATIC; +int32_t RESPAWNMARKERGREEN = RESPAWNMARKERGREEN__STATIC; +int32_t BONUSSCREEN = BONUSSCREEN__STATIC; +int32_t VIEWBORDER = VIEWBORDER__STATIC; +int32_t VICTORY1 = VICTORY1__STATIC; +int32_t ORDERING = ORDERING__STATIC; +int32_t TEXTSTORY = TEXTSTORY__STATIC; +int32_t LOADSCREEN = LOADSCREEN__STATIC; +int32_t BORNTOBEWILDSCREEN = BORNTOBEWILDSCREEN__STATIC; +int32_t BLIMP = BLIMP__STATIC; +int32_t FEM9 = FEM9__STATIC; +int32_t FOOTPRINT = FOOTPRINT__STATIC; +int32_t POOP = POOP__STATIC; +int32_t FRAMEEFFECT1 = FRAMEEFFECT1__STATIC; +int32_t PANNEL3 = PANNEL3__STATIC; +int32_t SCREENBREAK14 = SCREENBREAK14__STATIC; +int32_t SCREENBREAK15 = SCREENBREAK15__STATIC; +int32_t SCREENBREAK19 = SCREENBREAK19__STATIC; +int32_t SCREENBREAK16 = SCREENBREAK16__STATIC; +int32_t SCREENBREAK17 = SCREENBREAK17__STATIC; +int32_t SCREENBREAK18 = SCREENBREAK18__STATIC; +int32_t W_TECHWALL11 = W_TECHWALL11__STATIC; +int32_t W_TECHWALL12 = W_TECHWALL12__STATIC; +int32_t W_TECHWALL13 = W_TECHWALL13__STATIC; +int32_t W_TECHWALL14 = W_TECHWALL14__STATIC; +int32_t W_TECHWALL5 = W_TECHWALL5__STATIC; +int32_t W_TECHWALL6 = W_TECHWALL6__STATIC; +int32_t W_TECHWALL7 = W_TECHWALL7__STATIC; +int32_t W_TECHWALL8 = W_TECHWALL8__STATIC; +int32_t W_TECHWALL9 = W_TECHWALL9__STATIC; +int32_t BPANNEL3 = BPANNEL3__STATIC; +int32_t W_HITTECHWALL16 = W_HITTECHWALL16__STATIC; +int32_t W_HITTECHWALL10 = W_HITTECHWALL10__STATIC; +int32_t W_HITTECHWALL15 = W_HITTECHWALL15__STATIC; +int32_t W_MILKSHELF = W_MILKSHELF__STATIC; +int32_t W_MILKSHELFBROKE = W_MILKSHELFBROKE__STATIC; +int32_t PURPLELAVA = PURPLELAVA__STATIC; +int32_t LAVABUBBLE = LAVABUBBLE__STATIC; +int32_t DUKECUTOUT = DUKECUTOUT__STATIC; +int32_t TARGET = TARGET__STATIC; +int32_t GUNPOWDERBARREL = GUNPOWDERBARREL__STATIC; +int32_t DUCK = DUCK__STATIC; +int32_t HATRACK = HATRACK__STATIC; +int32_t DESKLAMP = DESKLAMP__STATIC; +int32_t COFFEEMACHINE = COFFEEMACHINE__STATIC; +int32_t CUPS = CUPS__STATIC; +int32_t GAVALS = GAVALS__STATIC; +int32_t GAVALS2 = GAVALS2__STATIC; +int32_t POLICELIGHTPOLE = POLICELIGHTPOLE__STATIC; +int32_t FLOORBASKET = FLOORBASKET__STATIC; +int32_t PUKE = PUKE__STATIC; +int32_t DOORTILE23 = DOORTILE23__STATIC; +int32_t TOPSECRET = TOPSECRET__STATIC; +int32_t SPEAKER = SPEAKER__STATIC; +int32_t TEDDYBEAR = TEDDYBEAR__STATIC; +int32_t ROBOTDOG = ROBOTDOG__STATIC; +int32_t ROBOTPIRATE = ROBOTPIRATE__STATIC; +int32_t ROBOTMOUSE = ROBOTMOUSE__STATIC; +int32_t MAIL = MAIL__STATIC; +int32_t MAILBAG = MAILBAG__STATIC; +int32_t HOTMEAT = HOTMEAT__STATIC; +int32_t COFFEEMUG = COFFEEMUG__STATIC; +int32_t DONUTS2 = DONUTS2__STATIC; +int32_t TRIPODCAMERA = TRIPODCAMERA__STATIC; +int32_t METER = METER__STATIC; +int32_t DESKPHONE = DESKPHONE__STATIC; +int32_t GUMBALLMACHINE = GUMBALLMACHINE__STATIC; +int32_t GUMBALLMACHINEBROKE = GUMBALLMACHINEBROKE__STATIC; +int32_t PAPER = PAPER__STATIC; +int32_t MACE = MACE__STATIC; +int32_t GENERICPOLE2 = GENERICPOLE2__STATIC; +int32_t XXXSTACY = XXXSTACY__STATIC; +int32_t WETFLOOR = WETFLOOR__STATIC; +int32_t BROOM = BROOM__STATIC; +int32_t MOP = MOP__STATIC; +int32_t LETTER = LETTER__STATIC; +int32_t PIRATE1A = PIRATE1A__STATIC; +int32_t PIRATE4A = PIRATE4A__STATIC; +int32_t PIRATE2A = PIRATE2A__STATIC; +int32_t PIRATE5A = PIRATE5A__STATIC; +int32_t PIRATE3A = PIRATE3A__STATIC; +int32_t PIRATE6A = PIRATE6A__STATIC; +int32_t PIRATEHALF = PIRATEHALF__STATIC; +int32_t CHESTOFGOLD = CHESTOFGOLD__STATIC; +int32_t SIDEBOLT1 = SIDEBOLT1__STATIC; +int32_t FOODOBJECT1 = FOODOBJECT1__STATIC; +int32_t FOODOBJECT2 = FOODOBJECT2__STATIC; +int32_t FOODOBJECT3 = FOODOBJECT3__STATIC; +int32_t FOODOBJECT4 = FOODOBJECT4__STATIC; +int32_t FOODOBJECT5 = FOODOBJECT5__STATIC; +int32_t FOODOBJECT6 = FOODOBJECT6__STATIC; +int32_t FOODOBJECT7 = FOODOBJECT7__STATIC; +int32_t FOODOBJECT8 = FOODOBJECT8__STATIC; +int32_t FOODOBJECT9 = FOODOBJECT9__STATIC; +int32_t FOODOBJECT10 = FOODOBJECT10__STATIC; +int32_t FOODOBJECT11 = FOODOBJECT11__STATIC; +int32_t FOODOBJECT12 = FOODOBJECT12__STATIC; +int32_t FOODOBJECT13 = FOODOBJECT13__STATIC; +int32_t FOODOBJECT14 = FOODOBJECT14__STATIC; +int32_t FOODOBJECT15 = FOODOBJECT15__STATIC; +int32_t FOODOBJECT16 = FOODOBJECT16__STATIC; +int32_t FOODOBJECT17 = FOODOBJECT17__STATIC; +int32_t FOODOBJECT18 = FOODOBJECT18__STATIC; +int32_t FOODOBJECT19 = FOODOBJECT19__STATIC; +int32_t FOODOBJECT20 = FOODOBJECT20__STATIC; +int32_t HEADLAMP = HEADLAMP__STATIC; +int32_t TAMPON = TAMPON__STATIC; +int32_t SKINNEDCHICKEN = SKINNEDCHICKEN__STATIC; +int32_t FEATHEREDCHICKEN = FEATHEREDCHICKEN__STATIC; +int32_t ROBOTDOG2 = ROBOTDOG2__STATIC; +int32_t JOLLYMEAL = JOLLYMEAL__STATIC; +int32_t DUKEBURGER = DUKEBURGER__STATIC; +int32_t SHOPPINGCART = SHOPPINGCART__STATIC; +int32_t CANWITHSOMETHING2 = CANWITHSOMETHING2__STATIC; +int32_t CANWITHSOMETHING3 = CANWITHSOMETHING3__STATIC; +int32_t CANWITHSOMETHING4 = CANWITHSOMETHING4__STATIC; +int32_t SNAKEP = SNAKEP__STATIC; +int32_t DOLPHIN1 = DOLPHIN1__STATIC; +int32_t DOLPHIN2 = DOLPHIN2__STATIC; +int32_t NEWBEAST = NEWBEAST__STATIC; +int32_t NEWBEASTSTAYPUT = NEWBEASTSTAYPUT__STATIC; +int32_t NEWBEASTJUMP = NEWBEASTJUMP__STATIC; +int32_t NEWBEASTHANG = NEWBEASTHANG__STATIC; +int32_t NEWBEASTHANGDEAD = NEWBEASTHANGDEAD__STATIC; +int32_t BOSS4 = BOSS4__STATIC; +int32_t BOSS4STAYPUT = BOSS4STAYPUT__STATIC; +int32_t FEM10 = FEM10__STATIC; +int32_t TOUGHGAL = TOUGHGAL__STATIC; +int32_t MAN = MAN__STATIC; +int32_t MAN2 = MAN2__STATIC; +int32_t WOMAN = WOMAN__STATIC; +int32_t PLEASEWAIT = PLEASEWAIT__STATIC; +int32_t NATURALLIGHTNING = NATURALLIGHTNING__STATIC; +int32_t WEATHERWARN = WEATHERWARN__STATIC; +int32_t DUKETAG = DUKETAG__STATIC; +int32_t SIGN1 = SIGN1__STATIC; +int32_t SIGN2 = SIGN2__STATIC; +int32_t JURYGUY = JURYGUY__STATIC; + +int32_t RRTILE11 = 0; +int32_t RPG2SPRITE = 0; +int32_t RRTILE18 = 0; +int32_t RRTILE19 = 0; +int32_t RRTILE34 = 0; +int32_t RRTILE35 = 0; +int32_t DESTRUCTO = 0; +int32_t RRTILE38 = 0; +int32_t RRTILE43 = 0; +int32_t GUTMETER = 0; +int32_t RRTILE63 = 0; +int32_t RRTILE64 = 0; +int32_t RRTILE65 = 0; +int32_t RRTILE66 = 0; +int32_t RRTILE67 = 0; +int32_t RRTILE68 = 0; +int32_t SOUNDFX = 0; +int32_t MOTOAMMO = 0; +int32_t UFOBEAM = 0; +int32_t RRTILE280 = 0; +int32_t RRTILE281 = 0; +int32_t RRTILE282 = 0; +int32_t RRTILE283 = 0; +int32_t RRTILE285 = 0; +int32_t RRTILE286 = 0; +int32_t RRTILE287 = 0; +int32_t RRTILE288 = 0; +int32_t RRTILE289 = 0; +int32_t RRTILE290 = 0; +int32_t RRTILE291 = 0; +int32_t RRTILE292 = 0; +int32_t RRTILE293 = 0; +int32_t RRTILE295 = 0; +int32_t RRTILE296 = 0; +int32_t RRTILE297 = 0; +int32_t CDPLAYER = 0; +int32_t RRTILE380 = 0; +int32_t RRTILE403 = 0; +int32_t RRTILE409 = 0; +int32_t GUTMETER_LIGHT1 = 0; +int32_t GUTMETER_LIGHT2 = 0; +int32_t GUTMETER_LIGHT3 = 0; +int32_t GUTMETER_LIGHT4 = 0; +int32_t AMMO_ICON = 0; +int32_t RRTILE1076 = 0; +int32_t MUD = 0; +int32_t EXPLOSION3 = 0; +int32_t RRTILE1636 = 0; +int32_t WEAPONBAR = 0; +int32_t RRTILE1752 = 0; +int32_t RPG2 = 0; +int32_t RRTILE1790 = 0; +int32_t RRTILE1792 = 0; +int32_t RRTILE1801 = 0; +int32_t RRTILE1805 = 0; +int32_t RRTILE1807 = 0; +int32_t RRTILE1808 = 0; +int32_t RRTILE1812 = 0; +int32_t RRTILE1814 = 0; +int32_t RRTILE1817 = 0; +int32_t RRTILE1821 = 0; +int32_t RRTILE1824 = 0; +int32_t RRTILE1826 = 0; +int32_t RRTILE1850 = 0; +int32_t RRTILE1851 = 0; +int32_t RRTILE1856 = 0; +int32_t RRTILE1877 = 0; +int32_t RRTILE1878 = 0; +int32_t RRTILE1938 = 0; +int32_t RRTILE1939 = 0; +int32_t RRTILE1942 = 0; +int32_t RRTILE1944 = 0; +int32_t RRTILE1945 = 0; +int32_t RRTILE1947 = 0; +int32_t RRTILE1951 = 0; +int32_t RRTILE1952 = 0; +int32_t RRTILE1953 = 0; +int32_t RRTILE1961 = 0; +int32_t RRTILE1964 = 0; +int32_t RRTILE1973 = 0; +int32_t RRTILE1985 = 0; +int32_t RRTILE1986 = 0; +int32_t RRTILE1987 = 0; +int32_t RRTILE1988 = 0; +int32_t RRTILE1990 = 0; +int32_t RRTILE1995 = 0; +int32_t RRTILE1996 = 0; +int32_t RRTILE2004 = 0; +int32_t RRTILE2005 = 0; +int32_t POPCORN = 0; +int32_t RRTILE2022 = 0; +int32_t LANEPICS = 0; +int32_t RRTILE2025 = 0; +int32_t RRTILE2026 = 0; +int32_t RRTILE2027 = 0; +int32_t RRTILE2028 = 0; +int32_t RRTILE2034 = 0; +int32_t RRTILE2050 = 0; +int32_t RRTILE2052 = 0; +int32_t RRTILE2053 = 0; +int32_t RRTILE2056 = 0; +int32_t RRTILE2060 = 0; +int32_t RRTILE2072 = 0; +int32_t RRTILE2074 = 0; +int32_t RRTILE2075 = 0; +int32_t RRTILE2083 = 0; +int32_t RRTILE2097 = 0; +int32_t RRTILE2121 = 0; +int32_t RRTILE2122 = 0; +int32_t RRTILE2123 = 0; +int32_t RRTILE2124 = 0; +int32_t RRTILE2125 = 0; +int32_t RRTILE2126 = 0; +int32_t RRTILE2137 = 0; +int32_t RRTILE2132 = 0; +int32_t RRTILE2136 = 0; +int32_t RRTILE2139 = 0; +int32_t RRTILE2150 = 0; +int32_t RRTILE2151 = 0; +int32_t RRTILE2152 = 0; +int32_t RRTILE2156 = 0; +int32_t RRTILE2157 = 0; +int32_t RRTILE2158 = 0; +int32_t RRTILE2159 = 0; +int32_t RRTILE2160 = 0; +int32_t RRTILE2161 = 0; +int32_t RRTILE2175 = 0; +int32_t RRTILE2176 = 0; +int32_t RRTILE2178 = 0; +int32_t RRTILE2186 = 0; +int32_t RRTILE2214 = 0; +int32_t RRTILE2319 = 0; +int32_t RRTILE2321 = 0; +int32_t RRTILE2326 = 0; +int32_t RRTILE2329 = 0; +int32_t RRTILE2357 = 0; +int32_t RRTILE2382 = 0; +int32_t RRTILE2430 = 0; +int32_t RRTILE2431 = 0; +int32_t RRTILE2432 = 0; +int32_t RRTILE2437 = 0; +int32_t RRTILE2443 = 0; +int32_t RRTILE2445 = 0; +int32_t RRTILE2446 = 0; +int32_t RRTILE2450 = 0; +int32_t RRTILE2451 = 0; +int32_t RRTILE2455 = 0; +int32_t RRTILE2460 = 0; +int32_t RRTILE2465 = 0; +int32_t RRTILE2560 = 0; +int32_t RRTILE2562 = 0; +int32_t RRTILE2564 = 0; +int32_t RRTILE2573 = 0; +int32_t RRTILE2574 = 0; +int32_t RRTILE2577 = 0; +int32_t RRTILE2578 = 0; +int32_t RRTILE2581 = 0; +int32_t RRTILE2583 = 0; +int32_t RRTILE2604 = 0; +int32_t RRTILE2610 = 0; +int32_t RRTILE2613 = 0; +int32_t RRTILE2621 = 0; +int32_t RRTILE2622 = 0; +int32_t RRTILE2636 = 0; +int32_t RRTILE2637 = 0; +int32_t RRTILE2654 = 0; +int32_t RRTILE2656 = 0; +int32_t RRTILE2676 = 0; +int32_t RRTILE2689 = 0; +int32_t RRTILE2697 = 0; +int32_t RRTILE2702 = 0; +int32_t RRTILE2707 = 0; +int32_t RRTILE2732 = 0; +int32_t RRTILE2030 = 0; +int32_t RRTILE2831 = 0; +int32_t RRTILE2832 = 0; +int32_t RRTILE2842 = 0; +int32_t RRTILE2859 = 0; +int32_t RRTILE2876 = 0; +int32_t RRTILE2878 = 0; +int32_t RRTILE2879 = 0; +int32_t RRTILE2893 = 0; +int32_t RRTILE2894 = 0; +int32_t RRTILE2898 = 0; +int32_t RRTILE2899 = 0; +int32_t RRTILE2915 = 0; +int32_t RRTILE2940 = 0; +int32_t RRTILE2944 = 0; +int32_t RRTILE2945 = 0; +int32_t RRTILE2946 = 0; +int32_t RRTILE2947 = 0; +int32_t RRTILE2948 = 0; +int32_t RRTILE2949 = 0; +int32_t RRTILE2961 = 0; +int32_t RRTILE2970 = 0; +int32_t RRTILE2977 = 0; +int32_t RRTILE2978 = 0; +int32_t RRTILE2990 = 0; +int32_t RRTILE3073 = 0; +int32_t RRTILE3083 = 0; +int32_t RRTILE3100 = 0; +int32_t RRTILE3114 = 0; +int32_t RRTILE3115 = 0; +int32_t RRTILE3116 = 0; +int32_t RRTILE3117 = 0; +int32_t RRTILE3120 = 0; +int32_t RRTILE3121 = 0; +int32_t RRTILE3122 = 0; +int32_t RRTILE3123 = 0; +int32_t RRTILE3124 = 0; +int32_t RRTILE3132 = 0; +int32_t RRTILE3139 = 0; +int32_t RRTILE3144 = 0; +int32_t RRTILE3152 = 0; +int32_t RRTILE3153 = 0; +int32_t RRTILE3155 = 0; +int32_t RRTILE3171 = 0; +int32_t RRTILE3172 = 0; +int32_t RRTILE3190 = 0; +int32_t RRTILE3191 = 0; +int32_t RRTILE3192 = 0; +int32_t RRTILE3195 = 0; +int32_t RRTILE3200 = 0; +int32_t RRTILE3201 = 0; +int32_t RRTILE3202 = 0; +int32_t RRTILE3203 = 0; +int32_t RRTILE3204 = 0; +int32_t RRTILE3205 = 0; +int32_t RRTILE3206 = 0; +int32_t RRTILE3207 = 0; +int32_t RRTILE3208 = 0; +int32_t RRTILE3209 = 0; +int32_t RRTILE3216 = 0; +int32_t RRTILE3218 = 0; +int32_t RRTILE3219 = 0; +int32_t RRTILE3232 = 0; +int32_t SHOTGUNSHELLS = 0; +int32_t CIRCLESTUCK = 0; +int32_t RRTILE3410 = 0; +int32_t LUMBERBLADE = 0; +int32_t BOWLINGBALLH = 0; +int32_t BOWLINGBALL = 0; +int32_t BOWLINGBALLSPRITE = 0; +int32_t POWDERH = 0; +int32_t RRTILE3440 = 0; +int32_t RRTILE3462 = 0; +int32_t OWHIP = 0; +int32_t UWHIP = 0; +int32_t RPGGUN2 = 0; +int32_t RRTILE3497 = 0; +int32_t RRTILE3498 = 0; +int32_t RRTILE3499 = 0; +int32_t RRTILE3500 = 0; +int32_t SLINGBLADE = 0; +int32_t RRTILE3584 = 0; +int32_t RRTILE3586 = 0; +int32_t RRTILE3587 = 0; +int32_t RRTILE3600 = 0; +int32_t RRTILE3631 = 0; +int32_t RRTILE3635 = 0; +int32_t RRTILE3637 = 0; +int32_t RRTILE3643 = 0; +int32_t RRTILE3647 = 0; +int32_t RRTILE3652 = 0; +int32_t RRTILE3653 = 0; +int32_t RRTILE3668 = 0; +int32_t RRTILE3671 = 0; +int32_t RRTILE3673 = 0; +int32_t RRTILE3677 = 0; +int32_t RRTILE3684 = 0; +int32_t RRTILE3708 = 0; +int32_t RRTILE3714 = 0; +int32_t RRTILE3716 = 0; +int32_t RRTILE3720 = 0; +int32_t RRTILE3723 = 0; +int32_t RRTILE3725 = 0; +int32_t RRTILE3737 = 0; +int32_t RRTILE3754 = 0; +int32_t RRTILE3762 = 0; +int32_t RRTILE3763 = 0; +int32_t RRTILE3764 = 0; +int32_t RRTILE3765 = 0; +int32_t RRTILE3767 = 0; +int32_t RRTILE3773 = 0; +int32_t RRTILE3774 = 0; +int32_t RRTILE3793 = 0; +int32_t RRTILE3795 = 0; +int32_t RRTILE3804 = 0; +int32_t RRTILE3814 = 0; +int32_t RRTILE3815 = 0; +int32_t RRTILE3819 = 0; +int32_t RRTILE3827 = 0; +int32_t RRTILE3837 = 0; +int32_t RRTILE5014 = 0; +int32_t RRTILE5016 = 0; +int32_t RRTILE5017 = 0; +int32_t RRTILE5018 = 0; +int32_t RRTILE5019 = 0; +int32_t RRTILE5020 = 0; +int32_t RRTILE5021 = 0; +int32_t RRTILE5022 = 0; +int32_t RRTILE5023 = 0; +int32_t RRTILE5024 = 0; +int32_t RRTILE5025 = 0; +int32_t RRTILE5026 = 0; +int32_t RRTILE5027 = 0; +int32_t RRTILE5029 = 0; +int32_t RRTILE5030 = 0; +int32_t RRTILE5031 = 0; +int32_t RRTILE5032 = 0; +int32_t RRTILE5033 = 0; +int32_t RRTILE5034 = 0; +int32_t RRTILE5035 = 0; +int32_t RRTILE5036 = 0; +int32_t RRTILE5037 = 0; +int32_t RRTILE5038 = 0; +int32_t RRTILE5039 = 0; +int32_t RRTILE5040 = 0; +int32_t RRTILE5041 = 0; +int32_t RRTILE5043 = 0; +int32_t RRTILE5044 = 0; +int32_t RRTILE5045 = 0; +int32_t RRTILE5046 = 0; +int32_t RRTILE5047 = 0; +int32_t RRTILE5048 = 0; +int32_t RRTILE5049 = 0; +int32_t RRTILE5050 = 0; +int32_t RRTILE5051 = 0; +int32_t RRTILE5052 = 0; +int32_t RRTILE5053 = 0; +int32_t RRTILE5054 = 0; +int32_t RRTILE5055 = 0; +int32_t RRTILE5056 = 0; +int32_t RRTILE5057 = 0; +int32_t RRTILE5058 = 0; +int32_t RRTILE5059 = 0; +int32_t RRTILE5061 = 0; +int32_t RRTILE5062 = 0; +int32_t RRTILE5063 = 0; +int32_t RRTILE5064 = 0; +int32_t RRTILE5065 = 0; +int32_t RRTILE5066 = 0; +int32_t RRTILE5067 = 0; +int32_t RRTILE5068 = 0; +int32_t RRTILE5069 = 0; +int32_t RRTILE5070 = 0; +int32_t RRTILE5071 = 0; +int32_t RRTILE5072 = 0; +int32_t RRTILE5073 = 0; +int32_t RRTILE5074 = 0; +int32_t RRTILE5075 = 0; +int32_t RRTILE5076 = 0; +int32_t RRTILE5077 = 0; +int32_t RRTILE5078 = 0; +int32_t RRTILE5079 = 0; +int32_t RRTILE5080 = 0; +int32_t RRTILE5081 = 0; +int32_t RRTILE5082 = 0; +int32_t RRTILE5083 = 0; +int32_t RRTILE5084 = 0; +int32_t RRTILE5085 = 0; +int32_t RRTILE5086 = 0; +int32_t RRTILE5087 = 0; +int32_t RRTILE5088 = 0; +int32_t RRTILE5090 = 0; +int32_t RRTILE6144 = 0; +int32_t RRTILE7110 = 0; +int32_t RRTILE7111 = 0; +int32_t RRTILE7112 = 0; +int32_t RRTILE7113 = 0; +int32_t MOTOGUN = 0; +int32_t RRTILE7169 = 0; +int32_t MOTOHIT = 0; +int32_t BOATHIT = 0; +int32_t RRTILE7184 = 0; +int32_t RRTILE7190 = 0; +int32_t RRTILE7191 = 0; +int32_t RRTILE7213 = 0; +int32_t RRTILE7219 = 0; +int32_t EMPTYBIKE = 0; +int32_t EMPTYBOAT = 0; +int32_t RRTILE7424 = 0; +int32_t RRTILE7430 = 0; +int32_t RRTILE7433 = 0; +int32_t RRTILE7441 = 0; +int32_t RRTILE7547 = 0; +int32_t RRTILE7467 = 0; +int32_t RRTILE7469 = 0; +int32_t RRTILE7470 = 0; +int32_t RRTILE7475 = 0; +int32_t RRTILE7478 = 0; +int32_t RRTILE7505 = 0; +int32_t RRTILE7506 = 0; +int32_t RRTILE7534 = 0; +int32_t RRTILE7540 = 0; +int32_t RRTILE7533 = 0; +int32_t RRTILE7545 = 0; +int32_t RRTILE7552 = 0; +int32_t RRTILE7553 = 0; +int32_t RRTILE7554 = 0; +int32_t RRTILE7555 = 0; +int32_t RRTILE7557 = 0; +int32_t RRTILE7558 = 0; +int32_t RRTILE7559 = 0; +int32_t RRTILE7561 = 0; +int32_t RRTILE7566 = 0; +int32_t RRTILE7568 = 0; +int32_t RRTILE7574 = 0; +int32_t RRTILE7575 = 0; +int32_t RRTILE7576 = 0; +int32_t RRTILE7578 = 0; +int32_t RRTILE7579 = 0; +int32_t RRTILE7580 = 0; +int32_t RRTILE7595 = 0; +int32_t RRTILE7629 = 0; +int32_t RRTILE7636 = 0; +int32_t RRTILE7638 = 0; +int32_t RRTILE7640 = 0; +int32_t RRTILE7644 = 0; +int32_t RRTILE7646 = 0; +int32_t RRTILE7648 = 0; +int32_t RRTILE7650 = 0; +int32_t RRTILE7653 = 0; +int32_t RRTILE7655 = 0; +int32_t RRTILE7657 = 0; +int32_t RRTILE7659 = 0; +int32_t RRTILE7691 = 0; +int32_t RRTILE7694 = 0; +int32_t RRTILE7696 = 0; +int32_t RRTILE7697 = 0; +int32_t RRTILE7700 = 0; +int32_t RRTILE7702 = 0; +int32_t RRTILE7704 = 0; +int32_t RRTILE7705 = 0; +int32_t RRTILE7711 = 0; +int32_t RRTILE7716 = 0; +int32_t RRTILE7756 = 0; +int32_t RRTILE7768 = 0; +int32_t RRTILE7806 = 0; +int32_t RRTILE7820 = 0; +int32_t RRTILE7859 = 0; +int32_t RRTILE7870 = 0; +int32_t RRTILE7873 = 0; +int32_t RRTILE7875 = 0; +int32_t RRTILE7876 = 0; +int32_t RRTILE7879 = 0; +int32_t RRTILE7881 = 0; +int32_t RRTILE7883 = 0; +int32_t RRTILE7885 = 0; +int32_t RRTILE7886 = 0; +int32_t RRTILE7887 = 0; +int32_t RRTILE7888 = 0; +int32_t RRTILE7889 = 0; +int32_t RRTILE7890 = 0; +int32_t RRTILE7900 = 0; +int32_t RRTILE7901 = 0; +int32_t RRTILE7906 = 0; +int32_t RRTILE7912 = 0; +int32_t RRTILE7913 = 0; +int32_t RRTILE7936 = 0; +int32_t RRTILE8047 = 0; +int32_t MULTISWITCH2 = 0; +int32_t RRTILE8059 = 0; +int32_t RRTILE8060 = 0; +int32_t RRTILE8063 = 0; +int32_t RRTILE8067 = 0; +int32_t RRTILE8076 = 0; +int32_t RRTILE8094 = 0; +int32_t RRTILE8096 = 0; +int32_t RRTILE8099 = 0; +int32_t RRTILE8106 = 0; +int32_t RRTILE8162 = 0; +int32_t RRTILE8163 = 0; +int32_t RRTILE8164 = 0; +int32_t RRTILE8165 = 0; +int32_t RRTILE8166 = 0; +int32_t RRTILE8167 = 0; +int32_t RRTILE8168 = 0; +int32_t RRTILE8192 = 0; +int32_t RRTILE8193 = 0; +int32_t RRTILE8215 = 0; +int32_t RRTILE8216 = 0; +int32_t RRTILE8217 = 0; +int32_t RRTILE8218 = 0; +int32_t RRTILE8220 = 0; +int32_t RRTILE8221 = 0; +int32_t RRTILE8222 = 0; +int32_t RRTILE8223 = 0; +int32_t RRTILE8224 = 0; +int32_t RRTILE8227 = 0; +int32_t RRTILE8312 = 0; +int32_t RRTILE8370 = 0; +int32_t RRTILE8371 = 0; +int32_t RRTILE8372 = 0; +int32_t RRTILE8373 = 0; +int32_t RRTILE8379 = 0; +int32_t RRTILE8380 = 0; +int32_t RRTILE8385 = 0; +int32_t RRTILE8386 = 0; +int32_t RRTILE8387 = 0; +int32_t RRTILE8388 = 0; +int32_t RRTILE8389 = 0; +int32_t RRTILE8390 = 0; +int32_t RRTILE8391 = 0; +int32_t RRTILE8392 = 0; +int32_t RRTILE8394 = 0; +int32_t RRTILE8395 = 0; +int32_t RRTILE8396 = 0; +int32_t RRTILE8397 = 0; +int32_t RRTILE8398 = 0; +int32_t RRTILE8399 = 0; +int32_t RRTILE8423 = 0; +int32_t RRTILE8448 = 0; +int32_t RRTILE8450 = 0; +int32_t BOATAMMO = 0; +int32_t RRTILE8461 = 0; +int32_t RRTILE8462 = 0; +int32_t RRTILE8464 = 0; +int32_t RRTILE8475 = 0; +int32_t RRTILE8487 = 0; +int32_t RRTILE8488 = 0; +int32_t RRTILE8489 = 0; +int32_t RRTILE8490 = 0; +int32_t RRTILE8496 = 0; +int32_t RRTILE8497 = 0; +int32_t RRTILE8498 = 0; +int32_t RRTILE8499 = 0; +int32_t RRTILE8503 = 0; +int32_t RRTILE8525 = 0; +int32_t RRTILE8537 = 0; +int32_t RRTILE8565 = 0; +int32_t RRTILE8567 = 0; +int32_t RRTILE8568 = 0; +int32_t RRTILE8569 = 0; +int32_t RRTILE8570 = 0; +int32_t RRTILE8571 = 0; +int32_t RRTILE8579 = 0; +int32_t RRTILE8588 = 0; +int32_t RRTILE8589 = 0; +int32_t RRTILE8590 = 0; +int32_t RRTILE8591 = 0; +int32_t RRTILE8592 = 0; +int32_t RRTILE8593 = 0; +int32_t RRTILE8594 = 0; +int32_t RRTILE8595 = 0; +int32_t RRTILE8596 = 0; +int32_t RRTILE8598 = 0; +int32_t RRTILE8605 = 0; +int32_t RRTILE8608 = 0; +int32_t RRTILE8609 = 0; +int32_t RRTILE8611 = 0; +int32_t RRTILE8617 = 0; +int32_t RRTILE8618 = 0; +int32_t RRTILE8620 = 0; +int32_t RRTILE8621 = 0; +int32_t RRTILE8622 = 0; +int32_t RRTILE8623 = 0; +int32_t RRTILE8624 = 0; +int32_t RRTILE8640 = 0; +int32_t RRTILE8651 = 0; +int32_t RRTILE8660 = 0; +int32_t RRTILE8677 = 0; +int32_t RRTILE8679 = 0; +int32_t RRTILE8680 = 0; +int32_t RRTILE8681 = 0; +int32_t RRTILE8682 = 0; +int32_t RRTILE8683 = 0; +int32_t RRTILE8704 = 0; +int32_t BOULDER = 0; +int32_t BOULDER1 = 0; +int32_t TORNADO = 0; +int32_t CHEERBOMB = 0; +int32_t CHEERBLADE = 0; +int32_t DOGATTACK = 0; +int32_t BILLYWALK = 0; +int32_t BILLYDIE = 0; +int32_t BILLYCOCK = 0; +int32_t BILLYRAY = 0; +int32_t BILLYRAYSTAYPUT = 0; +int32_t BILLYBUT = 0; +int32_t BILLYSCRATCH = 0; +int32_t BILLYSNIFF = 0; +int32_t BILLYWOUND = 0; +int32_t BILLYGORE = 0; +int32_t BILLYJIBA = 0; +int32_t BILLYJIBB = 0; +int32_t BRAYSNIPER = 0; +int32_t DOGRUN = 0; +int32_t DOGDIE = 0; +int32_t DOGDEAD = 0; +int32_t DOGBARK = 0; +int32_t LTH = 0; +int32_t LTHSTRAFE = 0; +int32_t HULKHANG = 0; +int32_t HULKHANGDEAD = 0; +int32_t HULKJUMP = 0; +int32_t LTHLOAD = 0; +int32_t LTHDIE = 0; +int32_t BUBBASCRATCH = 0; +int32_t BUBBANOSE = 0; +int32_t BUBBAPISS = 0; +int32_t BUBBASTAND = 0; +int32_t BUBBAOUCH = 0; +int32_t BUBBADIE = 0; +int32_t BUBBADEAD = 0; +int32_t HULK = 0; +int32_t HULKSTAYPUT = 0; +int32_t HULKA = 0; +int32_t HULKB = 0; +int32_t HULKC = 0; +int32_t HULKJIBA = 0; +int32_t HULKJIBB = 0; +int32_t HULKJIBC = 0; +int32_t SBSWIPE = 0; +int32_t SBPAIN = 0; +int32_t SBDIE = 0; +int32_t HEN = 0; +int32_t HENSTAYPUT = 0; +int32_t HENSTAND = 0; +int32_t PIG = 0; +int32_t PIGSTAYPUT = 0; +int32_t PIGEAT = 0; +int32_t SBMOVE = 0; +int32_t SBSPIT = 0; +int32_t SBDIP = 0; +int32_t MINION = 0; +int32_t MINIONSTAYPUT = 0; +int32_t UFO1 = 0; +int32_t UFO2 = 0; +int32_t UFO3 = 0; +int32_t UFO4 = 0; +int32_t UFO5 = 0; +int32_t MINJIBA = 0; +int32_t MINJIBB = 0; +int32_t MINJIBC = 0; +int32_t COW = 0; +int32_t COOT = 0; +int32_t COOTSTAYPUT = 0; +int32_t COOTSHOOT = 0; +int32_t COOTDIE = 0; +int32_t COOTDUCK = 0; +int32_t COOTPAIN = 0; +int32_t COOTTRANS = 0; +int32_t COOTGETUP = 0; +int32_t COOTJIBA = 0; +int32_t COOTJIBB = 0; +int32_t COOTJIBC = 0; +int32_t VIXEN = 0; +int32_t VIXENPAIN = 0; +int32_t VIXENDIE = 0; +int32_t VIXENSHOOT = 0; +int32_t VIXENWDN = 0; +int32_t VIXENWUP = 0; +int32_t VIXENKICK = 0; +int32_t VIXENTELE = 0; +int32_t VIXENTEAT = 0; +int32_t BIKEJIBA = 0; +int32_t BIKEJIBB = 0; +int32_t BIKEJIBC = 0; +int32_t BIKERB = 0; +int32_t BIKERBV2 = 0; +int32_t BIKER = 0; +int32_t BIKERJIBA = 0; +int32_t BIKERJIBB = 0; +int32_t BIKERJIBC = 0; +int32_t BIKERJIBD = 0; +int32_t MAKEOUT = 0; +int32_t CHEERB = 0; +int32_t CHEER = 0; +int32_t CHEERSTAYPUT = 0; +int32_t CHEERJIBA = 0; +int32_t CHEERJIBB = 0; +int32_t CHEERJIBC = 0; +int32_t CHEERJIBD = 0; +int32_t FBOATJIBA = 0; +int32_t FBOATJIBB = 0; +int32_t COOTPLAY = 0; +int32_t BILLYPLAY = 0; +int32_t MINIONBOAT = 0; +int32_t HULKBOAT = 0; +int32_t CHEERBOAT = 0; +int32_t RRTILE7274 = 0; +int32_t RABBIT = 0; +int32_t RABBITJIBA = 0; +int32_t RABBITJIBB = 0; +int32_t RABBITJIBC = 0; +int32_t ROCK = 0; +int32_t ROCK2 = 0; +int32_t MAMACLOUD = 0; +int32_t MAMA = 0; +int32_t MAMAJIBA = 0; +int32_t MAMAJIBB = 0; + +#if 0 +static hashtable_t h_names = {512, NULL}; + +void G_ProcessDynamicTileMapping(const char *szLabel, int32_t lValue) +{ + int32_t i; + + if ((unsigned)lValue >= MAXTILES || !szLabel) + return; + + i = hash_find(&h_names,szLabel); + if (i>=0) + { + struct dynitem *di = &g_dynTileList[i]; +#ifdef DEBUGGINGAIDS + if (g_scriptDebug && di->staticval != lValue) + Printf("REMAP %s (%d) --> %d\n", di->str, di->staticval, lValue); +#endif + *di->dynvalptr = lValue; + } +} + +void inithashnames(void) +{ + int32_t i; + + hash_init(&h_names); + + for (i=0; g_dynTileList[i].staticval >= 0; i++) + hash_add(&h_names, g_dynTileList[i].str, i, 0); +} + +void freehashnames(void) +{ + hash_free(&h_names); +} +#endif + + +static struct dynitem g_dynWeaponList[] = +{ + { "KNEE_WEAPON", DVPTR(KNEE_WEAPON), KNEE_WEAPON__STATIC, KNEE_WEAPON__STATIC }, + { "PISTOL_WEAPON", DVPTR(PISTOL_WEAPON), PISTOL_WEAPON__STATIC, PISTOL_WEAPON__STATIC }, + { "SHOTGUN_WEAPON", DVPTR(SHOTGUN_WEAPON), SHOTGUN_WEAPON__STATIC, SHOTGUN_WEAPON__STATIC }, + { "CHAINGUN_WEAPON", DVPTR(CHAINGUN_WEAPON), CHAINGUN_WEAPON__STATIC, CHAINGUN_WEAPON__STATIC }, + { "RPG_WEAPON", DVPTR(RPG_WEAPON), RPG_WEAPON__STATIC, HANDBOMB_WEAPON__STATIC }, + { "HANDBOMB_WEAPON", DVPTR(HANDBOMB_WEAPON), HANDBOMB_WEAPON__STATIC, RPG_WEAPON__STATIC }, + { "SHRINKER_WEAPON", DVPTR(SHRINKER_WEAPON), SHRINKER_WEAPON__STATIC, SHRINKER_WEAPON__STATIC }, + { "DEVISTATOR_WEAPON", DVPTR(DEVISTATOR_WEAPON), DEVISTATOR_WEAPON__STATIC, FREEZE_WEAPON__STATIC }, + { "TRIPBOMB_WEAPON", DVPTR(TRIPBOMB_WEAPON), TRIPBOMB_WEAPON__STATIC, TRIPBOMB_WEAPON__STATIC }, + { "FREEZE_WEAPON", DVPTR(FREEZE_WEAPON), FREEZE_WEAPON__STATIC, DEVISTATOR_WEAPON__STATIC }, + { "HANDREMOTE_WEAPON", DVPTR(HANDREMOTE_WEAPON), HANDREMOTE_WEAPON__STATIC, HANDREMOTE_WEAPON__STATIC }, + { "GROW_WEAPON", DVPTR(GROW_WEAPON), GROW_WEAPON__STATIC, GROW_WEAPON__STATIC }, + { "BOWLINGBALL_WEAPON", DVPTR(BOWLINGBALL_WEAPON), BOWLINGBALL_WEAPON__STATIC, BOWLINGBALL_WEAPON__STATIC }, + { "MOTORCYCLE_WEAPON", DVPTR(MOTORCYCLE_WEAPON), MOTORCYCLE_WEAPON__STATIC, MOTORCYCLE_WEAPON__STATIC }, + { "BOAT_WEAPON", DVPTR(BOAT_WEAPON), BOAT_WEAPON__STATIC, BOAT_WEAPON__STATIC }, + { "SLINGBLADE_WEAPON", DVPTR(SLINGBLADE_WEAPON), SLINGBLADE_WEAPON__STATIC, SLINGBLADE_WEAPON__STATIC }, + { "CHICKEN_WEAPON", DVPTR(CHICKEN_WEAPON), CHICKEN_WEAPON__STATIC, CHICKEN_WEAPON__STATIC }, + { NULL, NULL, -1, -1 }, +}; + +int32_t KNEE_WEAPON = KNEE_WEAPON__STATIC; +int32_t PISTOL_WEAPON = PISTOL_WEAPON__STATIC; +int32_t SHOTGUN_WEAPON = SHOTGUN_WEAPON__STATIC; +int32_t CHAINGUN_WEAPON = CHAINGUN_WEAPON__STATIC; +int32_t RPG_WEAPON = RPG_WEAPON__STATIC; +int32_t HANDBOMB_WEAPON = HANDBOMB_WEAPON__STATIC; +int32_t SHRINKER_WEAPON = SHRINKER_WEAPON__STATIC; +int32_t DEVISTATOR_WEAPON = DEVISTATOR_WEAPON__STATIC; +int32_t TRIPBOMB_WEAPON = TRIPBOMB_WEAPON__STATIC; +int32_t FREEZE_WEAPON = FREEZE_WEAPON__STATIC; +int32_t HANDREMOTE_WEAPON = HANDREMOTE_WEAPON__STATIC; +int32_t GROW_WEAPON = GROW_WEAPON__STATIC; +int32_t BOWLINGBALL_WEAPON = BOWLINGBALL_WEAPON__STATIC; +int32_t MOTORCYCLE_WEAPON = MOTORCYCLE_WEAPON__STATIC; +int32_t BOAT_WEAPON = BOAT_WEAPON__STATIC; +int32_t SLINGBLADE_WEAPON = SLINGBLADE_WEAPON__STATIC; +int32_t CHICKEN_WEAPON = CHICKEN_WEAPON__STATIC; + +// This is run after all CON define's have been processed to set up the +// dynamic->static tile mapping. +void G_InitDynamicTiles(void) +{ + int32_t i; + + Bmemset(DynamicTileMap, 0, sizeof(DynamicTileMap)); + + if (RR) + { + for (i = 0; g_dynTileList[i].staticval >= 0; i++) { + *(g_dynTileList[i].dynvalptr) = -g_dynTileList[i].staticval_rr; + if (RRRA && *(g_dynTileList[i].dynvalptr) == -UFO1__STATICRR) *(g_dynTileList[i].dynvalptr) = -UFO1__STATICRRRA; + DynamicTileMap[*(g_dynTileList[i].dynvalptr)] = g_dynTileList[i].staticval_rr; + NameToTileIndex.Insert(g_dynTileList[i].str, *(g_dynTileList[i].dynvalptr)); + } + for (i = 0; g_dynWeaponList[i].staticval >= 0; i++) + *(g_dynWeaponList[i].dynvalptr) = g_dynWeaponList[i].staticval_rr; + + PHEIGHT = PHEIGHT_RR; + } + + for (i=0; g_dynTileList[i].staticval >= 0; i++) + if (g_dynTileList[i].staticval > 0) + { + DynamicTileMap[*(g_dynTileList[i].dynvalptr)] = g_dynTileList[i].staticval; + NameToTileIndex.Insert(g_dynTileList[i].str, *(g_dynTileList[i].dynvalptr)); + } + + for (i=0; g_dynWeaponList[i].staticval >= 0; i++) + DynamicWeaponMap[*(g_dynWeaponList[i].dynvalptr)] = g_dynWeaponList[i].staticval; + + DynamicTileMap[0] = 0; + + g_blimpSpawnItems[0] = RPGSPRITE; + g_blimpSpawnItems[1] = CHAINGUNSPRITE; + g_blimpSpawnItems[2] = DEVISTATORAMMO; + g_blimpSpawnItems[3] = RPGAMMO; + g_blimpSpawnItems[4] = RPGAMMO; + g_blimpSpawnItems[5] = JETPACK; + g_blimpSpawnItems[6] = SHIELD; + g_blimpSpawnItems[7] = FIRSTAID; + g_blimpSpawnItems[8] = STEROIDS; + g_blimpSpawnItems[9] = RPGAMMO; + g_blimpSpawnItems[10] = RPGAMMO; + g_blimpSpawnItems[11] = RPGSPRITE; + g_blimpSpawnItems[12] = RPGAMMO; + g_blimpSpawnItems[13] = FREEZESPRITE; + g_blimpSpawnItems[14] = FREEZEAMMO; + + if (RR) + { + WeaponPickupSprites[0] = KNEE; + WeaponPickupSprites[1] = FIRSTGUNSPRITE; + WeaponPickupSprites[2] = SHOTGUNSPRITE; + WeaponPickupSprites[3] = CHAINGUNSPRITE; + WeaponPickupSprites[4] = RPGSPRITE; + WeaponPickupSprites[5] = HEAVYHBOMB; + WeaponPickupSprites[6] = SHRINKERSPRITE; + WeaponPickupSprites[7] = DEVISTATORSPRITE; + WeaponPickupSprites[8] = TRIPBOMBSPRITE; + WeaponPickupSprites[9] = BOWLINGBALLSPRITE; + WeaponPickupSprites[10] = FREEZEBLAST; + WeaponPickupSprites[11] = HEAVYHBOMB; + } + else + { + WeaponPickupSprites[0] = KNEE; + WeaponPickupSprites[1] = FIRSTGUNSPRITE; + WeaponPickupSprites[2] = SHOTGUNSPRITE; + WeaponPickupSprites[3] = CHAINGUNSPRITE; + WeaponPickupSprites[4] = RPGSPRITE; + WeaponPickupSprites[5] = HEAVYHBOMB; + WeaponPickupSprites[6] = SHRINKERSPRITE; + WeaponPickupSprites[7] = DEVISTATORSPRITE; + WeaponPickupSprites[8] = TRIPBOMBSPRITE; + WeaponPickupSprites[9] = FREEZESPRITE; + WeaponPickupSprites[10] = HEAVYHBOMB; + WeaponPickupSprites[11] = SHRINKERSPRITE; + } + + // ouch... the big background image takes up a fuckload of memory and takes a second to load! +#ifdef EDUKE32_GLES + MENUSCREEN = LOADSCREEN = BETASCREEN; +#endif +} +END_DUKE_NS diff --git a/source/duke/src/namesdyn.h b/source/duke/src/namesdyn.h new file mode 100644 index 000000000..e92a8a197 --- /dev/null +++ b/source/duke/src/namesdyn.h @@ -0,0 +1,3598 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef namesdyn_h__ +#define namesdyn_h__ + +BEGIN_DUKE_NS + + +#define SECTOREFFECTOR__STATIC 1 +#define ACTIVATOR__STATIC 2 +#define TOUCHPLATE__STATIC 3 +#define ACTIVATORLOCKED__STATIC 4 +#define MUSICANDSFX__STATIC 5 +#define LOCATORS__STATIC 6 +#define CYCLER__STATIC 7 +#define MASTERSWITCH__STATIC 8 +#define RESPAWN__STATIC 9 +#define GPSPEED__STATIC 10 +#define FOF__STATIC 13 +#define ARROW__STATIC 20 +#define FIRSTGUNSPRITE__STATIC 21 +#define CHAINGUNSPRITE__STATIC 22 +#define RPGSPRITE__STATIC 23 +#define FREEZESPRITE__STATIC 24 +#define SHRINKERSPRITE__STATIC 25 +#define HEAVYHBOMB__STATIC 26 +#define TRIPBOMBSPRITE__STATIC 27 +#define SHOTGUNSPRITE__STATIC 28 +#define DEVISTATORSPRITE__STATIC 29 +#define HEALTHBOX__STATIC 30 +#define AMMOBOX__STATIC 31 +#define GROWSPRITEICON__STATIC 32 +#define INVENTORYBOX__STATIC 33 +#define FREEZEAMMO__STATIC 37 +#define AMMO__STATIC 40 +#define BATTERYAMMO__STATIC 41 +#define DEVISTATORAMMO__STATIC 42 +#define RPGAMMO__STATIC 44 +#define GROWAMMO__STATIC 45 +#define CRYSTALAMMO__STATIC 46 +#define HBOMBAMMO__STATIC 47 +#define AMMOLOTS__STATIC 48 +#define SHOTGUNAMMO__STATIC 49 +#define COLA__STATIC 51 +#define SIXPAK__STATIC 52 +#define FIRSTAID__STATIC 53 +#define SHIELD__STATIC 54 +#define STEROIDS__STATIC 55 +#define AIRTANK__STATIC 56 +#define JETPACK__STATIC 57 +#define HEATSENSOR__STATIC 59 +#define ACCESSCARD__STATIC 60 +#define BOOTS__STATIC 61 +#define MIRRORBROKE__STATIC 70 +#define CLOUDYOCEAN__STATIC 78 +#define CLOUDYSKIES__STATIC 79 +#define MOONSKY1__STATIC 80 +#define MOONSKY2__STATIC 81 +#define MOONSKY3__STATIC 82 +#define MOONSKY4__STATIC 83 +#define BIGORBIT1__STATIC 84 +#define BIGORBIT2__STATIC 85 +#define BIGORBIT3__STATIC 86 +#define BIGORBIT4__STATIC 87 +#define BIGORBIT5__STATIC 88 +#define LA__STATIC 89 +#define REDSKY1__STATIC 98 +#define REDSKY2__STATIC 99 +#define ATOMICHEALTH__STATIC 100 +#define TECHLIGHT2__STATIC 120 +#define TECHLIGHTBUST2__STATIC 121 +#define TECHLIGHT4__STATIC 122 +#define TECHLIGHTBUST4__STATIC 123 +#define WALLLIGHT4__STATIC 124 +#define WALLLIGHTBUST4__STATIC 125 +#define ACCESSSWITCH__STATIC 130 +#define SLOTDOOR__STATIC 132 +#define LIGHTSWITCH__STATIC 134 +#define SPACEDOORSWITCH__STATIC 136 +#define SPACELIGHTSWITCH__STATIC 138 +#define FRANKENSTINESWITCH__STATIC 140 +#define NUKEBUTTON__STATIC 142 +#define MULTISWITCH__STATIC 146 +#define DOORTILE5__STATIC 150 +#define DOORTILE6__STATIC 151 +#define DOORTILE1__STATIC 152 +#define DOORTILE2__STATIC 153 +#define DOORTILE3__STATIC 154 +#define DOORTILE4__STATIC 155 +#define DOORTILE7__STATIC 156 +#define DOORTILE8__STATIC 157 +#define DOORTILE9__STATIC 158 +#define DOORTILE10__STATIC 159 +#define DOORSHOCK__STATIC 160 +#define DIPSWITCH__STATIC 162 +#define DIPSWITCH2__STATIC 164 +#define TECHSWITCH__STATIC 166 +#define DIPSWITCH3__STATIC 168 +#define ACCESSSWITCH2__STATIC 170 +#define REFLECTWATERTILE__STATIC 180 +#define FLOORSLIME__STATIC 200 +#define BIGFORCE__STATIC 230 +#define EPISODE__STATIC 247 +#define MASKWALL9__STATIC 255 +#define W_LIGHT__STATIC 260 +#define SCREENBREAK1__STATIC 263 +#define SCREENBREAK2__STATIC 264 +#define SCREENBREAK3__STATIC 265 +#define SCREENBREAK4__STATIC 266 +#define SCREENBREAK5__STATIC 267 +#define SCREENBREAK6__STATIC 268 +#define SCREENBREAK7__STATIC 269 +#define SCREENBREAK8__STATIC 270 +#define SCREENBREAK9__STATIC 271 +#define SCREENBREAK10__STATIC 272 +#define SCREENBREAK11__STATIC 273 +#define SCREENBREAK12__STATIC 274 +#define SCREENBREAK13__STATIC 275 +#define MASKWALL1__STATIC 285 +#define W_TECHWALL1__STATIC 293 +#define W_TECHWALL2__STATIC 297 +#define W_TECHWALL15__STATIC 299 +#define W_TECHWALL3__STATIC 301 +#define W_TECHWALL4__STATIC 305 +#define W_TECHWALL10__STATIC 306 +#define W_TECHWALL16__STATIC 307 +#define WATERTILE2__STATIC 336 +#define BPANNEL1__STATIC 341 +#define PANNEL1__STATIC 342 +#define PANNEL2__STATIC 343 +#define WATERTILE__STATIC 344 +#define STATIC__STATIC 351 +#define W_SCREENBREAK__STATIC 357 +#define W_HITTECHWALL3__STATIC 360 +#define W_HITTECHWALL4__STATIC 361 +#define W_HITTECHWALL2__STATIC 362 +#define W_HITTECHWALL1__STATIC 363 +#define MASKWALL10__STATIC 387 +#define MASKWALL11__STATIC 391 +#define DOORTILE22__STATIC 395 +#define FANSPRITE__STATIC 407 +#define FANSPRITEBROKE__STATIC 411 +#define FANSHADOW__STATIC 412 +#define FANSHADOWBROKE__STATIC 416 +#define DOORTILE18__STATIC 447 +#define DOORTILE19__STATIC 448 +#define DOORTILE20__STATIC 449 +#define SATELLITE__STATIC 489 +#define VIEWSCREEN2__STATIC 499 +#define VIEWSCREENBROKE__STATIC 501 +#define VIEWSCREEN__STATIC 502 +#define GLASS__STATIC 503 +#define GLASS2__STATIC 504 +#define STAINGLASS1__STATIC 510 +#define MASKWALL5__STATIC 514 +#define SATELITE__STATIC 516 +#define FUELPOD__STATIC 517 +#define SLIMEPIPE__STATIC 538 +#define CRACK1__STATIC 546 +#define CRACK2__STATIC 547 +#define CRACK3__STATIC 548 +#define CRACK4__STATIC 549 +#define FOOTPRINTS__STATIC 550 +#define DOMELITE__STATIC 551 +#define CAMERAPOLE__STATIC 554 +#define CHAIR1__STATIC 556 +#define CHAIR2__STATIC 557 +#define BROKENCHAIR__STATIC 559 +#define MIRROR__STATIC 560 +#define WATERFOUNTAIN__STATIC 563 +#define WATERFOUNTAINBROKE__STATIC 567 +#define FEMMAG1__STATIC 568 +#define TOILET__STATIC 569 +#define STALL__STATIC 571 +#define STALLBROKE__STATIC 573 +#define FEMMAG2__STATIC 577 +#define REACTOR2__STATIC 578 +#define REACTOR2BURNT__STATIC 579 +#define REACTOR2SPARK__STATIC 580 +#define GRATE1__STATIC 595 +#define BGRATE1__STATIC 596 +#define SOLARPANNEL__STATIC 602 +#define NAKED1__STATIC 603 +#define ANTENNA__STATIC 607 +#define MASKWALL12__STATIC 609 +#define TOILETBROKE__STATIC 615 +#define PIPE2__STATIC 616 +#define PIPE1B__STATIC 617 +#define PIPE3__STATIC 618 +#define PIPE1__STATIC 619 +#define CAMERA1__STATIC 621 +#define BRICK__STATIC 626 +#define SPLINTERWOOD__STATIC 630 +#define PIPE2B__STATIC 633 +#define BOLT1__STATIC 634 +#define W_NUMBERS__STATIC 640 +#define WATERDRIP__STATIC 660 +#define WATERBUBBLE__STATIC 661 +#define WATERBUBBLEMAKER__STATIC 662 +#define W_FORCEFIELD__STATIC 663 +#define VACUUM__STATIC 669 +#define FOOTPRINTS2__STATIC 672 +#define FOOTPRINTS3__STATIC 673 +#define FOOTPRINTS4__STATIC 674 +#define EGG__STATIC 675 +#define SCALE__STATIC 678 +#define CHAIR3__STATIC 680 +#define CAMERALIGHT__STATIC 685 +#define MOVIECAMERA__STATIC 686 +#define IVUNIT__STATIC 689 +#define POT1__STATIC 694 +#define POT2__STATIC 695 +#define POT3__STATIC 697 +#define PIPE3B__STATIC 700 +#define WALLLIGHT3__STATIC 701 +#define WALLLIGHTBUST3__STATIC 702 +#define WALLLIGHT1__STATIC 703 +#define WALLLIGHTBUST1__STATIC 704 +#define WALLLIGHT2__STATIC 705 +#define WALLLIGHTBUST2__STATIC 706 +#define LIGHTSWITCH2__STATIC 712 +#define WAITTOBESEATED__STATIC 716 +#define DOORTILE14__STATIC 717 +#define STATUE__STATIC 753 +#define MIKE__STATIC 762 +#define VASE__STATIC 765 +#define SUSHIPLATE1__STATIC 768 +#define SUSHIPLATE2__STATIC 769 +#define SUSHIPLATE3__STATIC 774 +#define SUSHIPLATE4__STATIC 779 +#define DOORTILE16__STATIC 781 +#define SUSHIPLATE5__STATIC 792 +#define OJ__STATIC 806 +#define MASKWALL13__STATIC 830 +#define HURTRAIL__STATIC 859 +#define POWERSWITCH1__STATIC 860 +#define LOCKSWITCH1__STATIC 862 +#define POWERSWITCH2__STATIC 864 +#define ATM__STATIC 867 +#define STATUEFLASH__STATIC 869 +#define ATMBROKE__STATIC 888 +#define BIGHOLE2__STATIC 893 +#define STRIPEBALL__STATIC 901 +#define QUEBALL__STATIC 902 +#define POCKET__STATIC 903 +#define WOODENHORSE__STATIC 904 +#define TREE1__STATIC 908 +#define TREE2__STATIC 910 +#define CACTUS__STATIC 911 +#define MASKWALL2__STATIC 913 +#define MASKWALL3__STATIC 914 +#define MASKWALL4__STATIC 915 +#define FIREEXT__STATIC 916 +#define TOILETWATER__STATIC 921 +#define NEON1__STATIC 925 +#define NEON2__STATIC 926 +#define CACTUSBROKE__STATIC 939 +#define BOUNCEMINE__STATIC 940 +#define BROKEFIREHYDRENT__STATIC 950 +#define BOX__STATIC 951 +#define BULLETHOLE__STATIC 952 +#define BOTTLE1__STATIC 954 +#define BOTTLE2__STATIC 955 +#define BOTTLE3__STATIC 956 +#define BOTTLE4__STATIC 957 +#define FEMPIC5__STATIC 963 +#define FEMPIC6__STATIC 964 +#define FEMPIC7__STATIC 965 +#define HYDROPLANT__STATIC 969 +#define OCEANSPRITE1__STATIC 971 +#define OCEANSPRITE2__STATIC 972 +#define OCEANSPRITE3__STATIC 973 +#define OCEANSPRITE4__STATIC 974 +#define OCEANSPRITE5__STATIC 975 +#define GENERICPOLE__STATIC 977 +#define CONE__STATIC 978 +#define HANGLIGHT__STATIC 979 +#define HYDRENT__STATIC 981 +#define MASKWALL14__STATIC 988 +#define TIRE__STATIC 990 +#define PIPE5__STATIC 994 +#define PIPE6__STATIC 995 +#define PIPE4__STATIC 996 +#define PIPE4B__STATIC 997 +#define BROKEHYDROPLANT__STATIC 1003 +#define PIPE5B__STATIC 1005 +#define NEON3__STATIC 1007 +#define NEON4__STATIC 1008 +#define NEON5__STATIC 1009 +#define BOTTLE5__STATIC 1012 +#define BOTTLE6__STATIC 1013 +#define BOTTLE8__STATIC 1014 +#define SPOTLITE__STATIC 1020 +#define HANGOOZ__STATIC 1022 +#define MASKWALL15__STATIC 1024 +#define BOTTLE7__STATIC 1025 +#define HORSEONSIDE__STATIC 1026 +#define GLASSPIECES__STATIC 1031 +#define HORSELITE__STATIC 1034 +#define DONUTS__STATIC 1045 +#define NEON6__STATIC 1046 +#define MASKWALL6__STATIC 1059 +#define CLOCK__STATIC 1060 +#define RUBBERCAN__STATIC 1062 +#define BROKENCLOCK__STATIC 1067 +#define PLUG__STATIC 1069 +#define OOZFILTER__STATIC 1079 +#define FLOORPLASMA__STATIC 1082 +#define REACTOR__STATIC 1088 +#define REACTORSPARK__STATIC 1092 +#define REACTORBURNT__STATIC 1096 +#define DOORTILE15__STATIC 1102 +#define HANDSWITCH__STATIC 1111 +#define CIRCLEPANNEL__STATIC 1113 +#define CIRCLEPANNELBROKE__STATIC 1114 +#define PULLSWITCH__STATIC 1122 +#define MASKWALL8__STATIC 1124 +#define BIGHOLE__STATIC 1141 +#define ALIENSWITCH__STATIC 1142 +#define DOORTILE21__STATIC 1144 +#define HANDPRINTSWITCH__STATIC 1155 +#define BOTTLE10__STATIC 1157 +#define BOTTLE11__STATIC 1158 +#define BOTTLE12__STATIC 1159 +#define BOTTLE13__STATIC 1160 +#define BOTTLE14__STATIC 1161 +#define BOTTLE15__STATIC 1162 +#define BOTTLE16__STATIC 1163 +#define BOTTLE17__STATIC 1164 +#define BOTTLE18__STATIC 1165 +#define BOTTLE19__STATIC 1166 +#define DOORTILE17__STATIC 1169 +#define MASKWALL7__STATIC 1174 +#define JAILBARBREAK__STATIC 1175 +#define DOORTILE11__STATIC 1178 +#define DOORTILE12__STATIC 1179 +#define VENDMACHINE__STATIC 1212 +#define VENDMACHINEBROKE__STATIC 1214 +#define COLAMACHINE__STATIC 1215 +#define COLAMACHINEBROKE__STATIC 1217 +#define CRANEPOLE__STATIC 1221 +#define CRANE__STATIC 1222 +#define BARBROKE__STATIC 1225 +#define BLOODPOOL__STATIC 1226 +#define NUKEBARREL__STATIC 1227 +#define NUKEBARRELDENTED__STATIC 1228 +#define NUKEBARRELLEAKED__STATIC 1229 +#define CANWITHSOMETHING__STATIC 1232 +#define MONEY__STATIC 1233 +#define BANNER__STATIC 1236 +#define EXPLODINGBARREL__STATIC 1238 +#define EXPLODINGBARREL2__STATIC 1239 +#define FIREBARREL__STATIC 1240 +#define SEENINE__STATIC 1247 +#define SEENINEDEAD__STATIC 1248 +#define STEAM__STATIC 1250 +#define CEILINGSTEAM__STATIC 1255 +#define PIPE6B__STATIC 1260 +#define TRANSPORTERBEAM__STATIC 1261 +#define RAT__STATIC 1267 +#define TRASH__STATIC 1272 +#define FEMPIC1__STATIC 1280 +#define FEMPIC2__STATIC 1289 +#define BLANKSCREEN__STATIC 1293 +#define PODFEM1__STATIC 1294 +#define FEMPIC3__STATIC 1298 +#define FEMPIC4__STATIC 1306 +#define FEM1__STATIC 1312 +#define FEM2__STATIC 1317 +#define FEM3__STATIC 1321 +#define FEM5__STATIC 1323 +#define BLOODYPOLE__STATIC 1324 +#define FEM4__STATIC 1325 +#define FEM6__STATIC 1334 +#define FEM6PAD__STATIC 1335 +#define FEM8__STATIC 1336 +#define HELECOPT__STATIC 1346 +#define FETUSJIB__STATIC 1347 +#define HOLODUKE__STATIC 1348 +#define SPACEMARINE__STATIC 1353 +#define INDY__STATIC 1355 +#define FETUS__STATIC 1358 +#define FETUSBROKE__STATIC 1359 +#define MONK__STATIC 1352 +#define LUKE__STATIC 1354 +#define COOLEXPLOSION1__STATIC 1360 +#define WATERSPLASH2__STATIC 1380 +#define FIREVASE__STATIC 1390 +#define SCRATCH__STATIC 1393 +#define FEM7__STATIC 1395 +#define APLAYERTOP__STATIC 1400 +#define APLAYER__STATIC 1405 +#define PLAYERONWATER__STATIC 1420 +#define DUKELYINGDEAD__STATIC 1518 +#define DUKETORSO__STATIC 1520 +#define DUKEGUN__STATIC 1528 +#define DUKELEG__STATIC 1536 +#define SHARK__STATIC 1550 +#define BLOOD__STATIC 1620 +#define FIRELASER__STATIC 1625 +#define TRANSPORTERSTAR__STATIC 1630 +#define SPIT__STATIC 1636 +#define LOOGIE__STATIC 1637 +#define FIST__STATIC 1640 +#define FREEZEBLAST__STATIC 1641 +#define DEVISTATORBLAST__STATIC 1642 +#define SHRINKSPARK__STATIC 1646 +#define TONGUE__STATIC 1647 +#define MORTER__STATIC 1650 +#define SHRINKEREXPLOSION__STATIC 1656 +#define RADIUSEXPLOSION__STATIC 1670 +#define FORCERIPPLE__STATIC 1671 +#define LIZTROOP__STATIC 1680 +#define LIZTROOPRUNNING__STATIC 1681 +#define LIZTROOPSTAYPUT__STATIC 1682 +#define LIZTOP__STATIC 1705 +#define LIZTROOPSHOOT__STATIC 1715 +#define LIZTROOPJETPACK__STATIC 1725 +#define LIZTROOPDSPRITE__STATIC 1734 +#define LIZTROOPONTOILET__STATIC 1741 +#define LIZTROOPJUSTSIT__STATIC 1742 +#define LIZTROOPDUCKING__STATIC 1744 +#define HEADJIB1__STATIC 1768 +#define ARMJIB1__STATIC 1772 +#define LEGJIB1__STATIC 1776 +#define CANNONBALL__STATIC 1817 +#define OCTABRAIN__STATIC 1820 +#define OCTABRAINSTAYPUT__STATIC 1821 +#define OCTATOP__STATIC 1845 +#define OCTADEADSPRITE__STATIC 1855 +#define INNERJAW__STATIC 1860 +#define DRONE__STATIC 1880 +#define EXPLOSION2__STATIC 1890 +#define COMMANDER__STATIC 1920 +#define COMMANDERSTAYPUT__STATIC 1921 +#define RECON__STATIC 1960 +#define TANK__STATIC 1975 +#define PIGCOP__STATIC 2000 +#define PIGCOPSTAYPUT__STATIC 2001 +#define PIGCOPDIVE__STATIC 2045 +#define PIGCOPDEADSPRITE__STATIC 2060 +#define PIGTOP__STATIC 2061 +#define LIZMAN__STATIC 2120 +#define LIZMANSTAYPUT__STATIC 2121 +#define LIZMANSPITTING__STATIC 2150 +#define LIZMANFEEDING__STATIC 2160 +#define LIZMANJUMP__STATIC 2165 +#define LIZMANDEADSPRITE__STATIC 2185 +#define FECES__STATIC 2200 +#define LIZMANHEAD1__STATIC 2201 +#define LIZMANARM1__STATIC 2205 +#define LIZMANLEG1__STATIC 2209 +#define EXPLOSION2BOT__STATIC 2219 +#define USERWEAPON__STATIC 2235 +#define HEADERBAR__STATIC 2242 +#define JIBS1__STATIC 2245 +#define JIBS2__STATIC 2250 +#define JIBS3__STATIC 2255 +#define JIBS4__STATIC 2260 +#define JIBS5__STATIC 2265 +#define BURNING__STATIC 2270 +#define FIRE__STATIC 2271 +#define JIBS6__STATIC 2286 +#define BLOODSPLAT1__STATIC 2296 +#define BLOODSPLAT3__STATIC 2297 +#define BLOODSPLAT2__STATIC 2298 +#define BLOODSPLAT4__STATIC 2299 +#define OOZ__STATIC 2300 +#define OOZ2__STATIC 2309 +#define WALLBLOOD1__STATIC 2301 +#define WALLBLOOD2__STATIC 2302 +#define WALLBLOOD3__STATIC 2303 +#define WALLBLOOD4__STATIC 2304 +#define WALLBLOOD5__STATIC 2305 +#define WALLBLOOD6__STATIC 2306 +#define WALLBLOOD7__STATIC 2307 +#define WALLBLOOD8__STATIC 2308 +#define BURNING2__STATIC 2310 +#define FIRE2__STATIC 2311 +#define CRACKKNUCKLES__STATIC 2324 +#define SMALLSMOKE__STATIC 2329 +#define SMALLSMOKEMAKER__STATIC 2330 +#define FLOORFLAME__STATIC 2333 +#define ROTATEGUN__STATIC 2360 +#define GREENSLIME__STATIC 2370 +#define WATERDRIPSPLASH__STATIC 2380 +#define SCRAP6__STATIC 2390 +#define SCRAP1__STATIC 2400 +#define SCRAP2__STATIC 2404 +#define SCRAP3__STATIC 2408 +#define SCRAP4__STATIC 2412 +#define SCRAP5__STATIC 2416 +#define ORGANTIC__STATIC 2420 +#define BETAVERSION__STATIC 2440 +#define PLAYERISHERE__STATIC 2442 +#define PLAYERWASHERE__STATIC 2443 +#define SELECTDIR__STATIC 2444 +#define F1HELP__STATIC 2445 +#define NOTCHON__STATIC 2446 +#define NOTCHOFF__STATIC 2447 +#define GROWSPARK__STATIC 2448 +#define DUKEICON__STATIC 2452 +#define BADGUYICON__STATIC 2453 +#define FOODICON__STATIC 2454 +#define GETICON__STATIC 2455 +#define MENUSCREEN__STATIC 2456 +#define MENUBAR__STATIC 2457 +#define KILLSICON__STATIC 2458 +#define FIRSTAID_ICON__STATIC 2460 +#define HEAT_ICON__STATIC 2461 +#define BOTTOMSTATUSBAR__STATIC 2462 +#define BOOT_ICON__STATIC 2463 +#define FRAGBAR__STATIC 2465 +#define JETPACK_ICON__STATIC 2467 +#define AIRTANK_ICON__STATIC 2468 +#define STEROIDS_ICON__STATIC 2469 +#define HOLODUKE_ICON__STATIC 2470 +#define ACCESS_ICON__STATIC 2471 +#define DIGITALNUM__STATIC 2472 +#define DUKECAR__STATIC 2491 +#define CAMCORNER__STATIC 2482 +#define CAMLIGHT__STATIC 2484 +#define LOGO__STATIC 2485 +#define TITLE__STATIC 2486 +#define NUKEWARNINGICON__STATIC 2487 +#define MOUSECURSOR__STATIC 2488 +#define SLIDEBAR__STATIC 2489 +#define DREALMS__STATIC 2492 +#define BETASCREEN__STATIC 2493 +#define WINDOWBORDER1__STATIC 2494 +#define TEXTBOX__STATIC 2495 +#define WINDOWBORDER2__STATIC 2496 +#define DUKENUKEM__STATIC 2497 +#define THREEDEE__STATIC 2498 +#define INGAMEDUKETHREEDEE__STATIC 2499 +#define TENSCREEN__STATIC 2500 +#define PLUTOPAKSPRITE__STATIC 2501 +#define DEVISTATOR__STATIC 2510 +#define KNEE__STATIC 2521 +#define CROSSHAIR__STATIC 2523 +#define FIRSTGUN__STATIC 2524 +#define FIRSTGUNRELOAD__STATIC 2528 +#define FALLINGCLIP__STATIC 2530 +#define CLIPINHAND__STATIC 2531 +#define HAND__STATIC 2532 +#define SHELL__STATIC 2533 +#define SHOTGUNSHELL__STATIC 2535 +#define CHAINGUN__STATIC 2536 +#define RPGGUN__STATIC 2544 +#define RPGMUZZLEFLASH__STATIC 2545 +#define FREEZE__STATIC 2548 +#define CATLITE__STATIC 2552 +#define SHRINKER__STATIC 2556 +#define HANDHOLDINGLASER__STATIC 2563 +#define TRIPBOMB__STATIC 2566 +#define LASERLINE__STATIC 2567 +#define HANDHOLDINGACCESS__STATIC 2568 +#define HANDREMOTE__STATIC 2570 +#define HANDTHROW__STATIC 2573 +#define TIP__STATIC 2576 +#define GLAIR__STATIC 2578 +#define SCUBAMASK__STATIC 2581 +#define SPACEMASK__STATIC 2584 +#define FORCESPHERE__STATIC 2590 +#define SHOTSPARK1__STATIC 2595 +#define RPG__STATIC 2605 +#define LASERSITE__STATIC 2612 +#define SHOTGUN__STATIC 2613 +#define BOSS1__STATIC 2630 +#define BOSS1STAYPUT__STATIC 2631 +#define BOSS1SHOOT__STATIC 2660 +#define BOSS1LOB__STATIC 2670 +#define BOSSTOP__STATIC 2696 +#define BOSS2__STATIC 2710 +#define BOSS3__STATIC 2760 +#define SPINNINGNUKEICON__STATIC 2813 +#define BIGFNTCURSOR__STATIC 2820 +#define SMALLFNTCURSOR__STATIC 2821 +#define STARTALPHANUM__STATIC 2822 +#define ENDALPHANUM__STATIC 2915 +#define BIGALPHANUM__STATIC 2940 +#define BIGPERIOD__STATIC 3002 +#define BIGCOMMA__STATIC 3003 +#define BIGX__STATIC 3004 +#define BIGQ__STATIC 3005 +#define BIGSEMI__STATIC 3006 +#define BIGCOLIN__STATIC 3007 +#define THREEBYFIVE__STATIC 3010 +#define BIGAPPOS__STATIC 3022 +#define BLANK__STATIC 3026 +#define MINIFONT__STATIC 3072 +#define BUTTON1__STATIC 3164 +#define GLASS3__STATIC 3187 +#define RESPAWNMARKERRED__STATIC 3190 +#define RESPAWNMARKERYELLOW__STATIC 3200 +#define RESPAWNMARKERGREEN__STATIC 3210 +#define BONUSSCREEN__STATIC 3240 +#define VIEWBORDER__STATIC 3250 +#define VICTORY1__STATIC 3260 +#define ORDERING__STATIC 3270 +#define TEXTSTORY__STATIC 3280 +#define LOADSCREEN__STATIC 3281 +#define BORNTOBEWILDSCREEN__STATIC 3370 +#define BLIMP__STATIC 3400 +#define FEM9__STATIC 3450 +#define FOOTPRINT__STATIC 3701 +#define POOP__STATIC 4094 +#define FRAMEEFFECT1__STATIC 4095 +#define PANNEL3__STATIC 4099 +#define SCREENBREAK14__STATIC 4120 +#define SCREENBREAK15__STATIC 4123 +#define SCREENBREAK19__STATIC 4125 +#define SCREENBREAK16__STATIC 4127 +#define SCREENBREAK17__STATIC 4128 +#define SCREENBREAK18__STATIC 4129 +#define W_TECHWALL11__STATIC 4130 +#define W_TECHWALL12__STATIC 4131 +#define W_TECHWALL13__STATIC 4132 +#define W_TECHWALL14__STATIC 4133 +#define W_TECHWALL5__STATIC 4134 +#define W_TECHWALL6__STATIC 4136 +#define W_TECHWALL7__STATIC 4138 +#define W_TECHWALL8__STATIC 4140 +#define W_TECHWALL9__STATIC 4142 +#define BPANNEL3__STATIC 4100 +#define W_HITTECHWALL16__STATIC 4144 +#define W_HITTECHWALL10__STATIC 4145 +#define W_HITTECHWALL15__STATIC 4147 +#define W_MILKSHELF__STATIC 4181 +#define W_MILKSHELFBROKE__STATIC 4203 +#define PURPLELAVA__STATIC 4240 +#define LAVABUBBLE__STATIC 4340 +#define DUKECUTOUT__STATIC 4352 +#define TARGET__STATIC 4359 +#define GUNPOWDERBARREL__STATIC 4360 +#define DUCK__STATIC 4361 +#define HATRACK__STATIC 4367 +#define DESKLAMP__STATIC 4370 +#define COFFEEMACHINE__STATIC 4372 +#define CUPS__STATIC 4373 +#define GAVALS__STATIC 4374 +#define GAVALS2__STATIC 4375 +#define POLICELIGHTPOLE__STATIC 4377 +#define FLOORBASKET__STATIC 4388 +#define PUKE__STATIC 4389 +#define DOORTILE23__STATIC 4391 +#define TOPSECRET__STATIC 4396 +#define SPEAKER__STATIC 4397 +#define TEDDYBEAR__STATIC 4400 +#define ROBOTDOG__STATIC 4402 +#define ROBOTPIRATE__STATIC 4404 +#define ROBOTMOUSE__STATIC 4407 +#define MAIL__STATIC 4410 +#define MAILBAG__STATIC 4413 +#define HOTMEAT__STATIC 4427 +#define COFFEEMUG__STATIC 4438 +#define DONUTS2__STATIC 4440 +#define TRIPODCAMERA__STATIC 4444 +#define METER__STATIC 4453 +#define DESKPHONE__STATIC 4454 +#define GUMBALLMACHINE__STATIC 4458 +#define GUMBALLMACHINEBROKE__STATIC 4459 +#define PAPER__STATIC 4460 +#define MACE__STATIC 4464 +#define GENERICPOLE2__STATIC 4465 +#define XXXSTACY__STATIC 4470 +#define WETFLOOR__STATIC 4495 +#define BROOM__STATIC 4496 +#define MOP__STATIC 4497 +#define LETTER__STATIC 4502 +#define PIRATE1A__STATIC 4510 +#define PIRATE4A__STATIC 4511 +#define PIRATE2A__STATIC 4512 +#define PIRATE5A__STATIC 4513 +#define PIRATE3A__STATIC 4514 +#define PIRATE6A__STATIC 4515 +#define PIRATEHALF__STATIC 4516 +#define CHESTOFGOLD__STATIC 4520 +#define SIDEBOLT1__STATIC 4525 +#define FOODOBJECT1__STATIC 4530 +#define FOODOBJECT2__STATIC 4531 +#define FOODOBJECT3__STATIC 4532 +#define FOODOBJECT4__STATIC 4533 +#define FOODOBJECT5__STATIC 4534 +#define FOODOBJECT6__STATIC 4535 +#define FOODOBJECT7__STATIC 4536 +#define FOODOBJECT8__STATIC 4537 +#define FOODOBJECT9__STATIC 4538 +#define FOODOBJECT10__STATIC 4539 +#define FOODOBJECT11__STATIC 4540 +#define FOODOBJECT12__STATIC 4541 +#define FOODOBJECT13__STATIC 4542 +#define FOODOBJECT14__STATIC 4543 +#define FOODOBJECT15__STATIC 4544 +#define FOODOBJECT16__STATIC 4545 +#define FOODOBJECT17__STATIC 4546 +#define FOODOBJECT18__STATIC 4547 +#define FOODOBJECT19__STATIC 4548 +#define FOODOBJECT20__STATIC 4549 +#define HEADLAMP__STATIC 4550 +#define TAMPON__STATIC 4557 +#define SKINNEDCHICKEN__STATIC 4554 +#define FEATHEREDCHICKEN__STATIC 4555 +#define ROBOTDOG2__STATIC 4560 +#define JOLLYMEAL__STATIC 4569 +#define DUKEBURGER__STATIC 4570 +#define SHOPPINGCART__STATIC 4576 +#define CANWITHSOMETHING2__STATIC 4580 +#define CANWITHSOMETHING3__STATIC 4581 +#define CANWITHSOMETHING4__STATIC 4582 +#define SNAKEP__STATIC 4590 +#define DOLPHIN1__STATIC 4591 +#define DOLPHIN2__STATIC 4592 +#define NEWBEAST__STATIC 4610 +#define NEWBEASTSTAYPUT__STATIC 4611 +#define NEWBEASTJUMP__STATIC 4690 +#define NEWBEASTHANG__STATIC 4670 +#define NEWBEASTHANGDEAD__STATIC 4671 +#define BOSS4__STATIC 4740 +#define BOSS4STAYPUT__STATIC 4741 +#define FEM10__STATIC 4864 +#define TOUGHGAL__STATIC 4866 +#define MAN__STATIC 4871 +#define MAN2__STATIC 4872 +#define WOMAN__STATIC 4874 +#define PLEASEWAIT__STATIC 4887 +#define NATURALLIGHTNING__STATIC 4890 +#define WEATHERWARN__STATIC 4893 +#define DUKETAG__STATIC 4900 +#define SIGN1__STATIC 4909 +#define SIGN2__STATIC 4912 +#define JURYGUY__STATIC 4943 + +#define SECTOREFFECTOR__STATICRR -1 +#define ACTIVATOR__STATICRR -2 +#define TOUCHPLATE__STATICRR -3 +#define ACTIVATORLOCKED__STATICRR -4 +#define MUSICANDSFX__STATICRR -5 +#define LOCATORS__STATICRR -6 +#define CYCLER__STATICRR -7 +#define MASTERSWITCH__STATICRR -8 +#define RESPAWN__STATICRR -9 +#define GPSPEED__STATICRR -10 +#define FOF__STATICRR -13 +#define ARROW__STATICRR -20 +#define FIRSTGUNSPRITE__STATICRR -21 +#define CHAINGUNSPRITE__STATICRR -22 +#define RPGSPRITE__STATICRR -23 +#define FREEZESPRITE__STATICRR -24 +#define SHRINKERSPRITE__STATICRR -25 +#define HEAVYHBOMB__STATICRR -26 +#define TRIPBOMBSPRITE__STATICRR -27 +#define SHOTGUNSPRITE__STATICRR -28 +#define DEVISTATORSPRITE__STATICRR -29 +#define HEALTHBOX__STATICRR -30 +#define AMMOBOX__STATICRR -31 +#define GROWSPRITEICON__STATICRR -32 +#define INVENTORYBOX__STATICRR -33 +#define FREEZEAMMO__STATICRR -37 +#define AMMO__STATICRR -40 +#define BATTERYAMMO__STATICRR -41 +#define DEVISTATORAMMO__STATICRR -42 +#define RPGAMMO__STATICRR -44 +#define GROWAMMO__STATICRR -45 +#define CRYSTALAMMO__STATICRR -46 +#define HBOMBAMMO__STATICRR -47 +#define AMMOLOTS__STATICRR -48 +#define SHOTGUNAMMO__STATICRR -49 +#define COLA__STATICRR -51 +#define SIXPAK__STATICRR -52 +#define FIRSTAID__STATICRR -53 +#define SHIELD__STATICRR -54 +#define STEROIDS__STATICRR -55 +#define AIRTANK__STATICRR -56 +#define JETPACK__STATICRR -57 +#define HEATSENSOR__STATICRR -59 +#define ACCESSCARD__STATICRR -60 +#define BOOTS__STATICRR -61 +#define MIRRORBROKE__STATICRR -70 +#define CLOUDYSKIES__STATICRR -1021 +#define MOONSKY1__STATICRR -1022 +#define MOONSKY2__STATICRR -1023 +#define MOONSKY3__STATICRR -1024 +#define MOONSKY4__STATICRR -1025 +#define BIGORBIT1__STATICRR -1026 +#define BIGORBIT2__STATICRR -1027 +#define BIGORBIT3__STATICRR -1028 +#define BIGORBIT4__STATICRR -1029 +#define BIGORBIT5__STATICRR -1030 +#define LA__STATICRR -1031 +#define REDSKY1__STATICRR -1040 +#define REDSKY2__STATICRR -1041 +#define ATOMICHEALTH__STATICRR -5595 +#define TECHLIGHT2__STATICRR -72 +#define TECHLIGHTBUST2__STATICRR -73 +#define TECHLIGHT4__STATICRR -74 +#define TECHLIGHTBUST4__STATICRR -75 +#define WALLLIGHT4__STATICRR -76 +#define WALLLIGHTBUST4__STATICRR -77 +#define ACCESSSWITCH__STATICRR -82 +#define SLOTDOOR__STATICRR -84 +#define LIGHTSWITCH__STATICRR -86 +#define SPACEDOORSWITCH__STATICRR -88 +#define SPACELIGHTSWITCH__STATICRR -90 +#define FRANKENSTINESWITCH__STATICRR -92 +#define NUKEBUTTON__STATICRR -94 +#define MULTISWITCH__STATICRR -98 +#define DOORTILE5__STATICRR -106 +#define DOORTILE6__STATICRR -107 +#define DOORTILE1__STATICRR -102 +#define DOORTILE2__STATICRR -103 +#define DOORTILE3__STATICRR -104 +#define DOORTILE4__STATICRR -105 +#define DOORTILE7__STATICRR -108 +#define DOORTILE8__STATICRR -109 +#define DOORTILE9__STATICRR -110 +#define DOORTILE10__STATICRR -111 +#define DOORSHOCK__STATICRR -120 +#define DIPSWITCH__STATICRR -121 +#define DIPSWITCH2__STATICRR -123 +#define TECHSWITCH__STATICRR -125 +#define DIPSWITCH3__STATICRR -127 +#define ACCESSSWITCH2__STATICRR -129 +#define REFLECTWATERTILE__STATICRR -131 +#define FLOORSLIME__STATICRR -132 +#define BIGFORCE__STATICRR -135 +#define EPISODE__STATICRR -137 +#define MASKWALL9__STATICRR -147 +#define W_LIGHT__STATICRR -156 +#define SCREENBREAK1__STATICRR -159 +#define SCREENBREAK2__STATICRR -160 +#define SCREENBREAK3__STATICRR -161 +#define SCREENBREAK4__STATICRR -162 +#define SCREENBREAK5__STATICRR -163 +#define SCREENBREAK6__STATICRR -164 +#define SCREENBREAK7__STATICRR -165 +#define SCREENBREAK8__STATICRR -166 +#define SCREENBREAK9__STATICRR -167 +#define SCREENBREAK10__STATICRR -168 +#define SCREENBREAK11__STATICRR -169 +#define SCREENBREAK12__STATICRR -170 +#define SCREENBREAK13__STATICRR -171 +#define MASKWALL1__STATICRR -138 +#define W_TECHWALL1__STATICRR -185 +#define W_TECHWALL2__STATICRR -186 +#define W_TECHWALL15__STATICRR -191 +#define W_TECHWALL3__STATICRR -187 +#define W_TECHWALL4__STATICRR -188 +#define W_TECHWALL10__STATICRR -189 +#define W_TECHWALL16__STATICRR -192 +#define WATERTILE2__STATICRR -1045 +#define BPANNEL1__STATICRR -3006 +#define PANNEL1__STATICRR -3003 +#define PANNEL2__STATICRR -3004 +#define WATERTILE__STATICRR -1044 +#define STATIC__STATICRR -195 +#define W_SCREENBREAK__STATICRR -199 +#define W_HITTECHWALL3__STATICRR -205 +#define W_HITTECHWALL4__STATICRR -206 +#define W_HITTECHWALL2__STATICRR -207 +#define W_HITTECHWALL1__STATICRR -208 +#define MASKWALL10__STATICRR -148 +#define MASKWALL11__STATICRR -149 +#define DOORTILE22__STATICRR -232 +#define FANSPRITE__STATICRR -210 +#define FANSPRITEBROKE__STATICRR -215 +#define FANSHADOW__STATICRR -216 +#define FANSHADOWBROKE__STATICRR -219 +#define DOORTILE18__STATICRR -119 +#define DOORTILE19__STATICRR -229 +#define DOORTILE20__STATICRR -230 +#define SATELLITE__STATICRR -1049 +#define VIEWSCREEN2__STATICRR -1052 +#define VIEWSCREENBROKE__STATICRR -1054 +#define VIEWSCREEN__STATICRR -1055 +#define GLASS__STATICRR -1056 +#define GLASS2__STATICRR -1057 +#define STAINGLASS1__STATICRR -1063 +#define MASKWALL5__STATICRR -143 +#define SATELITE__STATICRR -1066 +#define FUELPOD__STATICRR -1067 +#define SLIMEPIPE__STATICRR -1070 +#define CRACK1__STATICRR -1075 +#define CRACK2__STATICRR -1076 +#define CRACK3__STATICRR -1077 +#define CRACK4__STATICRR -1078 +#define FOOTPRINTS__STATICRR -1079 +#define DOMELITE__STATICRR -1080 +#define CAMERAPOLE__STATICRR -1083 +#define CHAIR1__STATICRR -1085 +#define CHAIR2__STATICRR -1086 +#define BROKENCHAIR__STATICRR -1088 +#define MIRROR__STATICRR -1089 +#define WATERFOUNTAIN__STATICRR -1092 +#define WATERFOUNTAINBROKE__STATICRR -1096 +#define FEMMAG1__STATICRR -1097 +#define TOILET__STATICRR -1098 +#define STALL__STATICRR -1100 +#define STALLBROKE__STATICRR -1102 +#define FEMMAG2__STATICRR -1106 +#define REACTOR2__STATICRR -1107 +#define REACTOR2BURNT__STATICRR -1108 +#define REACTOR2SPARK__STATICRR -1109 +#define GRATE1__STATICRR -234 +#define BGRATE1__STATICRR -235 +#define SOLARPANNEL__STATICRR -1114 +#define NAKED1__STATICRR -1115 +#define ANTENNA__STATICRR -1117 +#define MASKWALL12__STATICRR -150 +#define TOILETBROKE__STATICRR -1120 +#define PIPE2__STATICRR -1121 +#define PIPE1B__STATICRR -1122 +#define PIPE3__STATICRR -1123 +#define PIPE1__STATICRR -1124 +#define CAMERA1__STATICRR -1134 +#define BRICK__STATICRR -1139 +#define SPLINTERWOOD__STATICRR -237 +#define PIPE2B__STATICRR -1126 +#define BOLT1__STATICRR -1127 +#define W_NUMBERS__STATICRR -810 +#define WATERDRIP__STATICRR -239 +#define WATERBUBBLE__STATICRR -240 +#define WATERBUBBLEMAKER__STATICRR -241 +#define W_FORCEFIELD__STATICRR -242 +#define VACUUM__STATICRR -1141 +#define FOOTPRINTS2__STATICRR -1144 +#define FOOTPRINTS3__STATICRR -1145 +#define FOOTPRINTS4__STATICRR -1146 +#define EGG__STATICRR -1147 +#define SCALE__STATICRR -1150 +#define CHAIR3__STATICRR -1152 +#define CAMERALIGHT__STATICRR -1157 +#define MOVIECAMERA__STATICRR -1158 +#define IVUNIT__STATICRR -1163 +#define POT1__STATICRR -1164 +#define POT2__STATICRR -1165 +#define POT3__STATICRR -1166 +#define PIPE3B__STATICRR -1132 +#define WALLLIGHT3__STATICRR -244 +#define WALLLIGHTBUST3__STATICRR -245 +#define WALLLIGHT1__STATICRR -246 +#define WALLLIGHTBUST1__STATICRR -247 +#define WALLLIGHT2__STATICRR -248 +#define WALLLIGHTBUST2__STATICRR -249 +#define LIGHTSWITCH2__STATICRR -250 +#define WAITTOBESEATED__STATICRR -2215 +#define DOORTILE14__STATICRR -115 +#define STATUE__STATICRR -1168 +#define MIKE__STATICRR -1170 +#define VASE__STATICRR -1172 +#define SUSHIPLATE1__STATICRR -1174 +#define SUSHIPLATE2__STATICRR -1175 +#define SUSHIPLATE3__STATICRR -1176 +#define SUSHIPLATE4__STATICRR -1178 +#define DOORTILE16__STATICRR -117 +#define SUSHIPLATE5__STATICRR -1180 +#define OJ__STATICRR -2217 +#define MASKWALL13__STATICRR -151 +#define HURTRAIL__STATICRR -2221 +#define POWERSWITCH1__STATICRR -2222 +#define LOCKSWITCH1__STATICRR -2224 +#define POWERSWITCH2__STATICRR -2226 +#define ATM__STATICRR -2229 +#define STATUEFLASH__STATICRR -2231 +#define ATMBROKE__STATICRR -2233 +#define BIGHOLE2__STATICRR -1182 +#define STRIPEBALL__STATICRR -1184 +#define QUEBALL__STATICRR -1185 +#define POCKET__STATICRR -1186 +#define WOODENHORSE__STATICRR -1187 +#define TREE1__STATICRR -1191 +#define TREE2__STATICRR -1193 +#define CACTUS__STATICRR -1194 +#define MASKWALL2__STATICRR -140 +#define MASKWALL3__STATICRR -141 +#define MASKWALL4__STATICRR -142 +#define FIREEXT__STATICRR -155 +#define TOILETWATER__STATICRR -1196 +#define NEON1__STATICRR -1200 +#define NEON2__STATICRR -1201 +#define CACTUSBROKE__STATICRR -1203 +#define BOUNCEMINE__STATICRR -1204 +#define BROKEFIREHYDRENT__STATICRR -1210 +#define BOX__STATICRR -1211 +#define BULLETHOLE__STATICRR -1212 +#define BOTTLE1__STATICRR -1215 +#define BOTTLE2__STATICRR -1216 +#define BOTTLE3__STATICRR -1217 +#define BOTTLE4__STATICRR -1218 +#define FEMPIC5__STATICRR -2235 +#define FEMPIC6__STATICRR -2236 +#define FEMPIC7__STATICRR -2237 +#define HYDROPLANT__STATICRR -3053 +#define OCEANSPRITE1__STATICRR -3055 +#define OCEANSPRITE2__STATICRR -3056 +#define OCEANSPRITE3__STATICRR -3057 +#define OCEANSPRITE4__STATICRR -3058 +#define OCEANSPRITE5__STATICRR -3059 +#define GENERICPOLE__STATICRR -3061 +#define CONE__STATICRR -3062 +#define HANGLIGHT__STATICRR -3063 +#define HYDRENT__STATICRR -1228 +#define MASKWALL14__STATICRR -152 +#define TIRE__STATICRR -1230 +#define PIPE5__STATICRR -1232 +#define PIPE6__STATICRR -1233 +#define PIPE4__STATICRR -1234 +#define PIPE4B__STATICRR -1235 +#define BROKEHYDROPLANT__STATICRR -1237 +#define PIPE5B__STATICRR -1239 +#define NEON3__STATICRR -1241 +#define NEON4__STATICRR -1242 +#define NEON5__STATICRR -1243 +#define BOTTLE5__STATICRR -1219 +#define BOTTLE6__STATICRR -1220 +#define BOTTLE8__STATICRR -1222 +#define SPOTLITE__STATICRR -1247 +#define HANGOOZ__STATICRR -1249 +#define MASKWALL15__STATICRR -153 +#define BOTTLE7__STATICRR -1221 +#define HORSEONSIDE__STATICRR -1251 +#define GLASSPIECES__STATICRR -1256 +#define HORSELITE__STATICRR -1259 +#define DONUTS__STATICRR -1263 +#define NEON6__STATICRR -1264 +#define MASKWALL6__STATICRR -144 +#define CLOCK__STATICRR -1266 +#define RUBBERCAN__STATICRR -1268 +#define BROKENCLOCK__STATICRR -1270 +#define PLUG__STATICRR -1272 +#define OOZFILTER__STATICRR -1273 +#define FLOORPLASMA__STATICRR -1276 +#define REACTOR__STATICRR -2239 +#define REACTORSPARK__STATICRR -2243 +#define REACTORBURNT__STATICRR -2247 +#define DOORTILE15__STATICRR -116 +#define HANDSWITCH__STATICRR -2249 +#define CIRCLEPANNEL__STATICRR -2251 +#define CIRCLEPANNELBROKE__STATICRR -2252 +#define PULLSWITCH__STATICRR -2254 +#define MASKWALL8__STATICRR -146 +#define BIGHOLE__STATICRR -3822 +#define ALIENSWITCH__STATICRR -2259 +#define DOORTILE21__STATICRR -2261 +#define HANDPRINTSWITCH__STATICRR -1278 +#define BOTTLE10__STATICRR -1280 +#define BOTTLE11__STATICRR -1281 +#define BOTTLE12__STATICRR -1282 +#define BOTTLE13__STATICRR -1283 +#define BOTTLE14__STATICRR -1284 +#define BOTTLE15__STATICRR -1285 +#define BOTTLE16__STATICRR -1286 +#define BOTTLE17__STATICRR -1287 +#define BOTTLE18__STATICRR -1288 +#define BOTTLE19__STATICRR -1289 +#define DOORTILE17__STATICRR -2263 +#define MASKWALL7__STATICRR -2264 +#define JAILBARBREAK__STATICRR -2265 +#define DOORTILE11__STATICRR -2267 +#define DOORTILE12__STATICRR -2268 +#define VENDMACHINE__STATICRR -1291 +#define VENDMACHINEBROKE__STATICRR -1293 +#define COLAMACHINE__STATICRR -1294 +#define COLAMACHINEBROKE__STATICRR -1296 +#define CRANEPOLE__STATICRR -1298 +#define CRANE__STATICRR -1299 +#define BARBROKE__STATICRR -1302 +#define BLOODPOOL__STATICRR -1303 +#define NUKEBARREL__STATICRR -1304 +#define NUKEBARRELDENTED__STATICRR -1305 +#define NUKEBARRELLEAKED__STATICRR -1306 +#define CANWITHSOMETHING__STATICRR -1309 +#define MONEY__STATICRR -1310 +#define BANNER__STATICRR -1313 +#define EXPLODINGBARREL__STATICRR -1315 +#define EXPLODINGBARREL2__STATICRR -1316 +#define FIREBARREL__STATICRR -1317 +#define SEENINE__STATICRR -1324 +#define SEENINEDEAD__STATICRR -1325 +#define STEAM__STATICRR -1327 +#define CEILINGSTEAM__STATICRR -1332 +#define PIPE6B__STATICRR -1337 +#define TRANSPORTERBEAM__STATICRR -1338 +#define RAT__STATICRR -1344 +#define TRASH__STATICRR -1346 +#define FEMPIC1__STATICRR -3239 +#define FEMPIC2__STATICRR -3248 +#define BLANKSCREEN__STATICRR -3252 +#define PODFEM1__STATICRR -3253 +#define FEMPIC3__STATICRR -3257 +#define FEMPIC4__STATICRR -3265 +#define FEM1__STATICRR -3271 +#define FEM2__STATICRR -3276 +#define FEM3__STATICRR -3280 +#define FEM5__STATICRR -3282 +#define BLOODYPOLE__STATICRR -3283 +#define FEM4__STATICRR -3284 +#define FEM6__STATICRR -3293 +#define FEM6PAD__STATICRR -3294 +#define FEM8__STATICRR -3295 +#define HELECOPT__STATICRR -1348 +#define FETUSJIB__STATICRR -1349 +#define HOLODUKE__STATICRR -1350 +#define SPACEMARINE__STATICRR -1355 +#define INDY__STATICRR -1357 +#define FETUS__STATICRR -1360 +#define FETUSBROKE__STATICRR -1361 +#define MONK__STATICRR -1354 +#define LUKE__STATICRR -1356 +#define COOLEXPLOSION1__STATICRR -2095 +#define WATERSPLASH2__STATICRR -1383 +#define FIREVASE__STATICRR -1388 +#define SCRATCH__STATICRR -1389 +#define FEM7__STATICRR -3298 +#define APLAYERTOP__STATICRR -3840 +#define APLAYER__STATICRR -3845 +#define PLAYERONWATER__STATICRR -3860 +#define DUKELYINGDEAD__STATICRR -3998 +#define DUKETORSO__STATICRR -4046 +#define DUKEGUN__STATICRR -4041 +#define DUKELEG__STATICRR -4055 +#define SHARK__STATICRR -5501 +#define BLOOD__STATICRR -1391 +#define FIRELASER__STATICRR -3420 +#define TRANSPORTERSTAR__STATICRR -1398 +#define SPIT__STATICRR -3390 +#define LOOGIE__STATICRR -1405 +#define FIST__STATICRR -1408 +#define FREEZEBLAST__STATICRR -1409 +#define DEVISTATORBLAST__STATICRR -1410 +#define SHRINKSPARK__STATICRR -3400 +#define TONGUE__STATICRR -1414 +#define MORTER__STATICRR -1416 +#define SHRINKEREXPLOSION__STATICRR -1421 +#define RADIUSEXPLOSION__STATICRR -1426 +#define FORCERIPPLE__STATICRR -1427 +#define CANNONBALL__STATICRR -1437 +#define INNERJAW__STATICRR -1439 +#define DRONE__STATICRR -4916 +#define EXPLOSION2__STATICRR -1441 +#define RECON__STATICRR -4989 +#define FECES__STATICRR -4802 +#define EXPLOSION2BOT__STATICRR -2272 +#define USERWEAPON__STATICRR -1510 +#define HEADERBAR__STATICRR -1493 +#define JIBS1__STATICRR -1463 +#define JIBS2__STATICRR -1468 +#define JIBS3__STATICRR -1473 +#define JIBS4__STATICRR -1478 +#define JIBS5__STATICRR -1483 +#define BURNING__STATICRR -1494 +#define FIRE__STATICRR -1495 +#define JIBS6__STATICRR -1515 +#define BLOODSPLAT1__STATICRR -1525 +#define BLOODSPLAT3__STATICRR -1526 +#define BLOODSPLAT2__STATICRR -1527 +#define BLOODSPLAT4__STATICRR -1528 +#define OOZ__STATICRR -1529 +#define OOZ2__STATICRR -1538 +#define WALLBLOOD1__STATICRR -1530 +#define WALLBLOOD2__STATICRR -1531 +#define WALLBLOOD3__STATICRR -1532 +#define WALLBLOOD4__STATICRR -1533 +#define WALLBLOOD5__STATICRR -1534 +#define WALLBLOOD6__STATICRR -1535 +#define WALLBLOOD7__STATICRR -1536 +#define WALLBLOOD8__STATICRR -1537 +#define BURNING2__STATICRR -1539 +#define FIRE2__STATICRR -1540 +#define CRACKKNUCKLES__STATICRR -1489 +#define SMALLSMOKE__STATICRR -1554 +#define SMALLSMOKEMAKER__STATICRR -1555 +#define FLOORFLAME__STATICRR -1558 +#define ROTATEGUN__STATICRR -1624 +#define GREENSLIME__STATICRR -1575 +#define WATERDRIPSPLASH__STATICRR -1585 +#define SCRAP6__STATICRR -1595 +#define SCRAP1__STATICRR -1605 +#define SCRAP2__STATICRR -1609 +#define SCRAP3__STATICRR -1613 +#define SCRAP4__STATICRR -1617 +#define SCRAP5__STATICRR -1621 +#define ORGANTIC__STATICRR -3308 +#define BETAVERSION__STATICRR -1629 +#define PLAYERISHERE__STATICRR -1630 +#define PLAYERWASHERE__STATICRR -1631 +#define SELECTDIR__STATICRR -1632 +#define F1HELP__STATICRR -1633 +#define NOTCHON__STATICRR -1634 +#define NOTCHOFF__STATICRR -1635 +#define GROWSPARK__STATICRR -3395 +#define DUKEICON__STATICRR -1637 +#define BADGUYICON__STATICRR -1638 +#define FOODICON__STATICRR -1639 +#define GETICON__STATICRR -1640 +#define MENUSCREEN__STATICRR -1641 +#define MENUBAR__STATICRR -1642 +#define KILLSICON__STATICRR -1643 +#define FIRSTAID_ICON__STATICRR -1645 +#define HEAT_ICON__STATICRR -1646 +#define BOTTOMSTATUSBAR__STATICRR -1647 +#define BOOT_ICON__STATICRR -1648 +#define FRAGBAR__STATICRR -1650 +#define JETPACK_ICON__STATICRR -1652 +#define AIRTANK_ICON__STATICRR -1653 +#define STEROIDS_ICON__STATICRR -1654 +#define HOLODUKE_ICON__STATICRR -1655 +#define ACCESS_ICON__STATICRR -1656 +#define DIGITALNUM__STATICRR -1657 +#define DUKECAR__STATICRR -1676 +#define CAMCORNER__STATICRR -1667 +#define CAMLIGHT__STATICRR -1669 +#define LOGO__STATICRR -1670 +#define TITLE__STATICRR -1671 +#define NUKEWARNINGICON__STATICRR -1672 +#define MOUSECURSOR__STATICRR -1673 +#define SLIDEBAR__STATICRR -1674 +#define DREALMS__STATICRR -1677 +#define BETASCREEN__STATICRR -1678 +#define WINDOWBORDER1__STATICRR -1679 +#define TEXTBOX__STATICRR -1680 +#define WINDOWBORDER2__STATICRR -1681 +#define DUKENUKEM__STATICRR -1682 +#define THREEDEE__STATICRR -1683 +#define INGAMEDUKETHREEDEE__STATICRR -1684 +#define TENSCREEN__STATICRR -1685 +#define PLUTOPAKSPRITE__STATICRR -1686 +#define DEVISTATOR__STATICRR -3445 +#define KNEE__STATICRR -3340 +#define CROSSHAIR__STATICRR -1689 +#define FIRSTGUN__STATICRR -3328 +#define FIRSTGUNRELOAD__STATICRR -3336 +#define FALLINGCLIP__STATICRR -1699 +#define CLIPINHAND__STATICRR -1700 +#define HAND__STATICRR -1701 +#define SHELL__STATICRR -1702 +#define SHOTGUNSHELL__STATICRR -1704 +#define CHAINGUN__STATICRR -3380 +#define RPGGUN__STATICRR -3452 +#define RPGMUZZLEFLASH__STATICRR -1714 +#define FREEZE__STATICRR -3415 +#define CATLITE__STATICRR -1721 +#define SHRINKER__STATICRR -3384 +#define HANDHOLDINGLASER__STATICRR -1732 +#define TRIPBOMB__STATICRR -1735 +#define LASERLINE__STATICRR -1736 +#define HANDHOLDINGACCESS__STATICRR -1737 +#define HANDREMOTE__STATICRR -1739 +#define HANDTHROW__STATICRR -3360 +#define TIP__STATICRR -1745 +#define GLAIR__STATICRR -1747 +#define SCUBAMASK__STATICRR -3374 +#define SPACEMASK__STATICRR -1753 +#define FORCESPHERE__STATICRR -1759 +#define SHOTSPARK1__STATICRR -1764 +#define RPG__STATICRR -1774 +#define SHOTGUN__STATICRR -3350 +#define BOSS1__STATICRR -4477 +#define BOSS2__STATICRR -4557 +#define BOSS3__STATICRR -4607 +#define SPINNINGNUKEICON__STATICRR -896 +#define BIGFNTCURSOR__STATICRR -512 +#define SMALLFNTCURSOR__STATICRR -513 +#define STARTALPHANUM__STATICRR -514 +#define ENDALPHANUM__STATICRR -607 +#define BIGALPHANUM__STATICRR -632 +#define BIGPERIOD__STATICRR -694 +#define BIGCOMMA__STATICRR -695 +#define BIGX__STATICRR -696 +#define BIGQ__STATICRR -697 +#define BIGSEMI__STATICRR -698 +#define BIGCOLIN__STATICRR -699 +#define THREEBYFIVE__STATICRR -702 +#define BIGAPPOS__STATICRR -714 +#define BLANK__STATICRR -820 +#define MINIFONT__STATICRR -718 +#define BUTTON1__STATICRR -80 +#define GLASS3__STATICRR -2983 +#define RESPAWNMARKERRED__STATICRR -866 +#define RESPAWNMARKERYELLOW__STATICRR -876 +#define RESPAWNMARKERGREEN__STATICRR -886 +#define BONUSSCREEN__STATICRR -2510 +#define VIEWBORDER__STATICRR -2520 +#define VICTORY1__STATICRR -2530 +#define ORDERING__STATICRR -2531 +#define TEXTSTORY__STATICRR -2541 +#define LOADSCREEN__STATICRR -2542 +#define BORNTOBEWILDSCREEN__STATICRR -2985 +#define BLIMP__STATICRR -2989 +#define FEM9__STATICRR -2991 +#define FOOTPRINT__STATICRR -1160 +#define POOP__STATICRR -2998 +#define FRAMEEFFECT1__STATICRR -2999 +#define PANNEL3__STATICRR -3005 +#define SCREENBREAK14__STATICRR -3008 +#define SCREENBREAK15__STATICRR -3009 +#define SCREENBREAK19__STATICRR -3011 +#define SCREENBREAK16__STATICRR -3013 +#define SCREENBREAK17__STATICRR -3014 +#define SCREENBREAK18__STATICRR -3015 +#define W_TECHWALL11__STATICRR -3016 +#define W_TECHWALL12__STATICRR -3017 +#define W_TECHWALL13__STATICRR -3018 +#define W_TECHWALL14__STATICRR -3019 +#define W_TECHWALL5__STATICRR -3020 +#define W_TECHWALL6__STATICRR -3022 +#define W_TECHWALL7__STATICRR -3024 +#define W_TECHWALL8__STATICRR -3026 +#define W_TECHWALL9__STATICRR -3028 +#define BPANNEL3__STATICRR -3007 +#define W_HITTECHWALL16__STATICRR -3030 +#define W_HITTECHWALL10__STATICRR -3031 +#define W_HITTECHWALL15__STATICRR -3033 +#define W_MILKSHELF__STATICRR -3035 +#define W_MILKSHELFBROKE__STATICRR -3036 +#define PURPLELAVA__STATICRR -3038 +#define LAVABUBBLE__STATICRR -3040 +#define DUKECUTOUT__STATICRR -3047 +#define TARGET__STATICRR -3049 +#define GUNPOWDERBARREL__STATICRR -3050 +#define DUCK__STATICRR -3051 +#define HATRACK__STATICRR -2717 +#define DESKLAMP__STATICRR -2719 +#define COFFEEMACHINE__STATICRR -2721 +#define CUPS__STATICRR -2722 +#define GAVALS__STATICRR -2723 +#define GAVALS2__STATICRR -2724 +#define POLICELIGHTPOLE__STATICRR -2726 +#define FLOORBASKET__STATICRR -2728 +#define PUKE__STATICRR -2729 +#define DOORTILE23__STATICRR -2731 +#define TOPSECRET__STATICRR -2733 +#define SPEAKER__STATICRR -2734 +#define TEDDYBEAR__STATICRR -2735 +#define ROBOTDOG__STATICRR -2737 +#define ROBOTPIRATE__STATICRR -2739 +#define ROBOTMOUSE__STATICRR -2740 +#define MAIL__STATICRR -2741 +#define MAILBAG__STATICRR -2742 +#define HOTMEAT__STATICRR -2744 +#define COFFEEMUG__STATICRR -2745 +#define DONUTS2__STATICRR -2746 +#define TRIPODCAMERA__STATICRR -2747 +#define METER__STATICRR -2748 +#define DESKPHONE__STATICRR -2749 +#define GUMBALLMACHINE__STATICRR -2750 +#define GUMBALLMACHINEBROKE__STATICRR -2751 +#define PAPER__STATICRR -2752 +#define MACE__STATICRR -2753 +#define GENERICPOLE2__STATICRR -2754 +#define XXXSTACY__STATICRR -2755 +#define WETFLOOR__STATICRR -2756 +#define BROOM__STATICRR -2757 +#define MOP__STATICRR -2758 +#define PIRATE1A__STATICRR -2759 +#define PIRATE4A__STATICRR -2760 +#define PIRATE2A__STATICRR -2761 +#define PIRATE5A__STATICRR -2762 +#define PIRATE3A__STATICRR -2763 +#define PIRATE6A__STATICRR -2764 +#define PIRATEHALF__STATICRR -2765 +#define CHESTOFGOLD__STATICRR -2767 +#define SIDEBOLT1__STATICRR -2768 +#define FOODOBJECT1__STATICRR -2773 +#define FOODOBJECT2__STATICRR -2774 +#define FOODOBJECT3__STATICRR -2775 +#define FOODOBJECT4__STATICRR -2776 +#define FOODOBJECT5__STATICRR -2777 +#define FOODOBJECT6__STATICRR -2778 +#define FOODOBJECT7__STATICRR -2779 +#define FOODOBJECT8__STATICRR -2780 +#define FOODOBJECT9__STATICRR -2781 +#define FOODOBJECT10__STATICRR -2782 +#define FOODOBJECT11__STATICRR -2783 +#define FOODOBJECT12__STATICRR -2784 +#define FOODOBJECT13__STATICRR -2785 +#define FOODOBJECT14__STATICRR -2786 +#define FOODOBJECT15__STATICRR -2787 +#define FOODOBJECT16__STATICRR -2788 +#define FOODOBJECT17__STATICRR -2789 +#define FOODOBJECT18__STATICRR -2790 +#define FOODOBJECT19__STATICRR -2791 +#define FOODOBJECT20__STATICRR -2792 +#define HEADLAMP__STATICRR -2793 +#define TAMPON__STATICRR -2796 +#define SKINNEDCHICKEN__STATICRR -2794 +#define FEATHEREDCHICKEN__STATICRR -2795 +#define ROBOTDOG2__STATICRR -2797 +#define JOLLYMEAL__STATICRR -2800 +#define DUKEBURGER__STATICRR -2801 +#define SHOPPINGCART__STATICRR -2806 +#define CANWITHSOMETHING2__STATICRR -2807 +#define CANWITHSOMETHING3__STATICRR -2808 +#define CANWITHSOMETHING4__STATICRR -2809 +#define SNAKEP__STATICRR -1224 +#define DOLPHIN1__STATICRR -1225 +#define DOLPHIN2__STATICRR -1226 +#define BOSS4__STATICRR -4221 +#define FEM10__STATICRR -5581 +#define TOUGHGAL__STATICRR -5583 +#define MAN__STATICRR -5588 +#define MAN2__STATICRR -5589 +#define WOMAN__STATICRR -5591 +#define PLEASEWAIT__STATICRR -12 +#define DUKETAG__STATICRR -15 +#define SIGN1__STATICRR -16 +#define SIGN2__STATICRR -17 +#define JURYGUY__STATICRR -1142 +#define RRTILE11__STATICRR -11 +#define RPG2SPRITE__STATICRR -14 +#define RRTILE18__STATICRR -18 +#define RRTILE19__STATICRR -19 +#define RRTILE34__STATICRR -34 +#define RRTILE35__STATICRR -35 +#define DESTRUCTO__STATICRR -36 +#define RRTILE38__STATICRR -38 +#define RRTILE43__STATICRR -43 +#define GUTMETER__STATICRR -62 +#define RRTILE63__STATICRR -63 +#define RRTILE64__STATICRR -64 +#define RRTILE65__STATICRR -65 +#define RRTILE66__STATICRR -66 +#define RRTILE67__STATICRR -67 +#define RRTILE68__STATICRR -68 +#define SOUNDFX__STATICRR -71 +#define MOTOAMMO__STATICRR -78 +#define UFOBEAM__STATICRR -252 +#define RRTILE280__STATICRR -280 +#define RRTILE281__STATICRR -281 +#define RRTILE282__STATICRR -282 +#define RRTILE283__STATICRR -283 +#define RRTILE285__STATICRR -285 +#define RRTILE286__STATICRR -286 +#define RRTILE287__STATICRR -287 +#define RRTILE288__STATICRR -288 +#define RRTILE289__STATICRR -289 +#define RRTILE290__STATICRR -290 +#define RRTILE291__STATICRR -291 +#define RRTILE292__STATICRR -292 +#define RRTILE293__STATICRR -293 +#define RRTILE295__STATICRR -295 +#define RRTILE296__STATICRR -296 +#define RRTILE297__STATICRR -297 +#define CDPLAYER__STATICRR -370 +#define RRTILE380__STATICRR -380 +#define RRTILE403__STATICRR -403 +#define RRTILE409__STATICRR -409 +#define GUTMETER_LIGHT1__STATICRR -920 +#define GUTMETER_LIGHT2__STATICRR -921 +#define GUTMETER_LIGHT3__STATICRR -922 +#define GUTMETER_LIGHT4__STATICRR -923 +#define AMMO_ICON__STATICRR -930 +#define RRTILE1076__STATICRR -1076 +#define MUD__STATICRR -1420 +#define EXPLOSION3__STATICRR -1442 +#define RRTILE1636__STATICRR -1636 +#define WEAPONBAR__STATICRR -1649 +#define RRTILE1752__STATICRR -1752 +#define RPG2__STATICRR -1781 +#define RRTILE1790__STATICRR -1790 +#define RRTILE1792__STATICRR -1792 +#define RRTILE1801__STATICRR -1801 +#define RRTILE1805__STATICRR -1805 +#define RRTILE1807__STATICRR -1807 +#define RRTILE1808__STATICRR -1808 +#define RRTILE1812__STATICRR -1812 +#define RRTILE1814__STATICRR -1814 +#define RRTILE1817__STATICRR -1817 +#define RRTILE1821__STATICRR -1821 +#define RRTILE1824__STATICRR -1824 +#define RRTILE1826__STATICRR -1826 +#define RRTILE1850__STATICRR -1850 +#define RRTILE1851__STATICRR -1851 +#define RRTILE1856__STATICRR -1856 +#define RRTILE1877__STATICRR -1877 +#define RRTILE1878__STATICRR -1878 +#define RRTILE1938__STATICRR -1938 +#define RRTILE1939__STATICRR -1939 +#define RRTILE1942__STATICRR -1942 +#define RRTILE1944__STATICRR -1944 +#define RRTILE1945__STATICRR -1945 +#define RRTILE1947__STATICRR -1947 +#define RRTILE1951__STATICRR -1951 +#define RRTILE1952__STATICRR -1952 +#define RRTILE1953__STATICRR -1953 +#define RRTILE1961__STATICRR -1961 +#define RRTILE1964__STATICRR -1964 +#define RRTILE1973__STATICRR -1973 +#define RRTILE1985__STATICRR -1985 +#define RRTILE1986__STATICRR -1986 +#define RRTILE1987__STATICRR -1987 +#define RRTILE1988__STATICRR -1988 +#define RRTILE1990__STATICRR -1990 +#define RRTILE1995__STATICRR -1995 +#define RRTILE1996__STATICRR -1996 +#define RRTILE2004__STATICRR -2004 +#define RRTILE2005__STATICRR -2005 +#define POPCORN__STATICRR -2021 +#define RRTILE2022__STATICRR -2022 +#define LANEPICS__STATICRR -2023 +#define RRTILE2025__STATICRR -2025 +#define RRTILE2026__STATICRR -2026 +#define RRTILE2027__STATICRR -2027 +#define RRTILE2028__STATICRR -2028 +#define RRTILE2034__STATICRR -2034 +#define RRTILE2050__STATICRR -2050 +#define RRTILE2052__STATICRR -2052 +#define RRTILE2053__STATICRR -2053 +#define RRTILE2056__STATICRR -2056 +#define RRTILE2060__STATICRR -2060 +#define RRTILE2072__STATICRR -2072 +#define RRTILE2074__STATICRR -2074 +#define RRTILE2075__STATICRR -2075 +#define RRTILE2083__STATICRR -2083 +#define RRTILE2097__STATICRR -2097 +#define RRTILE2121__STATICRR -2121 +#define RRTILE2122__STATICRR -2122 +#define RRTILE2123__STATICRR -2123 +#define RRTILE2124__STATICRR -2124 +#define RRTILE2125__STATICRR -2125 +#define RRTILE2126__STATICRR -2126 +#define RRTILE2137__STATICRR -2137 +#define RRTILE2132__STATICRR -2132 +#define RRTILE2136__STATICRR -2136 +#define RRTILE2139__STATICRR -2139 +#define RRTILE2150__STATICRR -2150 +#define RRTILE2151__STATICRR -2151 +#define RRTILE2152__STATICRR -2152 +#define RRTILE2156__STATICRR -2156 +#define RRTILE2157__STATICRR -2157 +#define RRTILE2158__STATICRR -2158 +#define RRTILE2159__STATICRR -2159 +#define RRTILE2160__STATICRR -2160 +#define RRTILE2161__STATICRR -2161 +#define RRTILE2175__STATICRR -2175 +#define RRTILE2176__STATICRR -2176 +#define RRTILE2178__STATICRR -2178 +#define RRTILE2186__STATICRR -2186 +#define RRTILE2214__STATICRR -2214 +#define RRTILE2319__STATICRR -2319 +#define RRTILE2321__STATICRR -2321 +#define RRTILE2326__STATICRR -2326 +#define RRTILE2329__STATICRR -2329 +#define RRTILE2357__STATICRR -2357 +#define RRTILE2382__STATICRR -2382 +#define RRTILE2430__STATICRR -2430 +#define RRTILE2431__STATICRR -2431 +#define RRTILE2432__STATICRR -2432 +#define RRTILE2437__STATICRR -2437 +#define RRTILE2443__STATICRR -2443 +#define RRTILE2445__STATICRR -2445 +#define RRTILE2446__STATICRR -2446 +#define RRTILE2450__STATICRR -2450 +#define RRTILE2451__STATICRR -2451 +#define RRTILE2455__STATICRR -2455 +#define RRTILE2460__STATICRR -2460 +#define RRTILE2465__STATICRR -2465 +#define RRTILE2560__STATICRR -2560 +#define RRTILE2562__STATICRR -2562 +#define RRTILE2564__STATICRR -2564 +#define RRTILE2573__STATICRR -2573 +#define RRTILE2574__STATICRR -2574 +#define RRTILE2577__STATICRR -2577 +#define RRTILE2578__STATICRR -2578 +#define RRTILE2581__STATICRR -2581 +#define RRTILE2583__STATICRR -2583 +#define RRTILE2604__STATICRR -2604 +#define RRTILE2610__STATICRR -2610 +#define RRTILE2613__STATICRR -2613 +#define RRTILE2621__STATICRR -2621 +#define RRTILE2622__STATICRR -2622 +#define RRTILE2636__STATICRR -2636 +#define RRTILE2637__STATICRR -2637 +#define RRTILE2654__STATICRR -2654 +#define RRTILE2656__STATICRR -2656 +#define RRTILE2676__STATICRR -2676 +#define RRTILE2689__STATICRR -2689 +#define RRTILE2697__STATICRR -2697 +#define RRTILE2702__STATICRR -2702 +#define RRTILE2707__STATICRR -2707 +#define RRTILE2732__STATICRR -2732 +#define RRTILE2030__STATICRR -2030 +#define RRTILE2831__STATICRR -2831 +#define RRTILE2832__STATICRR -2832 +#define RRTILE2842__STATICRR -2842 +#define RRTILE2859__STATICRR -2859 +#define RRTILE2876__STATICRR -2876 +#define RRTILE2878__STATICRR -2878 +#define RRTILE2879__STATICRR -2879 +#define RRTILE2893__STATICRR -2893 +#define RRTILE2894__STATICRR -2894 +#define RRTILE2898__STATICRR -2898 +#define RRTILE2899__STATICRR -2899 +#define RRTILE2915__STATICRR -2915 +#define RRTILE2940__STATICRR -2940 +#define RRTILE2944__STATICRR -2944 +#define RRTILE2945__STATICRR -2945 +#define RRTILE2946__STATICRR -2946 +#define RRTILE2947__STATICRR -2947 +#define RRTILE2948__STATICRR -2948 +#define RRTILE2949__STATICRR -2949 +#define RRTILE2961__STATICRR -2961 +#define RRTILE2970__STATICRR -2970 +#define RRTILE2977__STATICRR -2977 +#define RRTILE2978__STATICRR -2978 +#define RRTILE2990__STATICRR -2990 +#define RRTILE3073__STATICRR -3073 +#define RRTILE3083__STATICRR -3083 +#define RRTILE3100__STATICRR -3100 +#define RRTILE3114__STATICRR -3114 +#define RRTILE3115__STATICRR -3115 +#define RRTILE3116__STATICRR -3116 +#define RRTILE3117__STATICRR -3117 +#define RRTILE3120__STATICRR -3120 +#define RRTILE3121__STATICRR -3121 +#define RRTILE3122__STATICRR -3122 +#define RRTILE3123__STATICRR -3123 +#define RRTILE3124__STATICRR -3124 +#define RRTILE3132__STATICRR -3132 +#define RRTILE3139__STATICRR -3139 +#define RRTILE3144__STATICRR -3144 +#define RRTILE3152__STATICRR -3152 +#define RRTILE3153__STATICRR -3153 +#define RRTILE3155__STATICRR -3155 +#define RRTILE3171__STATICRR -3171 +#define RRTILE3172__STATICRR -3172 +#define RRTILE3190__STATICRR -3190 +#define RRTILE3191__STATICRR -3191 +#define RRTILE3192__STATICRR -3192 +#define RRTILE3195__STATICRR -3195 +#define RRTILE3200__STATICRR -3200 +#define RRTILE3201__STATICRR -3201 +#define RRTILE3202__STATICRR -3202 +#define RRTILE3203__STATICRR -3203 +#define RRTILE3204__STATICRR -3204 +#define RRTILE3205__STATICRR -3205 +#define RRTILE3206__STATICRR -3206 +#define RRTILE3207__STATICRR -3207 +#define RRTILE3208__STATICRR -3208 +#define RRTILE3209__STATICRR -3209 +#define RRTILE3216__STATICRR -3216 +#define RRTILE3218__STATICRR -3218 +#define RRTILE3219__STATICRR -3219 +#define RRTILE3232__STATICRR -3232 +#define SHOTGUNSHELLS__STATICRR -3372 +#define CIRCLESTUCK__STATICRR -3388 +#define RRTILE3410__STATICRR -3410 +#define LUMBERBLADE__STATICRR -3411 +#define BOWLINGBALLH__STATICRR -3428 +#define BOWLINGBALL__STATICRR -3430 +#define BOWLINGBALLSPRITE__STATICRR -3437 +#define POWDERH__STATICRR -3438 +#define RRTILE3440__STATICRR -3440 +#define RRTILE3462__STATICRR -3462 +#define OWHIP__STATICRR -3471 +#define UWHIP__STATICRR -3475 +#define RPGGUN2__STATICRR -3482 +#define RRTILE3497__STATICRR -3497 +#define RRTILE3498__STATICRR -3498 +#define RRTILE3499__STATICRR -3499 +#define RRTILE3500__STATICRR -3500 +#define SLINGBLADE__STATICRR -3510 +#define RRTILE3584__STATICRR -3584 +#define RRTILE3586__STATICRR -3586 +#define RRTILE3587__STATICRR -3587 +#define RRTILE3600__STATICRR -3600 +#define RRTILE3631__STATICRR -3631 +#define RRTILE3635__STATICRR -3635 +#define RRTILE3637__STATICRR -3637 +#define RRTILE3643__STATICRR -3643 +#define RRTILE3647__STATICRR -3647 +#define RRTILE3652__STATICRR -3652 +#define RRTILE3653__STATICRR -3653 +#define RRTILE3668__STATICRR -3668 +#define RRTILE3671__STATICRR -3671 +#define RRTILE3673__STATICRR -3673 +#define RRTILE3677__STATICRR -3677 +#define RRTILE3684__STATICRR -3684 +#define RRTILE3708__STATICRR -3708 +#define RRTILE3714__STATICRR -3714 +#define RRTILE3716__STATICRR -3716 +#define RRTILE3720__STATICRR -3720 +#define RRTILE3723__STATICRR -3723 +#define RRTILE3725__STATICRR -3725 +#define RRTILE3737__STATICRR -3737 +#define RRTILE3754__STATICRR -3754 +#define RRTILE3762__STATICRR -3762 +#define RRTILE3763__STATICRR -3763 +#define RRTILE3764__STATICRR -3764 +#define RRTILE3765__STATICRR -3765 +#define RRTILE3767__STATICRR -3767 +#define RRTILE3773__STATICRR -3773 +#define RRTILE3774__STATICRR -3774 +#define RRTILE3793__STATICRR -3793 +#define RRTILE3795__STATICRR -3795 +#define RRTILE3804__STATICRR -3804 +#define RRTILE3814__STATICRR -3814 +#define RRTILE3815__STATICRR -3815 +#define RRTILE3819__STATICRR -3819 +#define RRTILE3827__STATICRR -3827 +#define RRTILE3837__STATICRR -3837 +#define RRTILE5014__STATICRR -5014 +#define RRTILE5016__STATICRR -5016 +#define RRTILE5017__STATICRR -5017 +#define RRTILE5018__STATICRR -5018 +#define RRTILE5019__STATICRR -5019 +#define RRTILE5020__STATICRR -5020 +#define RRTILE5021__STATICRR -5021 +#define RRTILE5022__STATICRR -5022 +#define RRTILE5023__STATICRR -5023 +#define RRTILE5024__STATICRR -5024 +#define RRTILE5025__STATICRR -5025 +#define RRTILE5026__STATICRR -5026 +#define RRTILE5027__STATICRR -5027 +#define RRTILE5029__STATICRR -5029 +#define RRTILE5030__STATICRR -5030 +#define RRTILE5031__STATICRR -5031 +#define RRTILE5032__STATICRR -5032 +#define RRTILE5033__STATICRR -5033 +#define RRTILE5034__STATICRR -5034 +#define RRTILE5035__STATICRR -5035 +#define RRTILE5036__STATICRR -5036 +#define RRTILE5037__STATICRR -5037 +#define RRTILE5038__STATICRR -5038 +#define RRTILE5039__STATICRR -5039 +#define RRTILE5040__STATICRR -5040 +#define RRTILE5041__STATICRR -5041 +#define RRTILE5043__STATICRR -5043 +#define RRTILE5044__STATICRR -5044 +#define RRTILE5045__STATICRR -5045 +#define RRTILE5046__STATICRR -5046 +#define RRTILE5047__STATICRR -5047 +#define RRTILE5048__STATICRR -5048 +#define RRTILE5049__STATICRR -5049 +#define RRTILE5050__STATICRR -5050 +#define RRTILE5051__STATICRR -5051 +#define RRTILE5052__STATICRR -5052 +#define RRTILE5053__STATICRR -5053 +#define RRTILE5054__STATICRR -5054 +#define RRTILE5055__STATICRR -5055 +#define RRTILE5056__STATICRR -5056 +#define RRTILE5057__STATICRR -5057 +#define RRTILE5058__STATICRR -5058 +#define RRTILE5059__STATICRR -5059 +#define RRTILE5061__STATICRR -5061 +#define RRTILE5062__STATICRR -5062 +#define RRTILE5063__STATICRR -5063 +#define RRTILE5064__STATICRR -5064 +#define RRTILE5065__STATICRR -5065 +#define RRTILE5066__STATICRR -5066 +#define RRTILE5067__STATICRR -5067 +#define RRTILE5068__STATICRR -5068 +#define RRTILE5069__STATICRR -5069 +#define RRTILE5070__STATICRR -5070 +#define RRTILE5071__STATICRR -5071 +#define RRTILE5072__STATICRR -5072 +#define RRTILE5073__STATICRR -5073 +#define RRTILE5074__STATICRR -5074 +#define RRTILE5075__STATICRR -5075 +#define RRTILE5076__STATICRR -5076 +#define RRTILE5077__STATICRR -5077 +#define RRTILE5078__STATICRR -5078 +#define RRTILE5079__STATICRR -5079 +#define RRTILE5080__STATICRR -5080 +#define RRTILE5081__STATICRR -5081 +#define RRTILE5082__STATICRR -5082 +#define RRTILE5083__STATICRR -5083 +#define RRTILE5084__STATICRR -5084 +#define RRTILE5085__STATICRR -5085 +#define RRTILE5086__STATICRR -5086 +#define RRTILE5087__STATICRR -5087 +#define RRTILE5088__STATICRR -5088 +#define RRTILE5090__STATICRR -5090 +#define RRTILE6144__STATICRR -6144 +#define RRTILE7110__STATICRR -7110 +#define RRTILE7111__STATICRR -7111 +#define RRTILE7112__STATICRR -7112 +#define RRTILE7113__STATICRR -7113 +#define MOTOGUN__STATICRR -7168 +#define RRTILE7169__STATICRR -7169 +#define MOTOHIT__STATICRR -7170 +#define BOATHIT__STATICRR -7175 +#define RRTILE7184__STATICRR -7184 +#define RRTILE7190__STATICRR -7190 +#define RRTILE7191__STATICRR -7191 +#define RRTILE7213__STATICRR -7213 +#define RRTILE7219__STATICRR -7219 +#define EMPTYBIKE__STATICRR -7220 +#define EMPTYBOAT__STATICRR -7233 +#define RRTILE7424__STATICRR -7424 +#define RRTILE7430__STATICRR -7430 +#define RRTILE7433__STATICRR -7433 +#define RRTILE7441__STATICRR -7441 +#define RRTILE7547__STATICRR -7547 +#define RRTILE7467__STATICRR -7467 +#define RRTILE7469__STATICRR -7469 +#define RRTILE7470__STATICRR -7470 +#define RRTILE7475__STATICRR -7475 +#define RRTILE7478__STATICRR -7478 +#define RRTILE7505__STATICRR -7505 +#define RRTILE7506__STATICRR -7506 +#define RRTILE7534__STATICRR -7534 +#define RRTILE7540__STATICRR -7540 +#define RRTILE7533__STATICRR -7533 +#define RRTILE7545__STATICRR -7545 +#define RRTILE7552__STATICRR -7552 +#define RRTILE7553__STATICRR -7553 +#define RRTILE7554__STATICRR -7554 +#define RRTILE7555__STATICRR -7555 +#define RRTILE7557__STATICRR -7557 +#define RRTILE7558__STATICRR -7558 +#define RRTILE7559__STATICRR -7559 +#define RRTILE7561__STATICRR -7561 +#define RRTILE7566__STATICRR -7566 +#define RRTILE7568__STATICRR -7568 +#define RRTILE7574__STATICRR -7574 +#define RRTILE7575__STATICRR -7575 +#define RRTILE7576__STATICRR -7576 +#define RRTILE7578__STATICRR -7578 +#define RRTILE7579__STATICRR -7579 +#define RRTILE7580__STATICRR -7580 +#define RRTILE7595__STATICRR -7595 +#define RRTILE7629__STATICRR -7629 +#define RRTILE7636__STATICRR -7636 +#define RRTILE7638__STATICRR -7638 +#define RRTILE7640__STATICRR -7640 +#define RRTILE7644__STATICRR -7644 +#define RRTILE7646__STATICRR -7646 +#define RRTILE7648__STATICRR -7648 +#define RRTILE7650__STATICRR -7650 +#define RRTILE7653__STATICRR -7653 +#define RRTILE7655__STATICRR -7655 +#define RRTILE7657__STATICRR -7657 +#define RRTILE7659__STATICRR -7659 +#define RRTILE7691__STATICRR -7691 +#define RRTILE7694__STATICRR -7694 +#define RRTILE7696__STATICRR -7696 +#define RRTILE7697__STATICRR -7697 +#define RRTILE7700__STATICRR -7700 +#define RRTILE7702__STATICRR -7702 +#define RRTILE7704__STATICRR -7704 +#define RRTILE7705__STATICRR -7705 +#define RRTILE7711__STATICRR -7711 +#define RRTILE7716__STATICRR -7716 +#define RRTILE7756__STATICRR -7756 +#define RRTILE7768__STATICRR -7768 +#define RRTILE7806__STATICRR -7806 +#define RRTILE7820__STATICRR -7820 +#define RRTILE7859__STATICRR -7859 +#define RRTILE7870__STATICRR -7870 +#define RRTILE7873__STATICRR -7873 +#define RRTILE7875__STATICRR -7875 +#define RRTILE7876__STATICRR -7876 +#define RRTILE7879__STATICRR -7879 +#define RRTILE7881__STATICRR -7881 +#define RRTILE7883__STATICRR -7883 +#define RRTILE7885__STATICRR -7885 +#define RRTILE7886__STATICRR -7886 +#define RRTILE7887__STATICRR -7887 +#define RRTILE7888__STATICRR -7888 +#define RRTILE7889__STATICRR -7889 +#define RRTILE7890__STATICRR -7890 +#define RRTILE7900__STATICRR -7900 +#define RRTILE7901__STATICRR -7901 +#define RRTILE7906__STATICRR -7906 +#define RRTILE7912__STATICRR -7912 +#define RRTILE7913__STATICRR -7913 +#define RRTILE7936__STATICRR -7936 +#define RRTILE8047__STATICRR -8047 +#define MULTISWITCH2__STATICRR -8048 +#define RRTILE8059__STATICRR -8059 +#define RRTILE8060__STATICRR -8060 +#define RRTILE8063__STATICRR -8063 +#define RRTILE8067__STATICRR -8067 +#define RRTILE8076__STATICRR -8076 +#define RRTILE8094__STATICRR -8094 +#define RRTILE8096__STATICRR -8096 +#define RRTILE8099__STATICRR -8099 +#define RRTILE8106__STATICRR -8106 +#define RRTILE8162__STATICRR -8162 +#define RRTILE8163__STATICRR -8163 +#define RRTILE8164__STATICRR -8164 +#define RRTILE8165__STATICRR -8165 +#define RRTILE8166__STATICRR -8166 +#define RRTILE8167__STATICRR -8167 +#define RRTILE8168__STATICRR -8168 +#define RRTILE8192__STATICRR -8192 +#define RRTILE8193__STATICRR -8193 +#define RRTILE8215__STATICRR -8215 +#define RRTILE8216__STATICRR -8216 +#define RRTILE8217__STATICRR -8217 +#define RRTILE8218__STATICRR -8218 +#define RRTILE8220__STATICRR -8220 +#define RRTILE8221__STATICRR -8221 +#define RRTILE8222__STATICRR -8222 +#define RRTILE8223__STATICRR -8223 +#define RRTILE8224__STATICRR -8224 +#define RRTILE8227__STATICRR -8227 +#define RRTILE8312__STATICRR -8312 +#define RRTILE8370__STATICRR -8370 +#define RRTILE8371__STATICRR -8371 +#define RRTILE8372__STATICRR -8372 +#define RRTILE8373__STATICRR -8373 +#define RRTILE8379__STATICRR -8379 +#define RRTILE8380__STATICRR -8380 +#define RRTILE8385__STATICRR -8385 +#define RRTILE8386__STATICRR -8386 +#define RRTILE8387__STATICRR -8387 +#define RRTILE8388__STATICRR -8388 +#define RRTILE8389__STATICRR -8389 +#define RRTILE8390__STATICRR -8390 +#define RRTILE8391__STATICRR -8391 +#define RRTILE8392__STATICRR -8392 +#define RRTILE8394__STATICRR -8394 +#define RRTILE8395__STATICRR -8395 +#define RRTILE8396__STATICRR -8396 +#define RRTILE8397__STATICRR -8397 +#define RRTILE8398__STATICRR -8398 +#define RRTILE8399__STATICRR -8399 +#define RRTILE8423__STATICRR -8423 +#define RRTILE8448__STATICRR -8448 +#define RRTILE8450__STATICRR -8450 +#define BOATAMMO__STATICRR -8460 +#define RRTILE8461__STATICRR -8461 +#define RRTILE8462__STATICRR -8462 +#define RRTILE8464__STATICRR -8464 +#define RRTILE8475__STATICRR -8475 +#define RRTILE8487__STATICRR -8487 +#define RRTILE8488__STATICRR -8488 +#define RRTILE8489__STATICRR -8489 +#define RRTILE8490__STATICRR -8490 +#define RRTILE8496__STATICRR -8496 +#define RRTILE8497__STATICRR -8497 +#define RRTILE8498__STATICRR -8498 +#define RRTILE8499__STATICRR -8499 +#define RRTILE8503__STATICRR -8503 +#define RRTILE8525__STATICRR -8525 +#define RRTILE8537__STATICRR -8537 +#define RRTILE8565__STATICRR -8565 +#define RRTILE8567__STATICRR -8567 +#define RRTILE8568__STATICRR -8568 +#define RRTILE8569__STATICRR -8569 +#define RRTILE8570__STATICRR -8570 +#define RRTILE8571__STATICRR -8571 +#define RRTILE8579__STATICRR -8579 +#define RRTILE8588__STATICRR -8588 +#define RRTILE8589__STATICRR -8589 +#define RRTILE8590__STATICRR -8590 +#define RRTILE8591__STATICRR -8591 +#define RRTILE8592__STATICRR -8592 +#define RRTILE8593__STATICRR -8593 +#define RRTILE8594__STATICRR -8594 +#define RRTILE8595__STATICRR -8595 +#define RRTILE8596__STATICRR -8596 +#define RRTILE8598__STATICRR -8598 +#define RRTILE8605__STATICRR -8605 +#define RRTILE8608__STATICRR -8608 +#define RRTILE8609__STATICRR -8609 +#define RRTILE8611__STATICRR -8611 +#define RRTILE8617__STATICRR -8617 +#define RRTILE8618__STATICRR -8618 +#define RRTILE8620__STATICRR -8620 +#define RRTILE8621__STATICRR -8621 +#define RRTILE8622__STATICRR -8622 +#define RRTILE8623__STATICRR -8623 +#define RRTILE8624__STATICRR -8624 +#define RRTILE8640__STATICRR -8640 +#define RRTILE8651__STATICRR -8651 +#define RRTILE8660__STATICRR -8660 +#define RRTILE8677__STATICRR -8677 +#define RRTILE8679__STATICRR -8679 +#define RRTILE8680__STATICRR -8680 +#define RRTILE8681__STATICRR -8681 +#define RRTILE8682__STATICRR -8682 +#define RRTILE8683__STATICRR -8683 +#define RRTILE8704__STATICRR -8704 +#define BOULDER__STATICRR -256 +#define BOULDER1__STATICRR -264 +#define TORNADO__STATICRR -1930 +#define CHEERBOMB__STATICRR -3464 +#define CHEERBLADE__STATICRR -3460 +#define DOGATTACK__STATICRR -4060 +#define BILLYWALK__STATICRR -4096 +#define BILLYDIE__STATICRR -4137 +#define BILLYCOCK__STATICRR -4147 +#define BILLYRAY__STATICRR -4162 +#define BILLYRAYSTAYPUT__STATICRR -4163 +#define BILLYBUT__STATICRR -4188 +#define BILLYSCRATCH__STATICRR -4191 +#define BILLYSNIFF__STATICRR -4195 +#define BILLYWOUND__STATICRR -4202 +#define BILLYGORE__STATICRR -4228 +#define BILLYJIBA__STATICRR -4235 +#define BILLYJIBB__STATICRR -4244 +#define BRAYSNIPER__STATICRR -4249 +#define DOGRUN__STATICRR -4260 +#define DOGDIE__STATICRR -4295 +#define DOGDEAD__STATICRR -4303 +#define DOGBARK__STATICRR -4305 +#define LTH__STATICRR -4352 +#define LTHSTRAFE__STATICRR -4395 +#define HULKHANG__STATICRR -4409 +#define HULKHANGDEAD__STATICRR -4410 +#define HULKJUMP__STATICRR -4429 +#define LTHLOAD__STATICRR -4430 +#define LTHDIE__STATICRR -4456 +#define BUBBASCRATCH__STATICRR -4464 +#define BUBBANOSE__STATICRR -4476 +#define BUBBAPISS__STATICRR -4487 +#define BUBBASTAND__STATICRR -4504 +#define BUBBAOUCH__STATICRR -4506 +#define BUBBADIE__STATICRR -4513 +#define BUBBADEAD__STATICRR -4523 +#define HULK__STATICRR -4649 +#define HULKSTAYPUT__STATICRR -4650 +#define HULKA__STATICRR -4651 +#define HULKB__STATICRR -4652 +#define HULKC__STATICRR -4653 +#define HULKJIBA__STATICRR -4748 +#define HULKJIBB__STATICRR -4753 +#define HULKJIBC__STATICRR -4758 +#define SBSWIPE__STATICRR -4770 +#define SBPAIN__STATICRR -4810 +#define SBDIE__STATICRR -4820 +#define HEN__STATICRR -4861 +#define HENSTAYPUT__STATICRR -4862 +#define HENSTAND__STATICRR -4897 +#define PIG__STATICRR -4945 +#define PIGSTAYPUT__STATICRR -4946 +#define PIGEAT__STATICRR -4983 +#define SBMOVE__STATICRR -5015 +#define SBSPIT__STATICRR -5050 +#define SBDIP__STATICRR -5085 +#define MINION__STATICRR -5120 +#define MINIONSTAYPUT__STATICRR -5121 +#define UFO1__STATICRRRA -5260 +#define UFO1__STATICRR -5270 +#define UFO2__STATICRR -5274 +#define UFO3__STATICRR -5278 +#define UFO4__STATICRR -5282 +#define UFO5__STATICRR -5286 +#define MINJIBA__STATICRR -5290 +#define MINJIBB__STATICRR -5295 +#define MINJIBC__STATICRR -5300 +#define COW__STATICRR -5317 +#define COOT__STATICRR -5376 +#define COOTSTAYPUT__STATICRR -5377 +#define COOTSHOOT__STATICRR -5411 +#define COOTDIE__STATICRR -5437 +#define COOTDUCK__STATICRR -5481 +#define COOTPAIN__STATICRR -5548 +#define COOTTRANS__STATICRR -5568 +#define COOTGETUP__STATICRR -5579 +#define COOTJIBA__STATICRR -5602 +#define COOTJIBB__STATICRR -5607 +#define COOTJIBC__STATICRR -5616 +#define VIXEN__STATICRR -5635 +#define VIXENPAIN__STATICRR -5675 +#define VIXENDIE__STATICRR -5710 +#define VIXENSHOOT__STATICRR -5720 +#define VIXENWDN__STATICRR -5740 +#define VIXENWUP__STATICRR -5775 +#define VIXENKICK__STATICRR -5805 +#define VIXENTELE__STATICRR -5845 +#define VIXENTEAT__STATICRR -5851 +#define BIKEJIBA__STATICRR -5872 +#define BIKEJIBB__STATICRR -5877 +#define BIKEJIBC__STATICRR -5882 +#define BIKERB__STATICRR -5890 +#define BIKERBV2__STATICRR -5891 +#define BIKER__STATICRR -5995 +#define BIKERJIBA__STATICRR -6112 +#define BIKERJIBB__STATICRR -6117 +#define BIKERJIBC__STATICRR -6121 +#define BIKERJIBD__STATICRR -6127 +#define MAKEOUT__STATICRR -6225 +#define CHEERB__STATICRR -6401 +#define CHEER__STATICRR -6658 +#define CHEERSTAYPUT__STATICRR -6659 +#define CHEERJIBA__STATICRR -7000 +#define CHEERJIBB__STATICRR -7005 +#define CHEERJIBC__STATICRR -7010 +#define CHEERJIBD__STATICRR -7015 +#define FBOATJIBA__STATICRR -7020 +#define FBOATJIBB__STATICRR -7025 +#define COOTPLAY__STATICRR -7030 +#define BILLYPLAY__STATICRR -7035 +#define MINIONBOAT__STATICRR -7192 +#define HULKBOAT__STATICRR -7199 +#define CHEERBOAT__STATICRR -7206 +#define RRTILE7274__STATICRR -7274 +#define RABBIT__STATICRR -7280 +#define RABBITJIBA__STATICRR -7387 +#define RABBITJIBB__STATICRR -7392 +#define RABBITJIBC__STATICRR -7397 +#define ROCK__STATICRR -8035 +#define ROCK2__STATICRR -8036 +#define MAMACLOUD__STATICRR -8663 +#define MAMA__STATICRR -8705 +#define MAMAJIBA__STATICRR -8890 +#define MAMAJIBB__STATICRR -8895 + +extern int16_t DynamicTileMap[MAXTILES]; + +void G_InitDynamicTiles(void); + +void G_ProcessDynamicTileMapping(const char *szLabel, int32_t lValue); + +void inithashnames(void); +void freehashnames(void); + +extern int32_t SECTOREFFECTOR; +extern int32_t ACTIVATOR; +extern int32_t TOUCHPLATE; +extern int32_t ACTIVATORLOCKED; +extern int32_t MUSICANDSFX; +extern int32_t LOCATORS; +extern int32_t CYCLER; +extern int32_t MASTERSWITCH; +extern int32_t RESPAWN; +extern int32_t GPSPEED; +extern int32_t FOF; +extern int32_t ARROW; +extern int32_t FIRSTGUNSPRITE; +extern int32_t CHAINGUNSPRITE; +extern int32_t RPGSPRITE; +extern int32_t FREEZESPRITE; +extern int32_t SHRINKERSPRITE; +extern int32_t HEAVYHBOMB; +extern int32_t TRIPBOMBSPRITE; +extern int32_t SHOTGUNSPRITE; +extern int32_t DEVISTATORSPRITE; +extern int32_t HEALTHBOX; +extern int32_t AMMOBOX; +extern int32_t GROWSPRITEICON; +extern int32_t INVENTORYBOX; +extern int32_t FREEZEAMMO; +extern int32_t AMMO; +extern int32_t BATTERYAMMO; +extern int32_t DEVISTATORAMMO; +extern int32_t RPGAMMO; +extern int32_t GROWAMMO; +extern int32_t CRYSTALAMMO; +extern int32_t HBOMBAMMO; +extern int32_t AMMOLOTS; +extern int32_t SHOTGUNAMMO; +extern int32_t COLA; +extern int32_t SIXPAK; +extern int32_t FIRSTAID; +extern int32_t SHIELD; +extern int32_t STEROIDS; +extern int32_t AIRTANK; +extern int32_t JETPACK; +extern int32_t HEATSENSOR; +extern int32_t ACCESSCARD; +extern int32_t BOOTS; +extern int32_t MIRRORBROKE; +extern int32_t CLOUDYOCEAN; +extern int32_t CLOUDYSKIES; +extern int32_t MOONSKY1; +extern int32_t MOONSKY2; +extern int32_t MOONSKY3; +extern int32_t MOONSKY4; +extern int32_t BIGORBIT1; +extern int32_t BIGORBIT2; +extern int32_t BIGORBIT3; +extern int32_t BIGORBIT4; +extern int32_t BIGORBIT5; +extern int32_t LA; +extern int32_t REDSKY1; +extern int32_t REDSKY2; +extern int32_t ATOMICHEALTH; +extern int32_t TECHLIGHT2; +extern int32_t TECHLIGHTBUST2; +extern int32_t TECHLIGHT4; +extern int32_t TECHLIGHTBUST4; +extern int32_t WALLLIGHT4; +extern int32_t WALLLIGHTBUST4; +extern int32_t ACCESSSWITCH; +extern int32_t SLOTDOOR; +extern int32_t LIGHTSWITCH; +extern int32_t SPACEDOORSWITCH; +extern int32_t SPACELIGHTSWITCH; +extern int32_t FRANKENSTINESWITCH; +extern int32_t NUKEBUTTON; +extern int32_t MULTISWITCH; +extern int32_t DOORTILE5; +extern int32_t DOORTILE6; +extern int32_t DOORTILE1; +extern int32_t DOORTILE2; +extern int32_t DOORTILE3; +extern int32_t DOORTILE4; +extern int32_t DOORTILE7; +extern int32_t DOORTILE8; +extern int32_t DOORTILE9; +extern int32_t DOORTILE10; +extern int32_t DOORSHOCK; +extern int32_t DIPSWITCH; +extern int32_t DIPSWITCH2; +extern int32_t TECHSWITCH; +extern int32_t DIPSWITCH3; +extern int32_t ACCESSSWITCH2; +extern int32_t REFLECTWATERTILE; +extern int32_t FLOORSLIME; +extern int32_t BIGFORCE; +extern int32_t EPISODE; +extern int32_t MASKWALL9; +extern int32_t W_LIGHT; +extern int32_t SCREENBREAK1; +extern int32_t SCREENBREAK2; +extern int32_t SCREENBREAK3; +extern int32_t SCREENBREAK4; +extern int32_t SCREENBREAK5; +extern int32_t SCREENBREAK6; +extern int32_t SCREENBREAK7; +extern int32_t SCREENBREAK8; +extern int32_t SCREENBREAK9; +extern int32_t SCREENBREAK10; +extern int32_t SCREENBREAK11; +extern int32_t SCREENBREAK12; +extern int32_t SCREENBREAK13; +extern int32_t MASKWALL1; +extern int32_t W_TECHWALL1; +extern int32_t W_TECHWALL2; +extern int32_t W_TECHWALL15; +extern int32_t W_TECHWALL3; +extern int32_t W_TECHWALL4; +extern int32_t W_TECHWALL10; +extern int32_t W_TECHWALL16; +extern int32_t WATERTILE2; +extern int32_t BPANNEL1; +extern int32_t PANNEL1; +extern int32_t PANNEL2; +extern int32_t WATERTILE; +extern int32_t STATIC; +extern int32_t W_SCREENBREAK; +extern int32_t W_HITTECHWALL3; +extern int32_t W_HITTECHWALL4; +extern int32_t W_HITTECHWALL2; +extern int32_t W_HITTECHWALL1; +extern int32_t MASKWALL10; +extern int32_t MASKWALL11; +extern int32_t DOORTILE22; +extern int32_t FANSPRITE; +extern int32_t FANSPRITEBROKE; +extern int32_t FANSHADOW; +extern int32_t FANSHADOWBROKE; +extern int32_t DOORTILE18; +extern int32_t DOORTILE19; +extern int32_t DOORTILE20; +extern int32_t SATELLITE; +extern int32_t VIEWSCREEN2; +extern int32_t VIEWSCREENBROKE; +extern int32_t VIEWSCREEN; +extern int32_t GLASS; +extern int32_t GLASS2; +extern int32_t STAINGLASS1; +extern int32_t MASKWALL5; +extern int32_t SATELITE; +extern int32_t FUELPOD; +extern int32_t SLIMEPIPE; +extern int32_t CRACK1; +extern int32_t CRACK2; +extern int32_t CRACK3; +extern int32_t CRACK4; +extern int32_t FOOTPRINTS; +extern int32_t DOMELITE; +extern int32_t CAMERAPOLE; +extern int32_t CHAIR1; +extern int32_t CHAIR2; +extern int32_t BROKENCHAIR; +extern int32_t MIRROR; +extern int32_t WATERFOUNTAIN; +extern int32_t WATERFOUNTAINBROKE; +extern int32_t FEMMAG1; +extern int32_t TOILET; +extern int32_t STALL; +extern int32_t STALLBROKE; +extern int32_t FEMMAG2; +extern int32_t REACTOR2; +extern int32_t REACTOR2BURNT; +extern int32_t REACTOR2SPARK; +extern int32_t GRATE1; +extern int32_t BGRATE1; +extern int32_t SOLARPANNEL; +extern int32_t NAKED1; +extern int32_t ANTENNA; +extern int32_t MASKWALL12; +extern int32_t TOILETBROKE; +extern int32_t PIPE2; +extern int32_t PIPE1B; +extern int32_t PIPE3; +extern int32_t PIPE1; +extern int32_t CAMERA1; +extern int32_t BRICK; +extern int32_t SPLINTERWOOD; +extern int32_t PIPE2B; +extern int32_t BOLT1; +extern int32_t W_NUMBERS; +extern int32_t WATERDRIP; +extern int32_t WATERBUBBLE; +extern int32_t WATERBUBBLEMAKER; +extern int32_t W_FORCEFIELD; +extern int32_t VACUUM; +extern int32_t FOOTPRINTS2; +extern int32_t FOOTPRINTS3; +extern int32_t FOOTPRINTS4; +extern int32_t EGG; +extern int32_t SCALE; +extern int32_t CHAIR3; +extern int32_t CAMERALIGHT; +extern int32_t MOVIECAMERA; +extern int32_t IVUNIT; +extern int32_t POT1; +extern int32_t POT2; +extern int32_t POT3; +extern int32_t PIPE3B; +extern int32_t WALLLIGHT3; +extern int32_t WALLLIGHTBUST3; +extern int32_t WALLLIGHT1; +extern int32_t WALLLIGHTBUST1; +extern int32_t WALLLIGHT2; +extern int32_t WALLLIGHTBUST2; +extern int32_t LIGHTSWITCH2; +extern int32_t WAITTOBESEATED; +extern int32_t DOORTILE14; +extern int32_t STATUE; +extern int32_t MIKE; +extern int32_t VASE; +extern int32_t SUSHIPLATE1; +extern int32_t SUSHIPLATE2; +extern int32_t SUSHIPLATE3; +extern int32_t SUSHIPLATE4; +extern int32_t DOORTILE16; +extern int32_t SUSHIPLATE5; +extern int32_t OJ; +extern int32_t MASKWALL13; +extern int32_t HURTRAIL; +extern int32_t POWERSWITCH1; +extern int32_t LOCKSWITCH1; +extern int32_t POWERSWITCH2; +extern int32_t ATM; +extern int32_t STATUEFLASH; +extern int32_t ATMBROKE; +extern int32_t BIGHOLE2; +extern int32_t STRIPEBALL; +extern int32_t QUEBALL; +extern int32_t POCKET; +extern int32_t WOODENHORSE; +extern int32_t TREE1; +extern int32_t TREE2; +extern int32_t CACTUS; +extern int32_t MASKWALL2; +extern int32_t MASKWALL3; +extern int32_t MASKWALL4; +extern int32_t FIREEXT; +extern int32_t TOILETWATER; +extern int32_t NEON1; +extern int32_t NEON2; +extern int32_t CACTUSBROKE; +extern int32_t BOUNCEMINE; +extern int32_t BROKEFIREHYDRENT; +extern int32_t BOX; +extern int32_t BULLETHOLE; +extern int32_t BOTTLE1; +extern int32_t BOTTLE2; +extern int32_t BOTTLE3; +extern int32_t BOTTLE4; +extern int32_t FEMPIC5; +extern int32_t FEMPIC6; +extern int32_t FEMPIC7; +extern int32_t HYDROPLANT; +extern int32_t OCEANSPRITE1; +extern int32_t OCEANSPRITE2; +extern int32_t OCEANSPRITE3; +extern int32_t OCEANSPRITE4; +extern int32_t OCEANSPRITE5; +extern int32_t GENERICPOLE; +extern int32_t CONE; +extern int32_t HANGLIGHT; +extern int32_t HYDRENT; +extern int32_t MASKWALL14; +extern int32_t TIRE; +extern int32_t PIPE5; +extern int32_t PIPE6; +extern int32_t PIPE4; +extern int32_t PIPE4B; +extern int32_t BROKEHYDROPLANT; +extern int32_t PIPE5B; +extern int32_t NEON3; +extern int32_t NEON4; +extern int32_t NEON5; +extern int32_t BOTTLE5; +extern int32_t BOTTLE6; +extern int32_t BOTTLE8; +extern int32_t SPOTLITE; +extern int32_t HANGOOZ; +extern int32_t MASKWALL15; +extern int32_t BOTTLE7; +extern int32_t HORSEONSIDE; +extern int32_t GLASSPIECES; +extern int32_t HORSELITE; +extern int32_t DONUTS; +extern int32_t NEON6; +extern int32_t MASKWALL6; +extern int32_t CLOCK; +extern int32_t RUBBERCAN; +extern int32_t BROKENCLOCK; +extern int32_t PLUG; +extern int32_t OOZFILTER; +extern int32_t FLOORPLASMA; +extern int32_t REACTOR; +extern int32_t REACTORSPARK; +extern int32_t REACTORBURNT; +extern int32_t DOORTILE15; +extern int32_t HANDSWITCH; +extern int32_t CIRCLEPANNEL; +extern int32_t CIRCLEPANNELBROKE; +extern int32_t PULLSWITCH; +extern int32_t MASKWALL8; +extern int32_t BIGHOLE; +extern int32_t ALIENSWITCH; +extern int32_t DOORTILE21; +extern int32_t HANDPRINTSWITCH; +extern int32_t BOTTLE10; +extern int32_t BOTTLE11; +extern int32_t BOTTLE12; +extern int32_t BOTTLE13; +extern int32_t BOTTLE14; +extern int32_t BOTTLE15; +extern int32_t BOTTLE16; +extern int32_t BOTTLE17; +extern int32_t BOTTLE18; +extern int32_t BOTTLE19; +extern int32_t DOORTILE17; +extern int32_t MASKWALL7; +extern int32_t JAILBARBREAK; +extern int32_t DOORTILE11; +extern int32_t DOORTILE12; +extern int32_t VENDMACHINE; +extern int32_t VENDMACHINEBROKE; +extern int32_t COLAMACHINE; +extern int32_t COLAMACHINEBROKE; +extern int32_t CRANEPOLE; +extern int32_t CRANE; +extern int32_t BARBROKE; +extern int32_t BLOODPOOL; +extern int32_t NUKEBARREL; +extern int32_t NUKEBARRELDENTED; +extern int32_t NUKEBARRELLEAKED; +extern int32_t CANWITHSOMETHING; +extern int32_t MONEY; +extern int32_t BANNER; +extern int32_t EXPLODINGBARREL; +extern int32_t EXPLODINGBARREL2; +extern int32_t FIREBARREL; +extern int32_t SEENINE; +extern int32_t SEENINEDEAD; +extern int32_t STEAM; +extern int32_t CEILINGSTEAM; +extern int32_t PIPE6B; +extern int32_t TRANSPORTERBEAM; +extern int32_t RAT; +extern int32_t TRASH; +extern int32_t FEMPIC1; +extern int32_t FEMPIC2; +extern int32_t BLANKSCREEN; +extern int32_t PODFEM1; +extern int32_t FEMPIC3; +extern int32_t FEMPIC4; +extern int32_t FEM1; +extern int32_t FEM2; +extern int32_t FEM3; +extern int32_t FEM5; +extern int32_t BLOODYPOLE; +extern int32_t FEM4; +extern int32_t FEM6; +extern int32_t FEM6PAD; +extern int32_t FEM8; +extern int32_t HELECOPT; +extern int32_t FETUSJIB; +extern int32_t HOLODUKE; +extern int32_t SPACEMARINE; +extern int32_t INDY; +extern int32_t FETUS; +extern int32_t FETUSBROKE; +extern int32_t MONK; +extern int32_t LUKE; +extern int32_t COOLEXPLOSION1; +extern int32_t WATERSPLASH2; +extern int32_t FIREVASE; +extern int32_t SCRATCH; +extern int32_t FEM7; +extern int32_t APLAYERTOP; +extern int32_t APLAYER; +extern int32_t PLAYERONWATER; +extern int32_t DUKELYINGDEAD; +extern int32_t DUKETORSO; +extern int32_t DUKEGUN; +extern int32_t DUKELEG; +extern int32_t SHARK; +extern int32_t BLOOD; +extern int32_t FIRELASER; +extern int32_t TRANSPORTERSTAR; +extern int32_t SPIT; +extern int32_t LOOGIE; +extern int32_t FIST; +extern int32_t FREEZEBLAST; +extern int32_t DEVISTATORBLAST; +extern int32_t SHRINKSPARK; +extern int32_t TONGUE; +extern int32_t MORTER; +extern int32_t SHRINKEREXPLOSION; +extern int32_t RADIUSEXPLOSION; +extern int32_t FORCERIPPLE; +extern int32_t LIZTROOP; +extern int32_t LIZTROOPRUNNING; +extern int32_t LIZTROOPSTAYPUT; +extern int32_t LIZTOP; +extern int32_t LIZTROOPSHOOT; +extern int32_t LIZTROOPJETPACK; +extern int32_t LIZTROOPDSPRITE; +extern int32_t LIZTROOPONTOILET; +extern int32_t LIZTROOPJUSTSIT; +extern int32_t LIZTROOPDUCKING; +extern int32_t HEADJIB1; +extern int32_t ARMJIB1; +extern int32_t LEGJIB1; +extern int32_t CANNONBALL; +extern int32_t OCTABRAIN; +extern int32_t OCTABRAINSTAYPUT; +extern int32_t OCTATOP; +extern int32_t OCTADEADSPRITE; +extern int32_t INNERJAW; +extern int32_t DRONE; +extern int32_t EXPLOSION2; +extern int32_t COMMANDER; +extern int32_t COMMANDERSTAYPUT; +extern int32_t RECON; +extern int32_t TANK; +extern int32_t PIGCOP; +extern int32_t PIGCOPSTAYPUT; +extern int32_t PIGCOPDIVE; +extern int32_t PIGCOPDEADSPRITE; +extern int32_t PIGTOP; +extern int32_t LIZMAN; +extern int32_t LIZMANSTAYPUT; +extern int32_t LIZMANSPITTING; +extern int32_t LIZMANFEEDING; +extern int32_t LIZMANJUMP; +extern int32_t LIZMANDEADSPRITE; +extern int32_t FECES; +extern int32_t LIZMANHEAD1; +extern int32_t LIZMANARM1; +extern int32_t LIZMANLEG1; +extern int32_t EXPLOSION2BOT; +extern int32_t USERWEAPON; +extern int32_t HEADERBAR; +extern int32_t JIBS1; +extern int32_t JIBS2; +extern int32_t JIBS3; +extern int32_t JIBS4; +extern int32_t JIBS5; +extern int32_t BURNING; +extern int32_t FIRE; +extern int32_t JIBS6; +extern int32_t BLOODSPLAT1; +extern int32_t BLOODSPLAT3; +extern int32_t BLOODSPLAT2; +extern int32_t BLOODSPLAT4; +extern int32_t OOZ; +extern int32_t OOZ2; +extern int32_t WALLBLOOD1; +extern int32_t WALLBLOOD2; +extern int32_t WALLBLOOD3; +extern int32_t WALLBLOOD4; +extern int32_t WALLBLOOD5; +extern int32_t WALLBLOOD6; +extern int32_t WALLBLOOD7; +extern int32_t WALLBLOOD8; +extern int32_t BURNING2; +extern int32_t FIRE2; +extern int32_t CRACKKNUCKLES; +extern int32_t SMALLSMOKE; +extern int32_t SMALLSMOKEMAKER; +extern int32_t FLOORFLAME; +extern int32_t ROTATEGUN; +extern int32_t GREENSLIME; +extern int32_t WATERDRIPSPLASH; +extern int32_t SCRAP6; +extern int32_t SCRAP1; +extern int32_t SCRAP2; +extern int32_t SCRAP3; +extern int32_t SCRAP4; +extern int32_t SCRAP5; +extern int32_t ORGANTIC; +extern int32_t BETAVERSION; +extern int32_t PLAYERISHERE; +extern int32_t PLAYERWASHERE; +extern int32_t SELECTDIR; +extern int32_t F1HELP; +extern int32_t NOTCHON; +extern int32_t NOTCHOFF; +extern int32_t GROWSPARK; +extern int32_t DUKEICON; +extern int32_t BADGUYICON; +extern int32_t FOODICON; +extern int32_t GETICON; +extern int32_t MENUSCREEN; +extern int32_t MENUBAR; +extern int32_t KILLSICON; +extern int32_t FIRSTAID_ICON; +extern int32_t HEAT_ICON; +extern int32_t BOTTOMSTATUSBAR; +extern int32_t BOOT_ICON; +extern int32_t FRAGBAR; +extern int32_t JETPACK_ICON; +extern int32_t AIRTANK_ICON; +extern int32_t STEROIDS_ICON; +extern int32_t HOLODUKE_ICON; +extern int32_t ACCESS_ICON; +extern int32_t DIGITALNUM; +extern int32_t DUKECAR; +extern int32_t CAMCORNER; +extern int32_t CAMLIGHT; +extern int32_t LOGO; +extern int32_t TITLE; +extern int32_t NUKEWARNINGICON; +extern int32_t MOUSECURSOR; +extern int32_t SLIDEBAR; +extern int32_t DREALMS; +extern int32_t BETASCREEN; +extern int32_t WINDOWBORDER1; +extern int32_t TEXTBOX; +extern int32_t WINDOWBORDER2; +extern int32_t DUKENUKEM; +extern int32_t THREEDEE; +extern int32_t INGAMEDUKETHREEDEE; +extern int32_t TENSCREEN; +extern int32_t PLUTOPAKSPRITE; +extern int32_t DEVISTATOR; +extern int32_t KNEE; +extern int32_t CROSSHAIR; +extern int32_t FIRSTGUN; +extern int32_t FIRSTGUNRELOAD; +extern int32_t FALLINGCLIP; +extern int32_t CLIPINHAND; +extern int32_t HAND; +extern int32_t SHELL; +extern int32_t SHOTGUNSHELL; +extern int32_t CHAINGUN; +extern int32_t RPGGUN; +extern int32_t RPGMUZZLEFLASH; +extern int32_t FREEZE; +extern int32_t CATLITE; +extern int32_t SHRINKER; +extern int32_t HANDHOLDINGLASER; +extern int32_t TRIPBOMB; +extern int32_t LASERLINE; +extern int32_t HANDHOLDINGACCESS; +extern int32_t HANDREMOTE; +extern int32_t HANDTHROW; +extern int32_t TIP; +extern int32_t GLAIR; +extern int32_t SCUBAMASK; +extern int32_t SPACEMASK; +extern int32_t FORCESPHERE; +extern int32_t SHOTSPARK1; +extern int32_t RPG; +extern int32_t LASERSITE; +extern int32_t SHOTGUN; +extern int32_t BOSS1; +extern int32_t BOSS1STAYPUT; +extern int32_t BOSS1SHOOT; +extern int32_t BOSS1LOB; +extern int32_t BOSSTOP; +extern int32_t BOSS2; +extern int32_t BOSS3; +extern int32_t SPINNINGNUKEICON; +extern int32_t BIGFNTCURSOR; +extern int32_t SMALLFNTCURSOR; +extern int32_t STARTALPHANUM; +extern int32_t ENDALPHANUM; +extern int32_t BIGALPHANUM; +extern int32_t BIGPERIOD; +extern int32_t BIGCOMMA; +extern int32_t BIGX_; +extern int32_t BIGQ; +extern int32_t BIGSEMI; +extern int32_t BIGCOLIN; +extern int32_t THREEBYFIVE; +extern int32_t BIGAPPOS; +extern int32_t BLANK; +extern int32_t MINIFONT; +extern int32_t BUTTON1; +extern int32_t GLASS3; +extern int32_t RESPAWNMARKERRED; +extern int32_t RESPAWNMARKERYELLOW; +extern int32_t RESPAWNMARKERGREEN; +extern int32_t BONUSSCREEN; +extern int32_t VIEWBORDER; +extern int32_t VICTORY1; +extern int32_t ORDERING; +extern int32_t TEXTSTORY; +extern int32_t LOADSCREEN; +extern int32_t BORNTOBEWILDSCREEN; +extern int32_t BLIMP; +extern int32_t FEM9; +extern int32_t FOOTPRINT; +extern int32_t POOP; +extern int32_t FRAMEEFFECT1; +extern int32_t PANNEL3; +extern int32_t SCREENBREAK14; +extern int32_t SCREENBREAK15; +extern int32_t SCREENBREAK19; +extern int32_t SCREENBREAK16; +extern int32_t SCREENBREAK17; +extern int32_t SCREENBREAK18; +extern int32_t W_TECHWALL11; +extern int32_t W_TECHWALL12; +extern int32_t W_TECHWALL13; +extern int32_t W_TECHWALL14; +extern int32_t W_TECHWALL5; +extern int32_t W_TECHWALL6; +extern int32_t W_TECHWALL7; +extern int32_t W_TECHWALL8; +extern int32_t W_TECHWALL9; +extern int32_t BPANNEL3; +extern int32_t W_HITTECHWALL16; +extern int32_t W_HITTECHWALL10; +extern int32_t W_HITTECHWALL15; +extern int32_t W_MILKSHELF; +extern int32_t W_MILKSHELFBROKE; +extern int32_t PURPLELAVA; +extern int32_t LAVABUBBLE; +extern int32_t DUKECUTOUT; +extern int32_t TARGET; +extern int32_t GUNPOWDERBARREL; +extern int32_t DUCK; +extern int32_t HATRACK; +extern int32_t DESKLAMP; +extern int32_t COFFEEMACHINE; +extern int32_t CUPS; +extern int32_t GAVALS; +extern int32_t GAVALS2; +extern int32_t POLICELIGHTPOLE; +extern int32_t FLOORBASKET; +extern int32_t PUKE; +extern int32_t DOORTILE23; +extern int32_t TOPSECRET; +extern int32_t SPEAKER; +extern int32_t TEDDYBEAR; +extern int32_t ROBOTDOG; +extern int32_t ROBOTPIRATE; +extern int32_t ROBOTMOUSE; +extern int32_t MAIL; +extern int32_t MAILBAG; +extern int32_t HOTMEAT; +extern int32_t COFFEEMUG; +extern int32_t DONUTS2; +extern int32_t TRIPODCAMERA; +extern int32_t METER; +extern int32_t DESKPHONE; +extern int32_t GUMBALLMACHINE; +extern int32_t GUMBALLMACHINEBROKE; +extern int32_t PAPER; +extern int32_t MACE; +extern int32_t GENERICPOLE2; +extern int32_t XXXSTACY; +extern int32_t WETFLOOR; +extern int32_t BROOM; +extern int32_t MOP; +extern int32_t LETTER; +extern int32_t PIRATE1A; +extern int32_t PIRATE4A; +extern int32_t PIRATE2A; +extern int32_t PIRATE5A; +extern int32_t PIRATE3A; +extern int32_t PIRATE6A; +extern int32_t PIRATEHALF; +extern int32_t CHESTOFGOLD; +extern int32_t SIDEBOLT1; +extern int32_t FOODOBJECT1; +extern int32_t FOODOBJECT2; +extern int32_t FOODOBJECT3; +extern int32_t FOODOBJECT4; +extern int32_t FOODOBJECT5; +extern int32_t FOODOBJECT6; +extern int32_t FOODOBJECT7; +extern int32_t FOODOBJECT8; +extern int32_t FOODOBJECT9; +extern int32_t FOODOBJECT10; +extern int32_t FOODOBJECT11; +extern int32_t FOODOBJECT12; +extern int32_t FOODOBJECT13; +extern int32_t FOODOBJECT14; +extern int32_t FOODOBJECT15; +extern int32_t FOODOBJECT16; +extern int32_t FOODOBJECT17; +extern int32_t FOODOBJECT18; +extern int32_t FOODOBJECT19; +extern int32_t FOODOBJECT20; +extern int32_t HEADLAMP; +extern int32_t TAMPON; +extern int32_t SKINNEDCHICKEN; +extern int32_t FEATHEREDCHICKEN; +extern int32_t ROBOTDOG2; +extern int32_t JOLLYMEAL; +extern int32_t DUKEBURGER; +extern int32_t SHOPPINGCART; +extern int32_t CANWITHSOMETHING2; +extern int32_t CANWITHSOMETHING3; +extern int32_t CANWITHSOMETHING4; +extern int32_t SNAKEP; +extern int32_t DOLPHIN1; +extern int32_t DOLPHIN2; +extern int32_t NEWBEAST; +extern int32_t NEWBEASTSTAYPUT; +extern int32_t NEWBEASTJUMP; +extern int32_t NEWBEASTHANG; +extern int32_t NEWBEASTHANGDEAD; +extern int32_t BOSS4; +extern int32_t BOSS4STAYPUT; +extern int32_t FEM10; +extern int32_t TOUGHGAL; +extern int32_t MAN; +extern int32_t MAN2; +extern int32_t WOMAN; +extern int32_t PLEASEWAIT; +extern int32_t NATURALLIGHTNING; +extern int32_t WEATHERWARN; +extern int32_t DUKETAG; +extern int32_t SIGN1; +extern int32_t SIGN2; +extern int32_t JURYGUY; +extern int32_t RRTILE11; +extern int32_t RPG2SPRITE; +extern int32_t RRTILE18; +extern int32_t RRTILE19; +extern int32_t RRTILE34; +extern int32_t RRTILE35; +extern int32_t DESTRUCTO; +extern int32_t RRTILE38; +extern int32_t RRTILE43; +extern int32_t GUTMETER; +extern int32_t RRTILE63; +extern int32_t RRTILE64; +extern int32_t RRTILE65; +extern int32_t RRTILE66; +extern int32_t RRTILE67; +extern int32_t RRTILE68; +extern int32_t SOUNDFX; +extern int32_t MOTOAMMO; +extern int32_t UFOBEAM; +extern int32_t RRTILE280; +extern int32_t RRTILE281; +extern int32_t RRTILE282; +extern int32_t RRTILE283; +extern int32_t RRTILE285; +extern int32_t RRTILE286; +extern int32_t RRTILE287; +extern int32_t RRTILE288; +extern int32_t RRTILE289; +extern int32_t RRTILE290; +extern int32_t RRTILE291; +extern int32_t RRTILE292; +extern int32_t RRTILE293; +extern int32_t RRTILE295; +extern int32_t RRTILE296; +extern int32_t RRTILE297; +extern int32_t CDPLAYER; +extern int32_t RRTILE380; +extern int32_t RRTILE403; +extern int32_t RRTILE409; +extern int32_t GUTMETER_LIGHT1; +extern int32_t GUTMETER_LIGHT2; +extern int32_t GUTMETER_LIGHT3; +extern int32_t GUTMETER_LIGHT4; +extern int32_t AMMO_ICON; +extern int32_t RRTILE1076; +extern int32_t MUD; +extern int32_t EXPLOSION3; +extern int32_t RRTILE1636; +extern int32_t WEAPONBAR; +extern int32_t RRTILE1752; +extern int32_t RPG2; +extern int32_t RRTILE1790; +extern int32_t RRTILE1792; +extern int32_t RRTILE1801; +extern int32_t RRTILE1805; +extern int32_t RRTILE1807; +extern int32_t RRTILE1808; +extern int32_t RRTILE1812; +extern int32_t RRTILE1814; +extern int32_t RRTILE1817; +extern int32_t RRTILE1821; +extern int32_t RRTILE1824; +extern int32_t RRTILE1826; +extern int32_t RRTILE1850; +extern int32_t RRTILE1851; +extern int32_t RRTILE1856; +extern int32_t RRTILE1877; +extern int32_t RRTILE1878; +extern int32_t RRTILE1938; +extern int32_t RRTILE1939; +extern int32_t RRTILE1942; +extern int32_t RRTILE1944; +extern int32_t RRTILE1945; +extern int32_t RRTILE1947; +extern int32_t RRTILE1951; +extern int32_t RRTILE1952; +extern int32_t RRTILE1953; +extern int32_t RRTILE1961; +extern int32_t RRTILE1964; +extern int32_t RRTILE1973; +extern int32_t RRTILE1985; +extern int32_t RRTILE1986; +extern int32_t RRTILE1987; +extern int32_t RRTILE1988; +extern int32_t RRTILE1990; +extern int32_t RRTILE1995; +extern int32_t RRTILE1996; +extern int32_t RRTILE2004; +extern int32_t RRTILE2005; +extern int32_t POPCORN; +extern int32_t RRTILE2022; +extern int32_t LANEPICS; +extern int32_t RRTILE2025; +extern int32_t RRTILE2026; +extern int32_t RRTILE2027; +extern int32_t RRTILE2028; +extern int32_t RRTILE2034; +extern int32_t RRTILE2050; +extern int32_t RRTILE2052; +extern int32_t RRTILE2053; +extern int32_t RRTILE2056; +extern int32_t RRTILE2060; +extern int32_t RRTILE2072; +extern int32_t RRTILE2074; +extern int32_t RRTILE2075; +extern int32_t RRTILE2083; +extern int32_t RRTILE2097; +extern int32_t RRTILE2121; +extern int32_t RRTILE2122; +extern int32_t RRTILE2123; +extern int32_t RRTILE2124; +extern int32_t RRTILE2125; +extern int32_t RRTILE2126; +extern int32_t RRTILE2137; +extern int32_t RRTILE2132; +extern int32_t RRTILE2136; +extern int32_t RRTILE2139; +extern int32_t RRTILE2150; +extern int32_t RRTILE2151; +extern int32_t RRTILE2152; +extern int32_t RRTILE2156; +extern int32_t RRTILE2157; +extern int32_t RRTILE2158; +extern int32_t RRTILE2159; +extern int32_t RRTILE2160; +extern int32_t RRTILE2161; +extern int32_t RRTILE2175; +extern int32_t RRTILE2176; +extern int32_t RRTILE2178; +extern int32_t RRTILE2186; +extern int32_t RRTILE2214; +extern int32_t RRTILE2319; +extern int32_t RRTILE2321; +extern int32_t RRTILE2326; +extern int32_t RRTILE2329; +extern int32_t RRTILE2357; +extern int32_t RRTILE2382; +extern int32_t RRTILE2430; +extern int32_t RRTILE2431; +extern int32_t RRTILE2432; +extern int32_t RRTILE2437; +extern int32_t RRTILE2443; +extern int32_t RRTILE2445; +extern int32_t RRTILE2446; +extern int32_t RRTILE2450; +extern int32_t RRTILE2451; +extern int32_t RRTILE2455; +extern int32_t RRTILE2460; +extern int32_t RRTILE2465; +extern int32_t RRTILE2560; +extern int32_t RRTILE2562; +extern int32_t RRTILE2564; +extern int32_t RRTILE2573; +extern int32_t RRTILE2574; +extern int32_t RRTILE2577; +extern int32_t RRTILE2578; +extern int32_t RRTILE2581; +extern int32_t RRTILE2583; +extern int32_t RRTILE2604; +extern int32_t RRTILE2610; +extern int32_t RRTILE2613; +extern int32_t RRTILE2621; +extern int32_t RRTILE2622; +extern int32_t RRTILE2636; +extern int32_t RRTILE2637; +extern int32_t RRTILE2654; +extern int32_t RRTILE2656; +extern int32_t RRTILE2676; +extern int32_t RRTILE2689; +extern int32_t RRTILE2697; +extern int32_t RRTILE2702; +extern int32_t RRTILE2707; +extern int32_t RRTILE2732; +extern int32_t RRTILE2030; +extern int32_t RRTILE2831; +extern int32_t RRTILE2832; +extern int32_t RRTILE2842; +extern int32_t RRTILE2859; +extern int32_t RRTILE2876; +extern int32_t RRTILE2878; +extern int32_t RRTILE2879; +extern int32_t RRTILE2893; +extern int32_t RRTILE2894; +extern int32_t RRTILE2898; +extern int32_t RRTILE2899; +extern int32_t RRTILE2915; +extern int32_t RRTILE2940; +extern int32_t RRTILE2944; +extern int32_t RRTILE2945; +extern int32_t RRTILE2946; +extern int32_t RRTILE2947; +extern int32_t RRTILE2948; +extern int32_t RRTILE2949; +extern int32_t RRTILE2961; +extern int32_t RRTILE2970; +extern int32_t RRTILE2977; +extern int32_t RRTILE2978; +extern int32_t RRTILE2990; +extern int32_t RRTILE3073; +extern int32_t RRTILE3083; +extern int32_t RRTILE3100; +extern int32_t RRTILE3114; +extern int32_t RRTILE3115; +extern int32_t RRTILE3116; +extern int32_t RRTILE3117; +extern int32_t RRTILE3120; +extern int32_t RRTILE3121; +extern int32_t RRTILE3122; +extern int32_t RRTILE3123; +extern int32_t RRTILE3124; +extern int32_t RRTILE3132; +extern int32_t RRTILE3139; +extern int32_t RRTILE3144; +extern int32_t RRTILE3152; +extern int32_t RRTILE3153; +extern int32_t RRTILE3155; +extern int32_t RRTILE3171; +extern int32_t RRTILE3172; +extern int32_t RRTILE3190; +extern int32_t RRTILE3191; +extern int32_t RRTILE3192; +extern int32_t RRTILE3195; +extern int32_t RRTILE3200; +extern int32_t RRTILE3201; +extern int32_t RRTILE3202; +extern int32_t RRTILE3203; +extern int32_t RRTILE3204; +extern int32_t RRTILE3205; +extern int32_t RRTILE3206; +extern int32_t RRTILE3207; +extern int32_t RRTILE3208; +extern int32_t RRTILE3209; +extern int32_t RRTILE3216; +extern int32_t RRTILE3218; +extern int32_t RRTILE3219; +extern int32_t RRTILE3232; +extern int32_t SHOTGUNSHELLS; +extern int32_t CIRCLESTUCK; +extern int32_t RRTILE3410; +extern int32_t LUMBERBLADE; +extern int32_t BOWLINGBALLH; +extern int32_t BOWLINGBALL; +extern int32_t BOWLINGBALLSPRITE; +extern int32_t POWDERH; +extern int32_t RRTILE3440; +extern int32_t RRTILE3462; +extern int32_t OWHIP; +extern int32_t UWHIP; +extern int32_t RPGGUN2; +extern int32_t RRTILE3497; +extern int32_t RRTILE3498; +extern int32_t RRTILE3499; +extern int32_t RRTILE3500; +extern int32_t SLINGBLADE; +extern int32_t RRTILE3584; +extern int32_t RRTILE3586; +extern int32_t RRTILE3587; +extern int32_t RRTILE3600; +extern int32_t RRTILE3631; +extern int32_t RRTILE3635; +extern int32_t RRTILE3637; +extern int32_t RRTILE3643; +extern int32_t RRTILE3647; +extern int32_t RRTILE3652; +extern int32_t RRTILE3653; +extern int32_t RRTILE3668; +extern int32_t RRTILE3671; +extern int32_t RRTILE3673; +extern int32_t RRTILE3677; +extern int32_t RRTILE3684; +extern int32_t RRTILE3708; +extern int32_t RRTILE3714; +extern int32_t RRTILE3716; +extern int32_t RRTILE3720; +extern int32_t RRTILE3723; +extern int32_t RRTILE3725; +extern int32_t RRTILE3737; +extern int32_t RRTILE3754; +extern int32_t RRTILE3762; +extern int32_t RRTILE3763; +extern int32_t RRTILE3764; +extern int32_t RRTILE3765; +extern int32_t RRTILE3767; +extern int32_t RRTILE3773; +extern int32_t RRTILE3774; +extern int32_t RRTILE3793; +extern int32_t RRTILE3795; +extern int32_t RRTILE3804; +extern int32_t RRTILE3814; +extern int32_t RRTILE3815; +extern int32_t RRTILE3819; +extern int32_t RRTILE3827; +extern int32_t RRTILE3837; +extern int32_t RRTILE5014; +extern int32_t RRTILE5016; +extern int32_t RRTILE5017; +extern int32_t RRTILE5018; +extern int32_t RRTILE5019; +extern int32_t RRTILE5020; +extern int32_t RRTILE5021; +extern int32_t RRTILE5022; +extern int32_t RRTILE5023; +extern int32_t RRTILE5024; +extern int32_t RRTILE5025; +extern int32_t RRTILE5026; +extern int32_t RRTILE5027; +extern int32_t RRTILE5029; +extern int32_t RRTILE5030; +extern int32_t RRTILE5031; +extern int32_t RRTILE5032; +extern int32_t RRTILE5033; +extern int32_t RRTILE5034; +extern int32_t RRTILE5035; +extern int32_t RRTILE5036; +extern int32_t RRTILE5037; +extern int32_t RRTILE5038; +extern int32_t RRTILE5039; +extern int32_t RRTILE5040; +extern int32_t RRTILE5041; +extern int32_t RRTILE5043; +extern int32_t RRTILE5044; +extern int32_t RRTILE5045; +extern int32_t RRTILE5046; +extern int32_t RRTILE5047; +extern int32_t RRTILE5048; +extern int32_t RRTILE5049; +extern int32_t RRTILE5050; +extern int32_t RRTILE5051; +extern int32_t RRTILE5052; +extern int32_t RRTILE5053; +extern int32_t RRTILE5054; +extern int32_t RRTILE5055; +extern int32_t RRTILE5056; +extern int32_t RRTILE5057; +extern int32_t RRTILE5058; +extern int32_t RRTILE5059; +extern int32_t RRTILE5061; +extern int32_t RRTILE5062; +extern int32_t RRTILE5063; +extern int32_t RRTILE5064; +extern int32_t RRTILE5065; +extern int32_t RRTILE5066; +extern int32_t RRTILE5067; +extern int32_t RRTILE5068; +extern int32_t RRTILE5069; +extern int32_t RRTILE5070; +extern int32_t RRTILE5071; +extern int32_t RRTILE5072; +extern int32_t RRTILE5073; +extern int32_t RRTILE5074; +extern int32_t RRTILE5075; +extern int32_t RRTILE5076; +extern int32_t RRTILE5077; +extern int32_t RRTILE5078; +extern int32_t RRTILE5079; +extern int32_t RRTILE5080; +extern int32_t RRTILE5081; +extern int32_t RRTILE5082; +extern int32_t RRTILE5083; +extern int32_t RRTILE5084; +extern int32_t RRTILE5085; +extern int32_t RRTILE5086; +extern int32_t RRTILE5087; +extern int32_t RRTILE5088; +extern int32_t RRTILE5090; +extern int32_t RRTILE6144; +extern int32_t RRTILE7110; +extern int32_t RRTILE7111; +extern int32_t RRTILE7112; +extern int32_t RRTILE7113; +extern int32_t MOTOGUN; +extern int32_t RRTILE7169; +extern int32_t MOTOHIT; +extern int32_t BOATHIT; +extern int32_t RRTILE7184; +extern int32_t RRTILE7190; +extern int32_t RRTILE7191; +extern int32_t RRTILE7213; +extern int32_t RRTILE7219; +extern int32_t EMPTYBIKE; +extern int32_t EMPTYBOAT; +extern int32_t RRTILE7424; +extern int32_t RRTILE7430; +extern int32_t RRTILE7433; +extern int32_t RRTILE7441; +extern int32_t RRTILE7547; +extern int32_t RRTILE7467; +extern int32_t RRTILE7469; +extern int32_t RRTILE7470; +extern int32_t RRTILE7475; +extern int32_t RRTILE7478; +extern int32_t RRTILE7505; +extern int32_t RRTILE7506; +extern int32_t RRTILE7534; +extern int32_t RRTILE7540; +extern int32_t RRTILE7533; +extern int32_t RRTILE7545; +extern int32_t RRTILE7552; +extern int32_t RRTILE7553; +extern int32_t RRTILE7554; +extern int32_t RRTILE7555; +extern int32_t RRTILE7557; +extern int32_t RRTILE7558; +extern int32_t RRTILE7559; +extern int32_t RRTILE7561; +extern int32_t RRTILE7566; +extern int32_t RRTILE7568; +extern int32_t RRTILE7574; +extern int32_t RRTILE7575; +extern int32_t RRTILE7576; +extern int32_t RRTILE7578; +extern int32_t RRTILE7579; +extern int32_t RRTILE7580; +extern int32_t RRTILE7595; +extern int32_t RRTILE7629; +extern int32_t RRTILE7636; +extern int32_t RRTILE7638; +extern int32_t RRTILE7640; +extern int32_t RRTILE7644; +extern int32_t RRTILE7646; +extern int32_t RRTILE7648; +extern int32_t RRTILE7650; +extern int32_t RRTILE7653; +extern int32_t RRTILE7655; +extern int32_t RRTILE7657; +extern int32_t RRTILE7659; +extern int32_t RRTILE7691; +extern int32_t RRTILE7694; +extern int32_t RRTILE7696; +extern int32_t RRTILE7697; +extern int32_t RRTILE7700; +extern int32_t RRTILE7702; +extern int32_t RRTILE7704; +extern int32_t RRTILE7705; +extern int32_t RRTILE7711; +extern int32_t RRTILE7716; +extern int32_t RRTILE7756; +extern int32_t RRTILE7768; +extern int32_t RRTILE7806; +extern int32_t RRTILE7820; +extern int32_t RRTILE7870; +extern int32_t RRTILE7873; +extern int32_t RRTILE7859; +extern int32_t RRTILE7875; +extern int32_t RRTILE7876; +extern int32_t RRTILE7879; +extern int32_t RRTILE7881; +extern int32_t RRTILE7883; +extern int32_t RRTILE7885; +extern int32_t RRTILE7886; +extern int32_t RRTILE7887; +extern int32_t RRTILE7888; +extern int32_t RRTILE7889; +extern int32_t RRTILE7890; +extern int32_t RRTILE7900; +extern int32_t RRTILE7901; +extern int32_t RRTILE7906; +extern int32_t RRTILE7912; +extern int32_t RRTILE7913; +extern int32_t RRTILE7936; +extern int32_t RRTILE8047; +extern int32_t MULTISWITCH2; +extern int32_t RRTILE8059; +extern int32_t RRTILE8060; +extern int32_t RRTILE8063; +extern int32_t RRTILE8067; +extern int32_t RRTILE8076; +extern int32_t RRTILE8094; +extern int32_t RRTILE8096; +extern int32_t RRTILE8099; +extern int32_t RRTILE8106; +extern int32_t RRTILE8162; +extern int32_t RRTILE8163; +extern int32_t RRTILE8164; +extern int32_t RRTILE8165; +extern int32_t RRTILE8166; +extern int32_t RRTILE8167; +extern int32_t RRTILE8168; +extern int32_t RRTILE8192; +extern int32_t RRTILE8193; +extern int32_t RRTILE8215; +extern int32_t RRTILE8216; +extern int32_t RRTILE8217; +extern int32_t RRTILE8218; +extern int32_t RRTILE8220; +extern int32_t RRTILE8221; +extern int32_t RRTILE8222; +extern int32_t RRTILE8223; +extern int32_t RRTILE8224; +extern int32_t RRTILE8227; +extern int32_t RRTILE8312; +extern int32_t RRTILE8370; +extern int32_t RRTILE8371; +extern int32_t RRTILE8372; +extern int32_t RRTILE8373; +extern int32_t RRTILE8379; +extern int32_t RRTILE8380; +extern int32_t RRTILE8385; +extern int32_t RRTILE8386; +extern int32_t RRTILE8387; +extern int32_t RRTILE8388; +extern int32_t RRTILE8389; +extern int32_t RRTILE8390; +extern int32_t RRTILE8391; +extern int32_t RRTILE8392; +extern int32_t RRTILE8394; +extern int32_t RRTILE8395; +extern int32_t RRTILE8396; +extern int32_t RRTILE8397; +extern int32_t RRTILE8398; +extern int32_t RRTILE8399; +extern int32_t RRTILE8423; +extern int32_t RRTILE8448; +extern int32_t RRTILE8450; +extern int32_t BOATAMMO; +extern int32_t RRTILE8461; +extern int32_t RRTILE8462; +extern int32_t RRTILE8464; +extern int32_t RRTILE8475; +extern int32_t RRTILE8487; +extern int32_t RRTILE8488; +extern int32_t RRTILE8489; +extern int32_t RRTILE8490; +extern int32_t RRTILE8496; +extern int32_t RRTILE8497; +extern int32_t RRTILE8498; +extern int32_t RRTILE8499; +extern int32_t RRTILE8503; +extern int32_t RRTILE8525; +extern int32_t RRTILE8537; +extern int32_t RRTILE8565; +extern int32_t RRTILE8567; +extern int32_t RRTILE8568; +extern int32_t RRTILE8569; +extern int32_t RRTILE8570; +extern int32_t RRTILE8571; +extern int32_t RRTILE8579; +extern int32_t RRTILE8588; +extern int32_t RRTILE8589; +extern int32_t RRTILE8590; +extern int32_t RRTILE8591; +extern int32_t RRTILE8592; +extern int32_t RRTILE8593; +extern int32_t RRTILE8594; +extern int32_t RRTILE8595; +extern int32_t RRTILE8596; +extern int32_t RRTILE8598; +extern int32_t RRTILE8605; +extern int32_t RRTILE8608; +extern int32_t RRTILE8609; +extern int32_t RRTILE8611; +extern int32_t RRTILE8617; +extern int32_t RRTILE8618; +extern int32_t RRTILE8620; +extern int32_t RRTILE8621; +extern int32_t RRTILE8622; +extern int32_t RRTILE8623; +extern int32_t RRTILE8624; +extern int32_t RRTILE8640; +extern int32_t RRTILE8651; +extern int32_t RRTILE8660; +extern int32_t RRTILE8677; +extern int32_t RRTILE8679; +extern int32_t RRTILE8680; +extern int32_t RRTILE8681; +extern int32_t RRTILE8682; +extern int32_t RRTILE8683; +extern int32_t RRTILE8704; +extern int32_t BOULDER; +extern int32_t BOULDER1; +extern int32_t TORNADO; +extern int32_t CHEERBOMB; +extern int32_t CHEERBLADE; +extern int32_t DOGATTACK; +extern int32_t BILLYWALK; +extern int32_t BILLYDIE; +extern int32_t BILLYCOCK; +extern int32_t BILLYRAY; +extern int32_t BILLYRAYSTAYPUT; +extern int32_t BILLYBUT; +extern int32_t BILLYSCRATCH; +extern int32_t BILLYSNIFF; +extern int32_t BILLYWOUND; +extern int32_t BILLYGORE; +extern int32_t BILLYJIBA; +extern int32_t BILLYJIBB; +extern int32_t BRAYSNIPER; +extern int32_t DOGRUN; +extern int32_t DOGDIE; +extern int32_t DOGDEAD; +extern int32_t DOGBARK; +extern int32_t LTH; +extern int32_t LTHSTRAFE; +extern int32_t HULKHANG; +extern int32_t HULKHANGDEAD; +extern int32_t HULKJUMP; +extern int32_t LTHLOAD; +extern int32_t LTHDIE; +extern int32_t BUBBASCRATCH; +extern int32_t BUBBANOSE; +extern int32_t BUBBAPISS; +extern int32_t BUBBASTAND; +extern int32_t BUBBAOUCH; +extern int32_t BUBBADIE; +extern int32_t BUBBADEAD; +extern int32_t HULK; +extern int32_t HULKSTAYPUT; +extern int32_t HULKA; +extern int32_t HULKB; +extern int32_t HULKC; +extern int32_t HULKJIBA; +extern int32_t HULKJIBB; +extern int32_t HULKJIBC; +extern int32_t SBSWIPE; +extern int32_t SBPAIN; +extern int32_t SBDIE; +extern int32_t HEN; +extern int32_t HENSTAYPUT; +extern int32_t HENSTAND; +extern int32_t PIG; +extern int32_t PIGSTAYPUT; +extern int32_t PIGEAT; +extern int32_t SBMOVE; +extern int32_t SBSPIT; +extern int32_t SBDIP; +extern int32_t MINION; +extern int32_t MINIONSTAYPUT; +extern int32_t UFO1; +extern int32_t UFO2; +extern int32_t UFO3; +extern int32_t UFO4; +extern int32_t UFO5; +extern int32_t MINJIBA; +extern int32_t MINJIBB; +extern int32_t MINJIBC; +extern int32_t COW; +extern int32_t COOT; +extern int32_t COOTSTAYPUT; +extern int32_t COOTSHOOT; +extern int32_t COOTDIE; +extern int32_t COOTDUCK; +extern int32_t COOTPAIN; +extern int32_t COOTTRANS; +extern int32_t COOTGETUP; +extern int32_t COOTJIBA; +extern int32_t COOTJIBB; +extern int32_t COOTJIBC; +extern int32_t VIXEN; +extern int32_t VIXENPAIN; +extern int32_t VIXENDIE; +extern int32_t VIXENSHOOT; +extern int32_t VIXENWDN; +extern int32_t VIXENWUP; +extern int32_t VIXENKICK; +extern int32_t VIXENTELE; +extern int32_t VIXENTEAT; +extern int32_t BIKEJIBA; +extern int32_t BIKEJIBB; +extern int32_t BIKEJIBC; +extern int32_t BIKERB; +extern int32_t BIKERBV2; +extern int32_t BIKER; +extern int32_t BIKERJIBA; +extern int32_t BIKERJIBB; +extern int32_t BIKERJIBC; +extern int32_t BIKERJIBD; +extern int32_t MAKEOUT; +extern int32_t CHEERB; +extern int32_t CHEER; +extern int32_t CHEERSTAYPUT; +extern int32_t CHEERJIBA; +extern int32_t CHEERJIBB; +extern int32_t CHEERJIBC; +extern int32_t CHEERJIBD; +extern int32_t FBOATJIBA; +extern int32_t FBOATJIBB; +extern int32_t COOTPLAY; +extern int32_t BILLYPLAY; +extern int32_t MINIONBOAT; +extern int32_t HULKBOAT; +extern int32_t CHEERBOAT; +extern int32_t RRTILE7274; +extern int32_t RABBIT; +extern int32_t RABBITJIBA; +extern int32_t RABBITJIBB; +extern int32_t RABBITJIBC; +extern int32_t ROCK; +extern int32_t ROCK2; +extern int32_t MAMACLOUD; +extern int32_t MAMA; +extern int32_t MAMAJIBA; +extern int32_t MAMAJIBB; + +#define DYNAMICTILEMAP(Tilenum) (DynamicTileMap[Tilenum]) + + +enum dukeweapon_t +{ + KNEE_WEAPON__STATIC, // 0 + PISTOL_WEAPON__STATIC, + SHOTGUN_WEAPON__STATIC, + CHAINGUN_WEAPON__STATIC, + RPG_WEAPON__STATIC, + HANDBOMB_WEAPON__STATIC, // 5 + SHRINKER_WEAPON__STATIC, + DEVISTATOR_WEAPON__STATIC, + TRIPBOMB_WEAPON__STATIC, + FREEZE_WEAPON__STATIC, + HANDREMOTE_WEAPON__STATIC, // 10 + GROW_WEAPON__STATIC, + BOWLINGBALL_WEAPON__STATIC, + MOTORCYCLE_WEAPON__STATIC, + BOAT_WEAPON__STATIC, + SLINGBLADE_WEAPON__STATIC, // 15 + CHICKEN_WEAPON__STATIC, + MAX_WEAPONS +}; + +extern int16_t DynamicWeaponMap[MAX_WEAPONS]; + +extern int32_t KNEE_WEAPON; +extern int32_t PISTOL_WEAPON; +extern int32_t SHOTGUN_WEAPON; +extern int32_t CHAINGUN_WEAPON; +extern int32_t RPG_WEAPON; +extern int32_t HANDBOMB_WEAPON; +extern int32_t SHRINKER_WEAPON; +extern int32_t DEVISTATOR_WEAPON; +extern int32_t TRIPBOMB_WEAPON; +extern int32_t FREEZE_WEAPON; +extern int32_t HANDREMOTE_WEAPON; +extern int32_t GROW_WEAPON; +extern int32_t BOWLINGBALL_WEAPON; +extern int32_t MOTORCYCLE_WEAPON; +extern int32_t BOAT_WEAPON; +extern int32_t SLINGBLADE_WEAPON; +extern int32_t CHICKEN_WEAPON; + +#define DYNAMICWEAPONMAP(Weaponnum) (DynamicWeaponMap[Weaponnum]) + +END_DUKE_NS + +#endif // namesdyn_h__ diff --git a/source/duke/src/net.cpp b/source/duke/src/net.cpp new file mode 100644 index 000000000..0a89fa6bf --- /dev/null +++ b/source/duke/src/net.cpp @@ -0,0 +1,3830 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- +#include "ns.h" // Must come before everything else! + +#ifndef NETWORK_DISABLE +#include "enet.h" +#endif + +#include "duke3d.h" +#include "game.h" +#include "gamedef.h" +#include "net.h" +#include "premap.h" +#include "savegame.h" + +#include "m_crc32.h" +#include "mapinfo.h" + +BEGIN_DUKE_NS + +#define TIMERUPDATESIZ 32 + +ENetHost *g_netServer = NULL; +ENetHost *g_netClient = NULL; +ENetPeer *g_netClientPeer = NULL; +ENetPeer* g_netPlayerPeer[MAXPLAYERS]; +enet_uint16 g_netPort = 23513; +int32_t g_netDisconnect = 0; +char g_netPassword[32]; +int32_t g_netPlayersWaiting = 0; +#ifndef NETCODE_DISABLE +int32_t g_networkMode = NET_CLIENT; +#endif +int32_t g_netIndex = 2; +newgame_t pendingnewgame; + +#ifdef NETCODE_DISABLE +void faketimerhandler(void) {} +#else + +static char recbuf[180]; +static int32_t g_chatPlayer = -1; + + +// sync a connecting player up with the current game state +void Net_SyncPlayer(ENetEvent *event) +{ + int32_t i, j; + + if (numplayers + g_netPlayersWaiting >= MAXPLAYERS) + { + enet_peer_disconnect_later(event->peer, DISC_SERVER_FULL); + Printf("Refused peer; server full.\n"); + return; + } + + g_netPlayersWaiting++; + + S_PlaySound(DUKE_GETWEAPON2); + + // open a new slot if necessary and save off the resulting slot # for future reference + for (TRAVERSE_CONNECT(i)) + { + if (g_player[i].playerquitflag == 0) + { + break; + } + } + + if (i == -1) + { + i = g_mostConcurrentPlayers++; + } + + event->peer->data = (void *)(intptr_t)i; + + //g_player[i].netsynctime = totalclock; + g_player[i].playerquitflag = 1; + //g_player[i].revision = g_netMapRevision; + + for (j=0; jpeer); + Net_SendClientInfo(); + Net_SendUserMapName(); + // Net_SendNewGame(0, event->peer); +} + +//void Net_SpawnPlayer(int32_t player) +//{ +// int32_t j = 0; +// packbuf[j++] = PACKET_PLAYER_SPAWN; +// packbuf[j++] = player; +// +// Bmemcpy(&packbuf[j], &g_player[player].ps->pos.x, sizeof(vec3_t) * 2); +// j += sizeof(vec3_t) * 2; +// +// packbuf[j++] = 0; +// +// enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(packbuf, j, ENET_PACKET_FLAG_RELIABLE)); +//} + +static void display_betascreen(void) +{ + rotatesprite_fs(160<<16,100<<16,65536,0,BETASCREEN,0,0,2+8+64+BGSTRETCH, nullptr, TITLEPAL); + + rotatesprite_fs(160<<16,(104)<<16,60<<10,0,DUKENUKEM,0,0,2+8, nullptr, TITLEPAL); + rotatesprite_fs(160<<16,(129)<<16,30<<11,0,THREEDEE,0,0,2+8, nullptr, TITLEPAL); + if (PLUTOPAK) // JBF 20030804 + rotatesprite_fs(160<<16,(151)<<16,30<<11,0,PLUTOPAKSPRITE+1,0,0,2+8, nullptr, TITLEPAL); +} + +void faketimerhandler(void) +{ + if (g_netServer==NULL && g_netClient==NULL) + return; + + enet_host_service(g_netServer ? g_netServer : g_netClient, NULL, 0); + + //Net_Update(); +} + +void Net_WaitForEverybody(void) +{ + if (numplayers < 2) return; + + packbuf[0] = PACKET_TYPE_PLAYER_READY; + g_player[myconnectindex].playerreadyflag++; + + // if we're a peer or slave, not a master + if ((g_networkBroadcastMode == 1) || (!g_networkBroadcastMode && (myconnectindex != connecthead))) + for (int TRAVERSE_CONNECT(i)) + { + if (i != myconnectindex) Net_SendPacket(i, packbuf, 1); + if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) break; //slaves in M/S mode only send to master + } + + + do + { + if (G_FPSLimit()) + { + display_betascreen(); + gametext_center_shade(170, "Waiting for players", 14); + videoNextPage(); + }; + + G_HandleAsync(); + Net_GetPackets(); + + int i; + for (TRAVERSE_CONNECT(i)) + { + if (g_player[i].playerreadyflag < g_player[myconnectindex].playerreadyflag) break; + if ((!g_networkBroadcastMode) && (myconnectindex != connecthead)) + { + // we're a slave + i = -1; break; + } + //slaves in M/S mode only wait for master + } + if (i < 0) + { + // master sends ready packet once it hears from all slaves + if (!g_networkBroadcastMode && myconnectindex == connecthead) + for (int TRAVERSE_CONNECT(i)) + { + packbuf[0] = PACKET_TYPE_PLAYER_READY; + if (i != myconnectindex) Net_SendPacket(i, packbuf, 1); + } + + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); + return; + } + } + while (1); +} + +void Net_ResetPrediction(void) +{ + mypos = omypos = g_player[myconnectindex].ps->pos; + myvel = { 0, 0, 0 }; + myang = omyang = g_player[myconnectindex].ps->q16ang; + myhoriz = omyhoriz = g_player[myconnectindex].ps->q16horiz; + myhorizoff = omyhorizoff = g_player[myconnectindex].ps->q16horizoff; + mycursectnum = g_player[myconnectindex].ps->cursectnum; + myjumpingcounter = g_player[myconnectindex].ps->jumping_counter; + myjumpingtoggle = g_player[myconnectindex].ps->jumping_toggle; + myonground = g_player[myconnectindex].ps->on_ground; + myhardlanding = g_player[myconnectindex].ps->hard_landing; + myreturntocenter = g_player[myconnectindex].ps->return_to_center; + my_moto_speed = g_player[myconnectindex].ps->moto_speed; + my_not_on_water = g_player[myconnectindex].ps->not_on_water; + my_moto_on_ground = g_player[myconnectindex].ps->moto_on_ground; + my_moto_do_bump = g_player[myconnectindex].ps->moto_do_bump; + my_moto_bump_fast = g_player[myconnectindex].ps->moto_bump_fast; + my_moto_on_oil = g_player[myconnectindex].ps->moto_on_oil; + my_moto_on_mud = g_player[myconnectindex].ps->moto_on_mud; + my_moto_bump = g_player[myconnectindex].ps->moto_do_bump; + my_moto_bump_target = g_player[myconnectindex].ps->moto_bump_target; + my_moto_turb = g_player[myconnectindex].ps->moto_turb; + my_stairs = g_player[myconnectindex].ps->stairs; +} + +void Net_DoPrediction(void) +{ + DukePlayer_t *const pPlayer = g_player[myconnectindex].ps; + spritetype *const pSprite = &sprite[pPlayer->i]; + + input_t *const pInput = &inputfifo[predictfifoplc&(MOVEFIFOSIZ-1)][myconnectindex]; + + int16_t backcstat = pSprite->cstat; + pSprite->cstat &= ~257; + + uint32_t playerBits = pInput->bits; + + if (RRRA) + { + if (pPlayer->on_motorcycle && pSprite->extra > 0) + { + int var64, var68, var6c, var74, var7c; + if (my_moto_speed < 0) + my_moto_speed = 0; + if (TEST_SYNC_KEY(playerBits, SK_CROUCH)) + { + var64 = 1; + playerBits &= ~(1< 0) + { + if (my_moto_on_oil) + my_moto_speed -= 2; + else + my_moto_speed -= 4; + if (my_moto_speed < 0) + my_moto_speed = 0; + my_moto_bump_target = -30; + my_moto_do_bump = 1; + } + else if (var68 && !var64) + { + if (my_moto_speed < 40) + { + my_moto_bump_target = 70; + my_moto_bump_fast = 1; + } + my_moto_speed += 2; + if (my_moto_speed > 120) + my_moto_speed = 120; + if (!my_not_on_water) + if (my_moto_speed > 80) + my_moto_speed = 80; + } + else if (my_moto_speed > 0) + my_moto_speed--; + if (my_moto_do_bump && (!var64 || my_moto_speed == 0)) + { + my_moto_bump_target = 0; + my_moto_do_bump = 0; + } + if (var6c && my_moto_speed <= 0 && !var64) + { + int var88; + my_moto_speed = -15; + var88 = var7c; + var7c = var74; + var74 = var88; + } + } + if (my_moto_speed != 0 && myonground == 1) + { + if (!my_moto_bump) + if ((g_globalRandom&3) == 2) + my_moto_bump_target = (my_moto_speed>>4)*((randomseed&7)-4); + } + if (my_moto_turb) + { + if (my_moto_turb <= 1) + { + myhoriz = F16(100); + my_moto_turb = 0; + my_moto_bump = 0; + } + else + { + myhoriz = F16(100+(g_globalRandom&15)-7); + my_moto_turb--; + } + } + else if (my_moto_bump_target > my_moto_bump) + { + if (my_moto_bump_fast) + my_moto_bump += 6; + else + my_moto_bump++; + if (my_moto_bump_target < my_moto_bump) + my_moto_bump = my_moto_bump_target; + myhoriz = F16(100+my_moto_bump/3); + } + else if (my_moto_bump_target < my_moto_bump) + { + if (my_moto_bump_fast) + my_moto_bump -= 6; + else + my_moto_bump--; + if (my_moto_bump_target > my_moto_bump) + my_moto_bump = my_moto_bump_target; + myhoriz = F16(100+my_moto_bump/3); + } + else + { + my_moto_bump_fast = 0; + } + if (my_moto_speed >= 20 && myonground == 1 && (var74 || var7c)) + { + short var8c, var90, var94, var98; + var8c = my_moto_speed; + var90 = fix16_to_int(myang); + if (var74) + var94 = -10; + else + var94 = 10; + if (var94 < 0) + var98 = 350; + else + var98 = -350; + if (my_moto_on_mud || my_moto_on_oil || !my_not_on_water) + { + if (my_moto_on_oil) + var8c <<= 3; + else + var8c <<= 2; + if (my_moto_do_bump) + { + myvel.x += (var8c>>5)*(sintable[(var94*-51+var90+512)&2047]<<4); + myvel.y += (var8c>>5)*(sintable[(var94*-51+var90)&2047]<<4); + myang = F16((var90-(var98>>2))&2047); + } + else + { + myvel.x += (var8c>>7)*(sintable[(var94*-51+var90+512)&2047]<<4); + myvel.y += (var8c>>7)*(sintable[(var94*-51+var90)&2047]<<4); + myang = F16((var90-(var98>>6))&2047); + } + my_moto_on_mud = 0; + my_moto_on_oil = 0; + } + else + { + if (my_moto_do_bump) + { + myvel.x += (var8c >> 5)*(sintable[(var94*-51 + var90 + 512) & 2047] << 4); + myvel.y += (var8c>>5)*(sintable[(var94*-51+var90)&2047]<<4); + myang = F16((var90-(var98>>4))&2047); + } + else + { + myvel.x += (var8c >> 7)*(sintable[(var94*-51 + var90 + 512) & 2047] << 4); + myvel.y += (var8c>>7)*(sintable[(var94*-51+var90)&2047]<<4); + myang = F16((var90-(var98>>7))&2047); + } + } + } + else if (my_moto_speed >= 20 && myonground == 1 && (my_moto_on_mud || my_moto_on_oil)) + { + short var9c, vara0; + var9c = my_moto_speed; + vara0 = fix16_to_int(myang); + if (my_moto_on_oil) + var9c *= 10; + else + var9c *= 5; + myvel.x += (var9c>>7)*(sintable[(vara0+512)&2047]<<4); + myvel.y += (var9c>>7)*(sintable[(vara0)&2047]<<4); + } + my_moto_on_mud = 0; + my_moto_on_oil = 0; + } + else if (pPlayer->on_boat && pSprite->extra > 0) + { + int vara8, varac, varb0, varb4, varbc, varc4; + if (my_moto_speed < 0) + my_moto_speed = 0; + if (TEST_SYNC_KEY(playerBits, SK_CROUCH) && TEST_SYNC_KEY(playerBits, SK_JUMP)) + { + vara8 = 1; + varac = 0; + playerBits &= ~(1< 0) + { + my_moto_speed -= 2; + if (my_moto_speed < 0) + my_moto_speed = 0; + my_moto_bump_target = 30; + my_moto_do_bump = 1; + } + else if (varac) + { + if (my_moto_speed < 40) + if (!my_not_on_water) + { + my_moto_bump_target = -30; + my_moto_bump_fast = 1; + } + my_moto_speed++; + if (my_moto_speed > 120) + my_moto_speed = 120; + } + else if (my_moto_speed > 0) + my_moto_speed--; + if (my_moto_do_bump && (!varb0 || my_moto_speed == 0)) + { + my_moto_bump_target = 0; + my_moto_do_bump = 0; + } + if (varb4 && my_moto_speed == 0 && !varb0) + { + int vard0; + if (!my_not_on_water) + my_moto_speed = -25; + else + my_moto_speed = -20; + vard0 = varc4; + varc4 = varbc; + varbc = vard0; + } + } + if (my_moto_speed != 0 && myonground == 1) + { + if (!my_moto_bump) + if ((g_globalRandom & 15) == 14) + my_moto_bump_target = (my_moto_speed>>4)*((randomseed&3)-2); + } + if (my_moto_turb) + { + if (my_moto_turb <= 1) + { + myhoriz = F16(100); + my_moto_turb = 0; + my_moto_bump_target = 0; + my_moto_bump = 0; + } + else + { + myhoriz = F16(100+((g_globalRandom&15)-7)); + my_moto_turb--; + } + } + else if (my_moto_bump_target > my_moto_bump) + { + if (my_moto_bump_fast) + my_moto_bump += 6; + else + my_moto_bump++; + if (my_moto_bump_target < my_moto_bump) + my_moto_bump = my_moto_bump_target; + myhoriz = F16(100+my_moto_bump/3); + } + else if (my_moto_bump_target < my_moto_bump) + { + if (my_moto_bump_fast) + my_moto_bump -= 6; + else + my_moto_bump--; + if (my_moto_bump_target > my_moto_bump) + my_moto_bump = my_moto_bump_target; + myhoriz = F16(100+my_moto_bump/3); + } + else + { + my_moto_bump_target = 0; + my_moto_bump_fast = 0; + } + if (my_moto_speed > 0 && myonground == 1 && (varbc || varc4)) + { + short vard4, vard8, vardc, vare0; + vard4 = my_moto_speed; + vard8 = fix16_to_int(myang); + if (varbc) + vardc = -10; + else + vardc = 10; + if (vardc < 0) + vare0 = 350; + else + vare0 = -350; + vard4 <<= 2; + if (my_moto_do_bump) + { + myvel.x += (vard4>>6)*(sintable[(vardc*-51+vard8+512)&2047]<<4); + myvel.y += (vard4>>6)*(sintable[(vardc*-51+vard8)&2047]<<4); + myang = F16((vard8-(vare0>>5))&2047); + } + else + { + myvel.x += (vard4>>7)*(sintable[(vardc*-51+vard8+512)&2047]<<4); + myvel.y += (vard4>>7)*(sintable[(vardc*-51+vard8)&2047]<<4); + myang = F16((vard8-(vare0>>6))&2047); + } + } + if (my_not_on_water) + if (my_moto_speed > 50) + my_moto_speed -= (my_moto_speed>>1); + } + } + + int sectorLotag = sector[mycursectnum].lotag; + int myclipdist = 64; + int spriteNum = 0; + + if (RR) + { + if (sectorLotag == 867) + { + int spriteNum = headspritesect[mycursectnum]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritesect[spriteNum]; + if (sprite[spriteNum].picnum == RRTILE380) + if (sprite[spriteNum].z - ZOFFSET3 < mypos.z) + sectorLotag = 2; + spriteNum = nextSprite; + } + } + + if (sectorLotag == 848 && sector[mycursectnum].floorpicnum == WATERTILE2) + sectorLotag = 1; + + if (sectorLotag == 857) + myclipdist = 1; + else + myclipdist = 64; + } + + uint8_t spritebridge = 0; + + int stepHeight, centerHoriz; + int16_t ceilingBunch, floorBunch; + + if (ud.noclip == 0 && (mycursectnum < 0 || mycursectnum >= MAXSECTORS || sector[mycursectnum].floorpicnum == MIRROR)) + { + mypos.x = omypos.x; + mypos.y = omypos.y; + } + else + { + omypos.x = mypos.x; + omypos.y = mypos.y; + } + + omyhoriz = myhoriz; + omyhorizoff = myhorizoff; + omypos.z = mypos.z; + omyang = myang; + + int32_t floorZ, ceilZ, highZhit, lowZhit; + if (!RR || myclipdist == 64) + getzrange(&mypos, mycursectnum, &ceilZ, &highZhit, &floorZ, &lowZhit, 163, CLIPMASK0); + else + getzrange(&mypos, mycursectnum, &ceilZ, &highZhit, &floorZ, &lowZhit, 1, CLIPMASK0); + + int truecz, truefz; +#ifdef YAX_ENABLE + getzsofslope_player(mycursectnum, mypos.x, mypos.y, &truecz, &truefz); +#else + getzsofslope(psect, mypos.x, mypos.y, &truecz, &truefz); +#endif + int const trueFloorZ = truefz; + int const trueFloorDist = klabs(mypos.z - trueFloorZ); + + if ((lowZhit & 49152) == 16384 && sectorLotag == 1 && trueFloorDist > PHEIGHT + ZOFFSET2) + sectorLotag = 0; + + // calculates automatic view angle for playing without a mouse + if (pPlayer->aim_mode == 0 && myonground && sectorLotag != ST_2_UNDERWATER + && (sector[mycursectnum].floorstat & 2)) + { + vec2_t const adjustedPlayer = { mypos.x + (sintable[(fix16_to_int(myang) + 512) & 2047] >> 5), + mypos.y + (sintable[fix16_to_int(myang) & 2047] >> 5) }; + int16_t curSectNum = mycursectnum; + + updatesector(adjustedPlayer.x, adjustedPlayer.y, &curSectNum); + + if (curSectNum >= 0) + { + int const slopeZ = getflorzofslope(mycursectnum, adjustedPlayer.x, adjustedPlayer.y); + if ((mycursectnum == curSectNum) || + (klabs(getflorzofslope(curSectNum, adjustedPlayer.x, adjustedPlayer.y) - slopeZ) <= ZOFFSET6)) + myhorizoff += fix16_from_int(mulscale16(trueFloorZ - slopeZ, 160)); + } + } + if (myhorizoff > 0) + { + myhorizoff -= ((myhorizoff >> 3) + fix16_one); + myhorizoff = max(myhorizoff, 0); + } + else if (myhorizoff < 0) + { + myhorizoff += (((-myhorizoff) >> 3) + fix16_one); + myhorizoff = min(myhorizoff, 0); + } + + if (highZhit >= 0 && (highZhit&49152) == 49152) + { + highZhit &= (MAXSPRITES-1); + + if (sprite[highZhit].statnum == STAT_ACTOR && sprite[highZhit].extra >= 0) + { + highZhit = 0; + ceilZ = truecz; + } + if (RR) + { + if (sprite[highZhit].picnum == RRTILE3587) + { + if (!my_stairs) + { + my_stairs = 10; + if (TEST_SYNC_KEY(playerBits, SK_JUMP) && (!RRRA || !pPlayer->on_motorcycle)) + { + highZhit = 0; + ceilZ = pPlayer->truecz; + } + } + else + my_stairs--; + } + } + } + + if (lowZhit >= 0 && (lowZhit&49152) == 49152) + { + int spriteNum = lowZhit&(MAXSPRITES-1); + + if ((sprite[spriteNum].cstat&33) == 33) + { + sectorLotag = 0; + spritebridge = 1; + //pPlayer->sbs = spriteNum; + } + else if (!RRRA) + goto check_enemy_sprite; + + if (RRRA) + { + if (pPlayer->on_motorcycle) + { + if (A_CheckEnemySprite(&sprite[spriteNum])) + { + my_moto_speed -= my_moto_speed >> 4; + } + } + if (pPlayer->on_boat) + { + if (A_CheckEnemySprite(&sprite[spriteNum])) + { + my_moto_speed -= my_moto_speed >> 4; + } + } + else + { +check_enemy_sprite: + if (A_CheckEnemySprite(&sprite[spriteNum]) && sprite[spriteNum].xrepeat > 24 + && klabs(pSprite->z - sprite[spriteNum].z) < (84 << 8)) + { + // TX: I think this is what makes the player slide off enemies... might + // be a good sprite flag to add later. + // Helix: there's also SLIDE_ABOVE_ENEMY. + int spriteAng = getangle(sprite[spriteNum].x - mypos.x, + sprite[spriteNum].y - mypos.y); + myvel.x -= sintable[(spriteAng + 512) & 2047] << 4; + myvel.y -= sintable[spriteAng & 2047] << 4; + } + } + } + if (RR) + { + if (sprite[spriteNum].picnum == RRTILE3587) + { + if (!my_stairs) + { + my_stairs = 10; + if (TEST_SYNC_KEY(playerBits, SK_CROUCH) && (!RRRA || !pPlayer->on_motorcycle)) + { + ceilZ = sprite[spriteNum].z; + highZhit = 0; + floorZ = sprite[spriteNum].z + ZOFFSET6; + } + } + else + my_stairs--; + } + } + } + + int velocityModifier = TICSPERFRAME; + int floorZOffset = 40; + int const playerShrunk = (pSprite->yrepeat < (RR ? 8 : 32)); + + if (pSprite->extra <= 0) + { + if (sectorLotag == ST_2_UNDERWATER) + { + if (pPlayer->on_warping_sector == 0) + { + if (klabs(mypos.z - floorZ) >(PHEIGHT>>1)) + mypos.z += 348; + } + clipmove(&mypos, &mycursectnum, + 0, 0, 164, (4L<<8), (4L<<8), CLIPMASK0); + } + + updatesector(mypos.x, mypos.y, &mycursectnum); + pushmove(&mypos, &mycursectnum, 128L, (4L<<8), (20L<<8), CLIPMASK0); + + myhoriz = F16(100); + myhorizoff = 0; + + goto ENDFAKEPROCESSINPUT; + } + + if (pPlayer->on_crane >= 0) + goto FAKEHORIZONLY; + + if (pPlayer->one_eighty_count < 0) + myang += F16(128); + + if (sectorLotag == ST_2_UNDERWATER) + { + myjumpingcounter = 0; + + if (TEST_SYNC_KEY(playerBits, SK_JUMP)) + { + myvel.z = max(min(-348, myvel.z - 348), -(256 * 6)); + } + else if (TEST_SYNC_KEY(playerBits, SK_CROUCH)) + { + myvel.z = min(max(348, myvel.z + 348), (256 * 6)); + } + else + { + // normal view + if (myvel.z < 0) + myvel.z = min(0, myvel.z + 256); + + if (myvel.z > 0) + myvel.z = max(0, myvel.z - 256); + } + + if (myvel.z > 2048) + myvel.z >>= 1; + + mypos.z += myvel.z; + + if (mypos.z > (floorZ-(15<<8))) + mypos.z += ((floorZ-(15<<8))-mypos.z)>>1; + + if (mypos.z < ceilZ+ZOFFSET6) + { + mypos.z = ceilZ+ZOFFSET6; + myvel.z = 0; + } + } + else if (!RR && pPlayer->jetpack_on) + { + myonground = 0; + myjumpingcounter = 0; + myhardlanding = 0; + + if (pPlayer->jetpack_on < 11) + mypos.z -= (pPlayer->jetpack_on<<7); //Goin up + + int const zAdjust = playerShrunk ? 512 : 2048; + + if (TEST_SYNC_KEY(playerBits, SK_JUMP)) // jumping, flying up + { + mypos.z -= zAdjust; + } + + if (TEST_SYNC_KEY(playerBits, SK_CROUCH)) // crouching, flying down + { + mypos.z += zAdjust; + } + + int const Zdiff = (playerShrunk == 0 && (sectorLotag == 0 || sectorLotag == ST_2_UNDERWATER)) ? 32 : 16; + + if (mypos.z > (floorZ - (Zdiff << 8))) + mypos.z += ((floorZ - (Zdiff << 8)) - mypos.z) >> 1; + + if (mypos.z < (ceilZ + (18 << 8))) + mypos.z = ceilZ + (18 << 8); + } + else + { + if (sectorLotag == ST_1_ABOVE_WATER && spritebridge == 0) + { + floorZOffset = playerShrunk ? 12 : 34; + } + if (mypos.z < (floorZ-(floorZOffset<<8))) //falling + { + if ((!TEST_SYNC_KEY(playerBits, SK_JUMP) && !TEST_SYNC_KEY(playerBits, SK_CROUCH)) && myonground && + (sector[mycursectnum].floorstat & 2) && mypos.z >= (floorZ - (floorZOffset << 8) - ZOFFSET2)) + mypos.z = floorZ - (floorZOffset << 8); + else + { + myonground = 0; + + if (RRRA && (pPlayer->on_motorcycle || pPlayer->on_boat) && floorZ - (floorZOffset << 9) > mypos.z) + { + if (my_moto_on_ground) + { + my_moto_bump_target = 80; + my_moto_bump_fast = 1; + myvel.z -= g_spriteGravity*(my_moto_speed>>4); + my_moto_on_ground = 0; + } + else + { + myvel.z += g_spriteGravity-80+(120-my_moto_speed); + } + } + else + myvel.z += (g_spriteGravity + 80); + + if (myvel.z >= (4096 + 2048)) + myvel.z = (4096 + 2048); + + if ((mypos.z + myvel.z) >= (floorZ - (floorZOffset << 8)) && mycursectnum >= 0) // hit the ground + { + if (sector[mycursectnum].lotag != ST_1_ABOVE_WATER) + { + if (RRRA) + my_moto_on_ground = 1; + } + } + } + } + + else + { + if ((sectorLotag != ST_1_ABOVE_WATER && sectorLotag != ST_2_UNDERWATER) && + (myonground == 0 && myvel.z > (6144 >> 1))) + myhardlanding = myvel.z>>10; + myonground = 1; + + if (floorZOffset == 40) + { + //Smooth on the ground + int Zdiff = ((floorZ - (floorZOffset << 8)) - mypos.z) >> 1; + + if (klabs(Zdiff) < 256) + Zdiff = 0; + + mypos.z += ((klabs(Zdiff) >= 256) ? (((floorZ - (floorZOffset << 8)) - mypos.z) >> 1) : 0); + //myz += k; // ((fz-(i<<8))-myz)>>1; + myvel.z -= 768; // 412; + if (myvel.z < 0) + myvel.z = 0; + } + else if (myjumpingcounter == 0) + { + mypos.z += ((floorZ - (floorZOffset << 7)) - mypos.z) >> 1; // Smooth on the water + + if (pPlayer->on_warping_sector == 0 && mypos.z > floorZ - ZOFFSET2) + { + mypos.z = floorZ - ZOFFSET2; + myvel.z >>= 1; + } + } + + if (TEST_SYNC_KEY(playerBits, SK_CROUCH) && (!RRRA || !pPlayer->on_motorcycle)) + mypos.z += (2048+768); + + if (!TEST_SYNC_KEY(playerBits, SK_JUMP) && (!RRRA || !pPlayer->on_motorcycle) && myjumpingtoggle == 1) + myjumpingtoggle = 0; + else if (TEST_SYNC_KEY(playerBits, SK_JUMP) && (!RRRA || !pPlayer->on_motorcycle) && myjumpingtoggle == 0) + { + if (myjumpingcounter == 0) + if ((floorZ-ceilZ) > (56<<8)) + { + myjumpingcounter = 1; + myjumpingtoggle = 1; + } + } + if (!RR && myjumpingcounter && !TEST_SYNC_KEY(playerBits, SK_JUMP)) + myjumpingcounter = 0; + } + + if (myjumpingcounter) + { + if (!TEST_SYNC_KEY(playerBits, SK_JUMP) && (!RRRA || !pPlayer->on_motorcycle) && myjumpingtoggle == 1) + myjumpingtoggle = 0; + + if (myjumpingcounter < (RR ? 768 : (1024+256))) + { + if (sectorLotag == ST_1_ABOVE_WATER && myjumpingcounter > 768) + { + myjumpingcounter = 0; + myvel.z = -512; + } + else + { + myvel.z -= (sintable[(2048-128+myjumpingcounter)&2047])/12; + myjumpingcounter += 180; + myonground = 0; + } + } + else + { + myjumpingcounter = 0; + myvel.z = 0; + } + } + + mypos.z += myvel.z; + + if (mypos.z < (ceilZ+ZOFFSET6)) + { + myjumpingcounter = 0; + if (myvel.z < 0) + myvel.x = myvel.y = 0; + myvel.z = 128; + mypos.z = ceilZ+ZOFFSET6; + } + + } + + if (pPlayer->fist_incs || pPlayer->transporter_hold > 2 || myhardlanding || pPlayer->access_incs > 0 || + pPlayer->knee_incs > 0 || (!RR && pPlayer->curr_weapon == TRIPBOMB_WEAPON && + pPlayer->kickback_pic > 1 && pPlayer->kickback_pic < 4)) + { + velocityModifier = 0; + myvel.x = 0; + myvel.y = 0; + } + else if (pInput->q16avel) //p->ang += syncangvel * constant + { + fix16_t const inputAng = pInput->q16avel; + + myang += (sectorLotag == ST_2_UNDERWATER) ? fix16_mul(inputAng - (inputAng >> 3), fix16_from_int(ksgn(velocityModifier))) + : fix16_mul(inputAng, fix16_from_int(ksgn(velocityModifier))); + + myang &= 0x7FFFFFF; + } + + if (myvel.x || myvel.y || pInput->fvel || pInput->svel) + { + if (RRRA) + { + if (spritebridge == 0 && myonground) + { + if (sectorLotag == ST_1_ABOVE_WATER) + my_not_on_water = 0; + else if (pPlayer->on_boat) + { + if (sectorLotag == 1234) + my_not_on_water = 0; + else + my_not_on_water = 1; + } + else + my_not_on_water = 1; + } + } + if (pPlayer->jetpack_on == 0 && pPlayer->inv_amount[GET_STEROIDS] > 0 && pPlayer->inv_amount[GET_STEROIDS] < 400) + velocityModifier <<= 1; + + myvel.x += ((pInput->fvel * velocityModifier) << 6); + myvel.y += ((pInput->svel * velocityModifier) << 6); + + int playerSpeedReduction = 0; + + if (!RRRA && myonground && (TEST_SYNC_KEY(playerBits, SK_CROUCH) + || (pPlayer->kickback_pic > 10 && pPlayer->curr_weapon == KNEE_WEAPON))) + playerSpeedReduction = 0x2000; + else if (sectorLotag == ST_2_UNDERWATER) + playerSpeedReduction = 0x1400; + + myvel.x = mulscale16(myvel.x, pPlayer->runspeed - playerSpeedReduction); + myvel.y = mulscale16(myvel.y, pPlayer->runspeed - playerSpeedReduction); + + if (RR) + { + if (RRRA) + { + if (sector[mycursectnum].floorpicnum == RRTILE7888) + { + if (pPlayer->on_motorcycle && myonground) + my_moto_on_oil = 1; + } + else if (sector[mycursectnum].floorpicnum == RRTILE7889) + { + if (pPlayer->on_motorcycle) + { + if (myonground) + my_moto_on_mud = 1; + } + else if (pPlayer->inv_amount[GET_BOOTS] <= 0) + { + myvel.x = mulscale16(myvel.x, pPlayer->runspeed); + myvel.y = mulscale16(myvel.y, pPlayer->runspeed); + } + } + } + if (sector[mycursectnum].floorpicnum == RRTILE3073 || sector[mycursectnum].floorpicnum == RRTILE2702) + { + if (RRRA && pPlayer->on_motorcycle) + { + if (myonground) + { + myvel.x = mulscale16(myvel.x, pPlayer->runspeed-0x1800); + myvel.y = mulscale16(myvel.y, pPlayer->runspeed-0x1800); + } + } + else if (pPlayer->inv_amount[GET_BOOTS] <= 0) + { + myvel.x = mulscale16(myvel.x, pPlayer->runspeed-0x1800); + myvel.y = mulscale16(myvel.y, pPlayer->runspeed-0x1800); + } + } + } + + if (klabs(myvel.x) < 2048 && klabs(myvel.y) < 2048) + myvel.x = myvel.y = 0; + + if (playerShrunk) + { + myvel.x = mulscale16(myvel.x, pPlayer->runspeed - (pPlayer->runspeed >> 1) + (pPlayer->runspeed >> 2)); + myvel.y = mulscale16(myvel.y, pPlayer->runspeed - (pPlayer->runspeed >> 1) + (pPlayer->runspeed >> 2)); + } + } + +FAKEHORIZONLY:; + stepHeight = (sectorLotag == ST_1_ABOVE_WATER || spritebridge == 1) ? pPlayer->autostep_sbw : pPlayer->autostep; + +#ifdef YAX_ENABLE + if (mycursectnum >= 0) + yax_getbunches(mycursectnum, &ceilingBunch, &floorBunch); + + // This updatesectorz conflicts with Duke3D's way of teleporting through water, + // so make it a bit conditional... OTOH, this way we have an ugly z jump when + // changing from above water to underwater + + if ((mycursectnum >= 0 && !(sector[mycursectnum].lotag == ST_1_ABOVE_WATER && myonground && floorBunch >= 0)) + && ((floorBunch >= 0 && !(sector[mycursectnum].floorstat & 512)) + || (ceilingBunch >= 0 && !(sector[mycursectnum].ceilingstat & 512)))) + { + mycursectnum += MAXSECTORS; // skip initial z check, restored by updatesectorz + updatesectorz(mypos.x, mypos.y, mypos.z, &mycursectnum); + } +#endif + clipmove(&mypos, &mycursectnum, myvel.x, myvel.y, 164, (4L << 8), stepHeight, CLIPMASK0); + pushmove(&mypos, &mycursectnum, 164, (4L << 8), (4L << 8), CLIPMASK0); + + // This makes the player view lower when shrunk. NOTE that it can get the + // view below the sector floor (and does, when on the ground). + if (pPlayer->jetpack_on == 0 && sectorLotag != ST_2_UNDERWATER && sectorLotag != ST_1_ABOVE_WATER && playerShrunk) + mypos.z += ZOFFSET5; + + if (RR) + { + if ((spriteNum & 49152) == 32768) + { + int const wallNum = spriteNum&(MAXWALLS-1); + if (RRRA && pPlayer->on_motorcycle) + { + int16_t var108, var10c; + var108 = getangle(wall[wall[wallNum].point2].x-wall[wallNum].x,wall[wall[wallNum].point2].y-wall[wallNum].y); + var10c = klabs(fix16_to_int(myang)-var108); + if (var10c >= 441 && var10c <= 581) + { + my_moto_speed = 0; + } + else if (var10c >= 311 && var10c <= 711) + { + my_moto_speed -= (my_moto_speed>>1)+(my_moto_speed>>2); + } + else if (var10c >= 111 && var10c <= 911) + { + my_moto_speed -= (my_moto_speed>>1); + } + else + { + my_moto_speed -= (my_moto_speed>>3); + } + } + else if (RRRA && pPlayer->on_boat) + { + short var114, var118; + var114 = getangle(wall[wall[wallNum].point2].x-wall[wallNum].x,wall[wall[wallNum].point2].y-wall[wallNum].y); + var118 = klabs(fix16_to_int(myang)-var114); + if (var118 >= 441 && var118 <= 581) + { + my_moto_speed = ((my_moto_speed>>1)+(my_moto_speed>>2))>>2; + } + else if (var118 >= 311 && var118 <= 711) + { + my_moto_speed -= ((my_moto_speed>>1)+(my_moto_speed>>2))>>3; + } + else if (var118 >= 111 && var118 <= 911) + { + my_moto_speed -= (my_moto_speed>>4); + } + else + { + my_moto_speed -= (my_moto_speed>>6); + } + } + } + else if ((spriteNum & 49152) == 49152) + { + spriteNum &= (MAXSPRITES-1); + + if (RRRA && pPlayer->on_motorcycle) + { + if (A_CheckEnemySprite(&sprite[spriteNum]) || sprite[spriteNum].picnum == APLAYER) + { + my_moto_speed -= my_moto_speed>>2; + my_moto_turb = 6; + } + } + else if (RRRA && pPlayer->on_boat) + { + if (A_CheckEnemySprite(&sprite[spriteNum]) || sprite[spriteNum].picnum == APLAYER) + { + my_moto_speed -= my_moto_speed>>2; + my_moto_turb = 6; + } + } + } + } + + centerHoriz = 0; + if (TEST_SYNC_KEY(playerBits, SK_CENTER_VIEW) || myhardlanding) + myreturntocenter = 9; + + if (TEST_SYNC_KEY(playerBits, SK_LOOK_UP)) + { + myreturntocenter = 9; + myhoriz += fix16_from_int(12<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN))); + centerHoriz++; + } + else if (TEST_SYNC_KEY(playerBits, SK_LOOK_DOWN)) + { + myreturntocenter = 9; + myhoriz -= fix16_from_int(12<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN))); + centerHoriz++; + } + else if (TEST_SYNC_KEY(playerBits, SK_AIM_UP)) + { + myhoriz += fix16_from_int(6<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN))); + centerHoriz++; + } + else if (TEST_SYNC_KEY(playerBits, SK_AIM_DOWN)) + { + myhoriz -= fix16_from_int(6<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN))); + centerHoriz++; + } + + if (RR && pPlayer->recoil && pPlayer->kickback_pic == 0) + { + int delta = pPlayer->recoil >> 1; + if (!delta) delta++; + myhoriz -= F16(delta); + } + if (myreturntocenter > 0 && !TEST_SYNC_KEY(playerBits, SK_LOOK_UP) && !TEST_SYNC_KEY(playerBits, SK_LOOK_DOWN)) + { + myreturntocenter--; + myhoriz += F16(33)-fix16_div(myhoriz, F16(3)); + centerHoriz++; + } + if (myhardlanding > 0) + { + myhardlanding--; + myhoriz -= fix16_from_int(myhardlanding<<4); + } + + myhoriz = fix16_clamp(myhoriz + pInput->q16horz, F16(HORIZ_MIN), F16(HORIZ_MAX)); + + if (centerHoriz) + { + if (myhoriz > F16(95) && myhoriz < F16(105)) myhoriz = F16(100); + if (myhorizoff > F16(-5) && myhorizoff < F16(5)) myhorizoff = 0; + } + + if (pPlayer->knee_incs > 0) + { + myhoriz -= F16(48); + myreturntocenter = 9; + } + + +ENDFAKEPROCESSINPUT: + + myposbak[predictfifoplc&(MOVEFIFOSIZ-1)] = mypos; + myangbak[predictfifoplc&(MOVEFIFOSIZ-1)] = myang; + myhorizbak[predictfifoplc&(MOVEFIFOSIZ-1)] = myhoriz; + predictfifoplc++; + + pSprite->cstat = backcstat; +} + +void Net_CorrectPrediction(void) +{ + if (numplayers < 2) + return; + + int i = ((movefifoplc-1)&(MOVEFIFOSIZ-1)); + DukePlayer_t *p = g_player[myconnectindex].ps; + + if (!Bmemcmp(&p->pos, &myposbak[i], sizeof(vec3_t)) + && p->q16horiz == myhorizbak[i] && p->q16ang == myangbak[i]) return; + + mypos = p->pos; omypos = p->opos, myvel = p->vel; + myang = p->q16ang; omyang = p->oq16ang; + mycursectnum = p->cursectnum; + myhoriz = p->q16horiz; omyhoriz = p->oq16horiz; + myhorizoff = p->q16horizoff; omyhorizoff = p->oq16horizoff; + myjumpingcounter = p->jumping_counter; + myjumpingtoggle = p->jumping_toggle; + myonground = p->on_ground; + myhardlanding = p->hard_landing; + myreturntocenter = p->return_to_center; + my_moto_speed = p->moto_speed; + my_not_on_water = p->not_on_water; + my_moto_on_ground = p->moto_on_ground; + my_moto_do_bump = p->moto_do_bump; + my_moto_bump_fast = p->moto_bump_fast; + my_moto_on_oil = p->moto_on_oil; + my_moto_on_mud = p->moto_on_mud; + my_moto_bump = p->moto_do_bump; + my_moto_bump_target = p->moto_bump_target; + my_moto_turb = p->moto_turb; + my_stairs = p->stairs; + + predictfifoplc = movefifoplc; + while (predictfifoplc < g_player[myconnectindex].movefifoend) + Net_DoPrediction(); +} + +int g_numSyncBytes = 1; +char g_szfirstSyncMsg[MAXSYNCBYTES][60]; +int g_foundSyncError = 0; + +char syncstat[MAXSYNCBYTES]; +int syncvaltail, syncvaltottail; + +static int crctable[256]; +#define updatecrc(dcrc,xz) (dcrc = (crctable[((dcrc)>>8)^((xz)&255)]^((dcrc)<<8))) + +void initsynccrc(void) +{ + int i, j, k, a; + + for (j=0;j<256;j++) //Calculate CRC table + { + k = (j<<8); a = 0; + for (i=7;i>=0;i--) + { + if (((k^a)&0x8000) > 0) + a = ((a<<1)&65535) ^ 0x1021; //0x1021 = genpoly + else + a = ((a<<1)&65535); + k = ((k<<1)&65535); + } + crctable[j] = (a&65535); + } +} + +char Net_PlayerSync(void) +{ + uint16_t crc = 0; + DukePlayer_t *pp; + + for(int TRAVERSE_CONNECT(i)) + { + pp = g_player[i].ps; + updatecrc(crc, pp->pos.x & 255); + updatecrc(crc, pp->pos.y & 255); + updatecrc(crc, pp->pos.z & 255); + updatecrc(crc, pp->q16ang & 255); + } + + return ((char) crc & 255); +} + +char Net_PlayerSync2(void) +{ + int nextj; + uint16_t crc = 0; + DukePlayer_t *pp; + spritetype *spr; + + for (int TRAVERSE_CONNECT(i)) + { + pp = g_player[i].ps; + + updatecrc(crc, pp->q16horiz & 255); + updatecrc(crc, sprite[pp->i].extra & 255); + updatecrc(crc, pp->bobcounter & 255); + } + + for (int TRAVERSE_SPRITE_STAT(headspritestat[STAT_PLAYER], j, nextj)) + { + spr = &sprite[j]; + updatecrc(crc, (spr->x) & 255); + updatecrc(crc, (spr->y) & 255); + updatecrc(crc, (spr->z) & 255); + updatecrc(crc, (spr->ang) & 255); + } + + return ((char) crc & 255); +} + +char Net_ActorSync(void) +{ + uint16_t crc = 0; + int nextj; + spritetype *spr; + + for (int TRAVERSE_SPRITE_STAT(headspritestat[STAT_ACTOR], j, nextj)) + { + spr = &sprite[j]; + updatecrc(crc, (spr->x) & 255); + updatecrc(crc, (spr->y) & 255); + updatecrc(crc, (spr->z) & 255); + updatecrc(crc, (spr->lotag) & 255); + updatecrc(crc, (spr->hitag) & 255); + updatecrc(crc, (spr->ang) & 255); + } + + for (int TRAVERSE_SPRITE_STAT(headspritestat[STAT_ZOMBIEACTOR], j, nextj)) + { + spr = &sprite[j]; + updatecrc(crc, (spr->x) & 255); + updatecrc(crc, (spr->y) & 255); + updatecrc(crc, (spr->z) & 255); + updatecrc(crc, (spr->lotag) & 255); + updatecrc(crc, (spr->hitag) & 255); + updatecrc(crc, (spr->ang) & 255); + } + + return ((char) crc & 255); +} + +char Net_WeaponSync(void) +{ + uint16_t crc = 0; + int nextj; + spritetype *spr; + + for (int TRAVERSE_SPRITE_STAT(headspritestat[STAT_PROJECTILE], j, nextj)) + { + spr = &sprite[j]; + updatecrc(crc, (spr->x) & 255); + updatecrc(crc, (spr->y) & 255); + updatecrc(crc, (spr->z) & 255); + updatecrc(crc, (spr->ang) & 255); + } + + return ((char) crc & 255); +} + +char Net_MapSync(void) +{ + uint16_t crc = 0; + int nextj; + spritetype *spr; + walltype *wal; + sectortype *sect; + + for (int TRAVERSE_SPRITE_STAT(headspritestat[STAT_EFFECTOR], j, nextj)) + { + spr = &sprite[j]; + updatecrc(crc, (spr->x) & 255); + updatecrc(crc, (spr->y) & 255); + updatecrc(crc, (spr->z) & 255); + updatecrc(crc, (spr->ang) & 255); + updatecrc(crc, (spr->lotag) & 255); + updatecrc(crc, (spr->hitag) & 255); + } + + for (int j=numwalls;j>=0;j--) + { + wal = &wall[j]; + updatecrc(crc, (wal->x) & 255); + updatecrc(crc, (wal->y) & 255); + } + + for (int j=numsectors;j>=0;j--) + { + sect = §or[j]; + updatecrc(crc, (sect->floorz) & 255); + updatecrc(crc, (sect->ceilingz) & 255); + } + + return ((char) crc & 255); +} + +char Net_RandomSync(void) +{ + unsigned short crc = 0; + + updatecrc(crc, randomseed & 255); + updatecrc(crc, (randomseed >> 8) & 255); + updatecrc(crc, g_globalRandom & 255); + updatecrc(crc, (g_globalRandom >> 8) & 255); + + if (g_numSyncBytes == 1) + { + updatecrc(crc,Net_PlayerSync() & 255); + updatecrc(crc,Net_PlayerSync2() & 255); + updatecrc(crc,Net_WeaponSync() & 255); + updatecrc(crc,Net_ActorSync() & 255); + updatecrc(crc,Net_MapSync() & 255); + } + + return ((char) crc & 255); +} + +const char *SyncNames[] = +{ + "Net_CheckRandomSync", + "Net_CheckPlayerSync", + "Net_CheckPlayerSync2", + "Net_CheckWeaponSync", + "Net_CheckActorSync", + "Net_CheckMapSync", + NULL +}; + +static char(*SyncFunc[MAXSYNCBYTES + 1])(void) = +{ + Net_RandomSync, + Net_PlayerSync, + Net_PlayerSync2, + Net_WeaponSync, + Net_ActorSync, + Net_MapSync, + NULL +}; + +void Net_GetSyncStat(void) +{ + int i; + playerdata_t *pp = &g_player[myconnectindex]; + unsigned int val; + static unsigned int count; + + if (numplayers < 2) + return; + + for (i = 0; SyncFunc[i]; i++) + { + pp->syncval[pp->syncvalhead & (SYNCFIFOSIZ - 1)][i] = (*SyncFunc[i])(); + } + + val = pp->syncval[pp->syncvalhead & (SYNCFIFOSIZ - 1)][0]; + count += val; + + pp->syncvalhead++; +} + +//////////////////////////////////////////////////////////////////////// +// +// Sync Message print +// +//////////////////////////////////////////////////////////////////////// + + +void Net_DisplaySyncMsg(void) +{ + int i, j; + static unsigned int moveCount = 0; + extern unsigned int g_moveThingsCount; + +// if (!SyncPrintMode) +// return; + + if (numplayers < 2) + return; + + for (i = 0; i < g_numSyncBytes; i++) + { + // syncstat is NON 0 - out of sync + if (syncstat[i] != 0) + { + if (g_numSyncBytes > 1) + { + Printf(PRINT_NOTIFY, "Out Of Sync - %s\n", SyncNames[i]); + } + + if (!g_foundSyncError && g_szfirstSyncMsg[i][0] == '\0') + { + // g_foundSyncError one so test all of them and then never test again + g_foundSyncError = 1; + + // save off loop count + moveCount = g_moveThingsCount; + + for (j = 0; j < g_numSyncBytes; j++) + { + if (syncstat[j] != 0 && g_szfirstSyncMsg[j][0] == '\0') + { + Printf(PRINT_NOTIFY, "Out Of Sync (%s) - Please restart game\n", SyncNames[j]); + } + } + } + } + } + + // print out the g_szfirstSyncMsg message you got + for (i = 0; i < g_numSyncBytes; i++) + { + if (g_szfirstSyncMsg[i][0] != '\0') + { + if (g_numSyncBytes > 1) + { + Printf(PRINT_NOTIFY, "FIRST %s - moveCount %d\n", g_szfirstSyncMsg[i],moveCount); + } + else + { + Printf(PRINT_NOTIFY, "%s\n", g_szfirstSyncMsg[i]); + } + } + } +} + + +void Net_AddSyncInfoToPacket(int *j) +{ + int sb; + int count = 0; + + // sync testing + while (g_player[myconnectindex].syncvalhead != syncvaltail && count++ < 4) + { + for (sb = 0; sb < g_numSyncBytes; sb++) + packbuf[(*j)++] = g_player[myconnectindex].syncval[syncvaltail & (SYNCFIFOSIZ - 1)][sb]; + + syncvaltail++; + } +} + +void Net_GetSyncInfoFromPacket(uint8_t *packbuf, int packbufleng, int *j, int otherconnectindex) +{ + int sb; + extern int syncvaltail, syncvaltottail; + playerdata_t *ppo = &g_player[otherconnectindex]; + char found = 0; + + // have had problems with this routine crashing when players quit + // games. + + // if ready2send is not set then don't try to get sync info + + if (!ready2send) + return; + + // Suspect that its trying to traverse the connect list + // for a player that does not exist. This tries to take care of that + + for (int TRAVERSE_CONNECT(i)) + { + if (otherconnectindex == i) + found = 1; + } + + if (!found) + return; + + // sync testing + //while ((*j) != packbufleng) // changed this on Kens suggestion + while ((*j) < packbufleng) + { + for (sb = 0; sb < g_numSyncBytes; sb++) + { + ppo->syncval[ppo->syncvalhead & (SYNCFIFOSIZ - 1)][sb] = packbuf[(*j)++]; + } + ppo->syncvalhead++; + } + + // update syncstat + // if any of the syncstat vars is non-0 then there is a problem + for (int TRAVERSE_CONNECT(i)) + { + if (g_player[i].syncvalhead == syncvaltottail) + return; + } + + //for (sb = 0; sb < g_numSyncBytes; sb++) + // syncstat[sb] = 0; + + while (1) + { + for (int i = connectpoint2[connecthead]; i >= 0; i = connectpoint2[i]) + { + for (sb = 0; sb < g_numSyncBytes; sb++) + { + if (g_player[i].connected && (g_player[i].syncval[syncvaltottail & (SYNCFIFOSIZ - 1)][sb] != g_player[connecthead].syncval[syncvaltottail & (SYNCFIFOSIZ - 1)][sb])) + { + syncstat[sb] = 1; + } + } + } + + syncvaltottail++; + + for (int TRAVERSE_CONNECT(i)) + { + if (g_player[i].syncvalhead == syncvaltottail) + return; + } + } +} + +void Net_ClearFIFO(void) +{ + int i = 0; + + syncvaltail = 0L; + syncvaltottail = 0L; + memset(&syncstat, 0, sizeof(syncstat)); + memset(&g_szfirstSyncMsg, 0, sizeof(g_szfirstSyncMsg)); + g_foundSyncError = 0; + + bufferjitter = 1; + mymaxlag = otherminlag = 0; + movefifoplc = movefifosendplc = predictfifoplc = 0; + avgfvel = avgsvel = avgavel = avghorz = avgbits = avgextbits = 0; + + for (; i < MAXPLAYERS; i++) + { + Bmemset(&g_player[i].movefifoend, 0, sizeof(g_player[i].movefifoend)); + Bmemset(&g_player[i].syncvalhead, 0, sizeof(g_player[i].syncvalhead)); + Bmemset(&g_player[i].myminlag, 0, sizeof(g_player[i].myminlag)); + } +} + +void Net_GetInput(void) +{ + input_t* osyn, * nsyn; + + if (numplayers > 1) + Net_GetPackets(); + + if (g_player[myconnectindex].movefifoend - movefifoplc >= 100 || System_WantGuiCapture()) + return; + + if (RRRA && g_player[myconnectindex].ps->on_motorcycle) + P_GetInputMotorcycle(myconnectindex); + else if (RRRA && g_player[myconnectindex].ps->on_boat) + P_GetInputBoat(myconnectindex); + else if (DEER) + P_DHGetInput(myconnectindex); + else + P_GetInput(myconnectindex); + + avgfvel += localInput.fvel; + avgsvel += localInput.svel; + avgavel += localInput.q16avel; + avghorz += localInput.q16horz; + avgbits |= localInput.bits; + avgextbits |= localInput.extbits; + + if (g_player[myconnectindex].movefifoend&(g_movesPerPacket-1)) + { + memcpy(&inputfifo[g_player[myconnectindex].movefifoend & (MOVEFIFOSIZ - 1)][myconnectindex], + &inputfifo[(g_player[myconnectindex].movefifoend - 1) & (MOVEFIFOSIZ - 1)][myconnectindex], sizeof(input_t)); + g_player[myconnectindex].movefifoend++; + return; + } + nsyn = &inputfifo[g_player[myconnectindex].movefifoend&(MOVEFIFOSIZ-1)][myconnectindex]; + nsyn[0].fvel = avgfvel/g_movesPerPacket; + nsyn[0].svel = avgsvel/g_movesPerPacket; + nsyn[0].q16avel = avgavel/g_movesPerPacket; + nsyn[0].q16horz = avghorz/g_movesPerPacket; + nsyn[0].bits = avgbits; + nsyn[0].extbits = avgextbits; + avgfvel = avgsvel = avgavel = avghorz = avgbits = avgextbits = 0; + g_player[myconnectindex].movefifoend++; + + + for (int TRAVERSE_CONNECT(i)) + if (i != myconnectindex) + { + int k = (g_player[myconnectindex].movefifoend-1)-g_player[i].movefifoend; + g_player[i].myminlag = min(g_player[i].myminlag,k); + mymaxlag = max(mymaxlag,k); + } + + if (((g_player[myconnectindex].movefifoend-1)&(TIMERUPDATESIZ-1)) == 0) + { + int i = mymaxlag-bufferjitter; mymaxlag = 0; + if (i > 0) bufferjitter += ((3+i)>>2); + else if (i < 0) bufferjitter -= ((1-i)>>2); + } + + if (g_networkBroadcastMode == 1) + { + packbuf[0] = SERVER_GENERATED_BROADCAST; + if ((g_player[myconnectindex].movefifoend-1) == 0) packbuf[0] = PACKET_TYPE_BROADCAST; + int j = 1; + + //Fix timers and buffer/jitter value + if (((g_player[myconnectindex].movefifoend-1)&(TIMERUPDATESIZ-1)) == 0) + { + if (myconnectindex != connecthead) + { + int i = g_player[connecthead].myminlag-otherminlag; + if (klabs(i) > 8) i >>= 1; + else if (klabs(i) > 2) i = ksgn(i); + else i = 0; + + totalclock -= TICSPERFRAME*i; + g_player[connecthead].myminlag -= i; otherminlag += i; + } + + if (myconnectindex == connecthead) + for(int i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + packbuf[j++] = min(max(g_player[i].myminlag,-128),127); + + for(int i=connecthead;i>=0;i=connectpoint2[i]) + g_player[i].myminlag = 0x7fffffff; + } + + osyn = (input_t *)&inputfifo[(g_player[myconnectindex].movefifoend-2)&(MOVEFIFOSIZ-1)][myconnectindex]; + nsyn = (input_t *)&inputfifo[(g_player[myconnectindex].movefifoend-1)&(MOVEFIFOSIZ-1)][myconnectindex]; + + int k = j; + packbuf[j++] = 0; + packbuf[j++] = 0; + + if (nsyn[0].fvel != osyn[0].fvel) + { + packbuf[j++] = (char)nsyn[0].fvel; + packbuf[j++] = (char)(nsyn[0].fvel>>8); + packbuf[k] |= 1; + } + if (nsyn[0].svel != osyn[0].svel) + { + packbuf[j++] = (char)nsyn[0].svel; + packbuf[j++] = (char)(nsyn[0].svel>>8); + packbuf[k] |= 2; + } + if (nsyn[0].q16avel != osyn[0].q16avel) + { + packbuf[j++] = (char)((nsyn[0].q16avel) & 255); + packbuf[j++] = (char)((nsyn[0].q16avel >> 8) & 255); + packbuf[j++] = (char)((nsyn[0].q16avel >> 16) & 255); + packbuf[j++] = (char)((nsyn[0].q16avel >> 24) & 255); + packbuf[k] |= 4; + } + + if ((nsyn[0].bits^osyn[0].bits)&0x000000ff) packbuf[j++] = (nsyn[0].bits&255), packbuf[k] |= 8; + if ((nsyn[0].bits^osyn[0].bits)&0x0000ff00) packbuf[j++] = ((nsyn[0].bits>>8)&255), packbuf[k] |= 16; + if ((nsyn[0].bits^osyn[0].bits)&0x00ff0000) packbuf[j++] = ((nsyn[0].bits>>16)&255), packbuf[k] |= 32; + if ((nsyn[0].bits^osyn[0].bits)&0xff000000) packbuf[j++] = ((nsyn[0].bits>>24)&255), packbuf[k] |= 64; + + if (nsyn[0].q16horz != osyn[0].q16horz) + { + packbuf[j++] = (char)((nsyn[0].q16horz) & 255); + packbuf[j++] = (char)((nsyn[0].q16horz >> 8) & 255); + packbuf[j++] = (char)((nsyn[0].q16horz >> 16) & 255); + packbuf[j++] = (char)((nsyn[0].q16horz >> 24) & 255); + packbuf[k] |= 128; + } +// k++; + packbuf[++k] = 0; + if (nsyn[0].extbits != osyn[0].extbits) packbuf[j++] = nsyn[0].extbits, packbuf[k] |= 1; + /* if ((nsyn[0].extbits^osyn[0].extbits)&0x000000ff) packbuf[j++] = (nsyn[0].extbits&255), packbuf[k] |= 1; + if ((nsyn[0].extbits^osyn[0].extbits)&0x0000ff00) packbuf[j++] = ((nsyn[0].extbits>>8)&255), packbuf[k] |= 2; + if ((nsyn[0].extbits^osyn[0].extbits)&0x00ff0000) packbuf[j++] = ((nsyn[0].extbits>>16)&255), packbuf[k] |= 4; + if ((nsyn[0].extbits^osyn[0].extbits)&0xff000000) packbuf[j++] = ((nsyn[0].extbits>>24)&255), packbuf[k] |= 8; */ + + /* while (g_player[myconnectindex].syncvalhead != syncvaltail) + { + packbuf[j++] = g_player[myconnectindex].syncval[syncvaltail&(MOVEFIFOSIZ-1)]; + syncvaltail++; + } */ + + Net_AddSyncInfoToPacket(&j); + + for (int TRAVERSE_CONNECT(i)) + if (i != myconnectindex) + Net_SendPacket(i,packbuf,j); + + return; + } + if (myconnectindex != connecthead) //Slave + { + //Fix timers and buffer/jitter value + if (((g_player[myconnectindex].movefifoend-1)&(TIMERUPDATESIZ-1)) == 0) + { + int i = g_player[connecthead].myminlag - otherminlag; + if (klabs(i) > 2) + { + if (klabs(i) > 8) + { + if (i < 0) + i++; + i >>= 1; + } + else + { + if (i < 0) + i = -1; + if (i > 0) + i = 1; + } + totalclock -= TICSPERFRAME * i; + otherminlag += i; + } + + for (int TRAVERSE_CONNECT(i)) + { + g_player[i].myminlag = 0x7fffffff; + } + } + + packbuf[0] = PACKET_TYPE_SLAVE_TO_MASTER; + packbuf[1] = 0; + packbuf[2] = 0; + int j = 3; + + osyn = (input_t *)&inputfifo[(g_player[myconnectindex].movefifoend-2)&(MOVEFIFOSIZ-1)][myconnectindex]; + nsyn = (input_t *)&inputfifo[(g_player[myconnectindex].movefifoend-1)&(MOVEFIFOSIZ-1)][myconnectindex]; + + if (nsyn[0].fvel != osyn[0].fvel) + { + packbuf[j++] = (char)nsyn[0].fvel; + packbuf[j++] = (char)(nsyn[0].fvel>>8); + packbuf[1] |= 1; + } + if (nsyn[0].svel != osyn[0].svel) + { + packbuf[j++] = (char)nsyn[0].svel; + packbuf[j++] = (char)(nsyn[0].svel>>8); + packbuf[1] |= 2; + } + if (nsyn[0].q16avel != osyn[0].q16avel) + { + packbuf[j++] = (char)((nsyn[0].q16avel) & 255); + packbuf[j++] = (char)((nsyn[0].q16avel >> 8) & 255); + packbuf[j++] = (char)((nsyn[0].q16avel >> 16) & 255); + packbuf[j++] = (char)((nsyn[0].q16avel >> 24) & 255); + packbuf[1] |= 4; + } + + if ((nsyn[0].bits^osyn[0].bits)&0x000000ff) packbuf[j++] = (nsyn[0].bits&255), packbuf[1] |= 8; + if ((nsyn[0].bits^osyn[0].bits)&0x0000ff00) packbuf[j++] = ((nsyn[0].bits>>8)&255), packbuf[1] |= 16; + if ((nsyn[0].bits^osyn[0].bits)&0x00ff0000) packbuf[j++] = ((nsyn[0].bits>>16)&255), packbuf[1] |= 32; + if ((nsyn[0].bits^osyn[0].bits)&0xff000000) packbuf[j++] = ((nsyn[0].bits>>24)&255), packbuf[1] |= 64; + + if (nsyn[0].q16horz != osyn[0].q16horz) + { + packbuf[j++] = (char)((nsyn[0].q16horz) & 255); + packbuf[j++] = (char)((nsyn[0].q16horz >> 8) & 255); + packbuf[j++] = (char)((nsyn[0].q16horz >> 16) & 255); + packbuf[j++] = (char)((nsyn[0].q16horz >> 24) & 255); + packbuf[1] |= 128; + } + packbuf[2] = 0; + if (nsyn[0].extbits != osyn[0].extbits) packbuf[j++] = nsyn[0].extbits, packbuf[2] |= 1; + /* if ((nsyn[0].extbits^osyn[0].extbits)&0x000000ff) packbuf[j++] = (nsyn[0].extbits&255), packbuf[2] |= 1; + if ((nsyn[0].extbits^osyn[0].extbits)&0x0000ff00) packbuf[j++] = ((nsyn[0].extbits>>8)&255), packbuf[2] |= 2; + if ((nsyn[0].extbits^osyn[0].extbits)&0x00ff0000) packbuf[j++] = ((nsyn[0].extbits>>16)&255), packbuf[2] |= 4; + if ((nsyn[0].extbits^osyn[0].extbits)&0xff000000) packbuf[j++] = ((nsyn[0].extbits>>24)&255), packbuf[2] |= 8; */ + + /* while (g_player[myconnectindex].syncvalhead != syncvaltail) + { + packbuf[j++] = g_player[myconnectindex].syncval[syncvaltail&(MOVEFIFOSIZ-1)]; + syncvaltail++; + } */ + Net_AddSyncInfoToPacket(&j); + + Net_SendPacket(connecthead,packbuf,j); + return; + } + + //This allows allow packet resends + for (int TRAVERSE_CONNECT(i)) + if (g_player[i].movefifoend <= movefifosendplc) + { + packbuf[0] = PACKET_TYPE_NULL_PACKET; + for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + Net_SendPacket(i,packbuf,1); + return; + } + + while (1) //Master + { + for (int TRAVERSE_CONNECT(i)) + if (g_player[i].playerquitflag && (g_player[i].movefifoend <= movefifosendplc)) return; + + osyn = (input_t *)&inputfifo[(movefifosendplc-1)&(MOVEFIFOSIZ-1)][0]; + nsyn = (input_t *)&inputfifo[(movefifosendplc)&(MOVEFIFOSIZ-1)][0]; + + //MASTER -> SLAVE packet + packbuf[0] = PACKET_TYPE_MASTER_TO_SLAVE; + int j = 1; + + //Fix timers and buffer/jitter value + if ((movefifosendplc&(TIMERUPDATESIZ-1)) == 0) + { + for (int i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + if (g_player[i].playerquitflag) + packbuf[j++] = min(max(g_player[i].myminlag,-128),127); + + for (int TRAVERSE_CONNECT(i)) + g_player[i].myminlag = 0x7fffffff; + } + + int k = j; + for (int TRAVERSE_CONNECT(i)) + j += g_player[i].playerquitflag + g_player[i].playerquitflag; + for (int TRAVERSE_CONNECT(i)) + { + if (g_player[i].playerquitflag == 0) continue; + + packbuf[k] = 0; + if (nsyn[i].fvel != osyn[i].fvel) + { + packbuf[j++] = (char)nsyn[i].fvel; + packbuf[j++] = (char)(nsyn[i].fvel>>8); + packbuf[k] |= 1; + } + if (nsyn[i].svel != osyn[i].svel) + { + packbuf[j++] = (char)nsyn[i].svel; + packbuf[j++] = (char)(nsyn[i].svel>>8); + packbuf[k] |= 2; + } + if (nsyn[i].q16avel != osyn[i].q16avel) + { + packbuf[j++] = (char)((nsyn[i].q16avel) & 255); + packbuf[j++] = (char)((nsyn[i].q16avel >> 8) & 255); + packbuf[j++] = (char)((nsyn[i].q16avel >> 16) & 255); + packbuf[j++] = (char)((nsyn[i].q16avel >> 24) & 255); + packbuf[k] |= 4; + } + + if ((nsyn[i].bits^osyn[i].bits)&0x000000ff) packbuf[j++] = (nsyn[i].bits&255), packbuf[k] |= 8; + if ((nsyn[i].bits^osyn[i].bits)&0x0000ff00) packbuf[j++] = ((nsyn[i].bits>>8)&255), packbuf[k] |= 16; + if ((nsyn[i].bits^osyn[i].bits)&0x00ff0000) packbuf[j++] = ((nsyn[i].bits>>16)&255), packbuf[k] |= 32; + if ((nsyn[i].bits^osyn[i].bits)&0xff000000) packbuf[j++] = ((nsyn[i].bits>>24)&255), packbuf[k] |= 64; + + if (nsyn[i].q16horz != osyn[i].q16horz) + { + packbuf[j++] = (char)((nsyn[i].q16horz) & 255); + packbuf[j++] = (char)((nsyn[i].q16horz >> 8) & 255); + packbuf[j++] = (char)((nsyn[i].q16horz >> 16) & 255); + packbuf[j++] = (char)((nsyn[i].q16horz >> 24) & 255); + packbuf[k] |= 128; + } + k++; + packbuf[k] = 0; + if (nsyn[i].extbits != osyn[i].extbits) packbuf[j++] = nsyn[i].extbits, packbuf[k] |= 1; + /* + if ((nsyn[i].extbits^osyn[i].extbits)&0x000000ff) packbuf[j++] = (nsyn[i].extbits&255), packbuf[k] |= 1; + if ((nsyn[i].extbits^osyn[i].extbits)&0x0000ff00) packbuf[j++] = ((nsyn[i].extbits>>8)&255), packbuf[k] |= 2; + if ((nsyn[i].extbits^osyn[i].extbits)&0x00ff0000) packbuf[j++] = ((nsyn[i].extbits>>16)&255), packbuf[k] |= 4; + if ((nsyn[i].extbits^osyn[i].extbits)&0xff000000) packbuf[j++] = ((nsyn[i].extbits>>24)&255), packbuf[k] |= 8; */ + k++; + } + + /* while (g_player[myconnectindex].syncvalhead != syncvaltail) + { + packbuf[j++] = g_player[myconnectindex].syncval[syncvaltail&(MOVEFIFOSIZ-1)]; + syncvaltail++; + } */ + Net_AddSyncInfoToPacket(&j); + + for (int i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + if (g_player[i].playerquitflag) + { + Net_SendPacket(i,packbuf,j); + if (TEST_SYNC_KEY(nsyn[i].bits,SK_GAMEQUIT)) + g_player[i].playerquitflag = 0; + } + + movefifosendplc += g_movesPerPacket; + } + +} + +void Net_ParsePacket(uint8_t *packbuf, int packbufleng) +{ + int i, j, k, l; + int other = *packbuf++; + packbufleng--; + + input_t *osyn, *nsyn; + + //if (numplayers < 2) return; + //while ((packbufleng = mmulti_getpacket(&other,packbuf)) > 0) + //{ + //lastpackettime = totalclock; +#if 0 + Printf("RECEIVED PACKET: type: %d : len %d\n", packbuf[0], packbufleng); +#endif + switch (packbuf[0]) + { + case PACKET_TYPE_MASTER_TO_SLAVE: //[0] (receive master sync buffer) + j = 1; + + if ((g_player[other].movefifoend&(TIMERUPDATESIZ-1)) == 0) + for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + { + if (g_player[i].playerquitflag == 0) continue; + if (i == myconnectindex) + otherminlag = (int)((signed char)packbuf[j]); + j++; + } + + osyn = (input_t *)&inputfifo[(g_player[connecthead].movefifoend-1)&(MOVEFIFOSIZ-1)][0]; + nsyn = (input_t *)&inputfifo[(g_player[connecthead].movefifoend)&(MOVEFIFOSIZ-1)][0]; + + k = j; + for(TRAVERSE_CONNECT(i)) + j += g_player[i].playerquitflag+g_player[i].playerquitflag; + for(TRAVERSE_CONNECT(i)) + { + if (g_player[i].playerquitflag == 0) continue; + + l = packbuf[k]+(int)(packbuf[k+1]<<8); + k += 2; + + if (i == myconnectindex) + { + //j += ((l&1)<<1)+(l&2)+((l&4)>>2)+((l&8)>>3)+((l&16)>>4)+((l&32)>>5)+((l&64)>>6)+((l&128)>>7)+((l&256)>>8)/*+((l&512)>>9)+((l&1024)>>10)+((l&2048)>>11)*/; + + if (l & 1) j += 2; + if (l & 2) j += 2; + if (l & 4) j += 4; + if (l & 8) j++; + if (l & 16) j++; + if (l & 32) j++; + if (l & 64) j++; + if (l & 128) j += 4; + if (l & 256) j++; + + continue; + } + + memcpy(&nsyn[i],&osyn[i],sizeof(input_t)); + if (l&1) nsyn[i].fvel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; + if (l&2) nsyn[i].svel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; + if (l&4) + { + nsyn[i].q16avel = (fix16_t)packbuf[j]; + nsyn[i].q16avel += (fix16_t)packbuf[j + 1] << 8; + nsyn[i].q16avel += (fix16_t)packbuf[j + 2] << 16; + nsyn[i].q16avel += (fix16_t)packbuf[j + 3] << 24; + j += 4; + } + if (l&8) nsyn[i].bits = ((nsyn[i].bits&0xffffff00)|((int)packbuf[j++])); + if (l&16) nsyn[i].bits = ((nsyn[i].bits&0xffff00ff)|((int)packbuf[j++])<<8); + if (l&32) nsyn[i].bits = ((nsyn[i].bits&0xff00ffff)|((int)packbuf[j++])<<16); + if (l&64) nsyn[i].bits = ((nsyn[i].bits&0x00ffffff)|((int)packbuf[j++])<<24); + if (l&128) + { + nsyn[i].q16horz = (fix16_t)packbuf[j]; + nsyn[i].q16horz += (fix16_t)packbuf[j + 1] << 8; + nsyn[i].q16horz += (fix16_t)packbuf[j + 2] << 16; + nsyn[i].q16horz += (fix16_t)packbuf[j + 3] << 24; + j += 4; + } + if (l&256) nsyn[i].extbits = (unsigned char)packbuf[j++]; + /* if (l&256) nsyn[i].extbits = ((nsyn[i].extbits&0xffffff00)|((int)packbuf[j++])); + if (l&512) nsyn[i].extbits = ((nsyn[i].extbits&0xffff00ff)|((int)packbuf[j++])<<8); + if (l&1024) nsyn[i].extbits = ((nsyn[i].extbits&0xff00ffff)|((int)packbuf[j++])<<16); + if (l&2048) nsyn[i].extbits = ((nsyn[i].extbits&0x00ffffff)|((int)packbuf[j++])<<24); */ + + if (TEST_SYNC_KEY(nsyn[i].bits,SK_GAMEQUIT)) g_player[i].playerquitflag = 0; + g_player[i].movefifoend++; + } + + Net_GetSyncInfoFromPacket(packbuf, packbufleng, &j, other); + + for (TRAVERSE_CONNECT(i)) + if (i != myconnectindex) + for (j=g_movesPerPacket-1;j>=1;j--) + { + memcpy(&inputfifo[g_player[i].movefifoend&(MOVEFIFOSIZ-1)][i], &nsyn[i],sizeof(input_t)); + g_player[i].movefifoend++; + } + + movefifosendplc += g_movesPerPacket; + + break; + case PACKET_TYPE_SLAVE_TO_MASTER: //[1] (receive slave sync buffer) + j = 3; + k = packbuf[1] + (int)(packbuf[2]<<8); + + osyn = (input_t *)&inputfifo[(g_player[other].movefifoend-1)&(MOVEFIFOSIZ-1)][0]; + nsyn = (input_t *)&inputfifo[(g_player[other].movefifoend)&(MOVEFIFOSIZ-1)][0]; + + memcpy(&nsyn[other], &osyn[other], sizeof(input_t)); + if (k&1) nsyn[other].fvel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; + if (k&2) nsyn[other].svel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; + if (k&4) + { + nsyn[other].q16avel = (fix16_t)packbuf[j]; + nsyn[other].q16avel += (fix16_t)packbuf[j + 1] << 8; + nsyn[other].q16avel += (fix16_t)packbuf[j + 2] << 16; + nsyn[other].q16avel += (fix16_t)packbuf[j + 3] << 24; + j += 4; + } + if (k&8) nsyn[other].bits = ((nsyn[other].bits&0xffffff00)|((int)packbuf[j++])); + if (k&16) nsyn[other].bits = ((nsyn[other].bits&0xffff00ff)|((int)packbuf[j++])<<8); + if (k&32) nsyn[other].bits = ((nsyn[other].bits&0xff00ffff)|((int)packbuf[j++])<<16); + if (k&64) nsyn[other].bits = ((nsyn[other].bits&0x00ffffff)|((int)packbuf[j++])<<24); + if (k&128) + { + nsyn[other].q16horz = (fix16_t)packbuf[j]; + nsyn[other].q16horz += (fix16_t)packbuf[j + 1] << 8; + nsyn[other].q16horz += (fix16_t)packbuf[j + 2] << 16; + nsyn[other].q16horz += (fix16_t)packbuf[j + 3] << 24; + j += 4; + } + if (k&256) nsyn[other].extbits = (unsigned char)packbuf[j++]; + /* if (k&256) nsyn[other].extbits = ((nsyn[other].extbits&0xffffff00)|((int)packbuf[j++])); + if (k&512) nsyn[other].extbits = ((nsyn[other].extbits&0xffff00ff)|((int)packbuf[j++])<<8); + if (k&1024) nsyn[other].extbits = ((nsyn[other].extbits&0xff00ffff)|((int)packbuf[j++])<<16); + if (k&2048) nsyn[other].extbits = ((nsyn[other].extbits&0x00ffffff)|((int)packbuf[j++])<<24); */ + g_player[other].movefifoend++; + + /* while (j != packbufleng) + { + g_player[other].syncval[g_player[other].syncvalhead&(MOVEFIFOSIZ-1)] = packbuf[j++]; + g_player[other].syncvalhead++; + } */ + Net_GetSyncInfoFromPacket(packbuf, packbufleng, &j, other); + + for (i=g_movesPerPacket-1;i>=1;i--) + { + memcpy(&inputfifo[g_player[other].movefifoend&(MOVEFIFOSIZ-1)][other], &nsyn[other], sizeof(input_t)); + g_player[other].movefifoend++; + } + + break; + + case PACKET_TYPE_BROADCAST: + g_player[other].movefifoend = movefifoplc = movefifosendplc = predictfifoplc = 0; + g_player[other].syncvalhead = syncvaltottail = 0L; + case SERVER_GENERATED_BROADCAST: + j = 1; + + if ((g_player[other].movefifoend&(TIMERUPDATESIZ-1)) == 0) + if (other == connecthead) + for (i=connectpoint2[connecthead];i>=0;i=connectpoint2[i]) + { + if (i == myconnectindex) + otherminlag = (int)((signed char)packbuf[j]); + j++; + } + + osyn = (input_t *)&inputfifo[(g_player[other].movefifoend-1)&(MOVEFIFOSIZ-1)][0]; + nsyn = (input_t *)&inputfifo[(g_player[other].movefifoend)&(MOVEFIFOSIZ-1)][0]; + + memcpy(&nsyn[other], &osyn[other], sizeof(input_t)); + k = packbuf[j] + (int)(packbuf[j+1]<<8); + j += 2; + + if (k&1) nsyn[other].fvel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; + if (k&2) nsyn[other].svel = packbuf[j]+((short)packbuf[j+1]<<8), j += 2; + if (k&4) + { + nsyn[other].q16avel = (fix16_t)packbuf[j]; + nsyn[other].q16avel += (fix16_t)packbuf[j + 1] << 8; + nsyn[other].q16avel += (fix16_t)packbuf[j + 2] << 16; + nsyn[other].q16avel += (fix16_t)packbuf[j + 3] << 24; + j += 4; + } + if (k&8) nsyn[other].bits = ((nsyn[other].bits&0xffffff00)|((int)packbuf[j++])); + if (k&16) nsyn[other].bits = ((nsyn[other].bits&0xffff00ff)|((int)packbuf[j++])<<8); + if (k&32) nsyn[other].bits = ((nsyn[other].bits&0xff00ffff)|((int)packbuf[j++])<<16); + if (k&64) nsyn[other].bits = ((nsyn[other].bits&0x00ffffff)|((int)packbuf[j++])<<24); + if (k&128) + { + nsyn[other].q16horz = (fix16_t)packbuf[j]; + nsyn[other].q16horz += (fix16_t)packbuf[j + 1] << 8; + nsyn[other].q16horz += (fix16_t)packbuf[j + 2] << 16; + nsyn[other].q16horz += (fix16_t)packbuf[j + 3] << 24; + j += 4; + } + + if (k&256) nsyn[other].extbits = (unsigned char)packbuf[j++]; + /* if (k&256) nsyn[other].extbits = ((nsyn[other].extbits&0xffffff00)|((int)packbuf[j++])); + if (k&512) nsyn[other].extbits = ((nsyn[other].extbits&0xffff00ff)|((int)packbuf[j++])<<8); + if (k&1024) nsyn[other].extbits = ((nsyn[other].extbits&0xff00ffff)|((int)packbuf[j++])<<16); + if (k&2048) nsyn[other].extbits = ((nsyn[other].extbits&0x00ffffff)|((int)packbuf[j++])<<24); */ + g_player[other].movefifoend++; + + for (i=g_movesPerPacket-1;i>=1;i--) + { + memcpy(&inputfifo[g_player[other].movefifoend&(MOVEFIFOSIZ-1)][other], &nsyn[other], sizeof(input_t)); + g_player[other].movefifoend++; + } + + /* + while (j < packbufleng) + { + g_player[other].syncval[g_player[other].syncvalhead&(MOVEFIFOSIZ-1)] = packbuf[j++]; + g_player[other].syncvalhead++; + } + */ + Net_GetSyncInfoFromPacket(packbuf, packbufleng, &j, other); + + if (j > packbufleng) + Printf("INVALID GAME PACKET!!! (packet %d, %d too many bytes (%d %d))\n",packbuf[0],j-packbufleng,packbufleng,k); + + break; + case PACKET_TYPE_NULL_PACKET: + break; + + case PACKET_TYPE_PLAYER_READY: + if (g_player[other].playerreadyflag == 0) + Printf("Player %d is ready\n", other); + g_player[other].playerreadyflag++; + return; + //case PACKET_TYPE_QUIT: + // G_GameExit(" "); + // break; + + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Connect/Disconnect + +void Net_Connect(const char *srvaddr) +{ + ENetAddress address; + ENetEvent event; + char *addrstr = NULL; + int32_t i; + + char *oursrvaddr = Xstrdup(srvaddr); + + Net_Disconnect(); + + g_netClient = enet_host_create(NULL, 1, CHAN_MAX, 0, 0); + + if (g_netClient == NULL) + { + Printf("An error occurred while trying to create an ENet client host.\n"); + return; + } + + addrstr = strtok(oursrvaddr, ":"); + enet_address_set_host(&address, addrstr); + addrstr = strtok(NULL, ":"); + address.port = addrstr==NULL ? g_netPort : Batoi(addrstr); + + g_netClientPeer = enet_host_connect(g_netClient, &address, CHAN_MAX, 0); + + if (g_netClientPeer == NULL) + { + Printf("No available peers for initiating an ENet connection.\n"); + return; + } + + for (i=4; i>0; i--) + { + /* Wait up to 5 seconds for the connection attempt to succeed. */ + if (enet_host_service(g_netClient, & event, 5000) > 0 && + event.type == ENET_EVENT_TYPE_CONNECT) + { + Printf("Connection to %s:%d succeeded.\n", oursrvaddr, address.port); + Xfree(oursrvaddr); + return; + } + else + { + /* Either the 5 seconds are up or a disconnect event was */ + /* received. Reset the peer in the event the 5 seconds */ + /* had run out without any significant event. */ + enet_peer_reset(g_netClientPeer); + Printf("Connection to %s:%d failed.\n", oursrvaddr, address.port); + } + Printf(i ? "Retrying...\n" : "Giving up connection attempt.\n"); + } + + Xfree(oursrvaddr); + Net_Disconnect(); +} + +void Net_Disconnect(void) +{ + if (g_netClient) + { + ENetEvent event; + + if (g_netClientPeer) + enet_peer_disconnect_later(g_netClientPeer, 0); + + while (enet_host_service(g_netClient, & event, 3000) > 0) + { + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + case ENET_EVENT_TYPE_NONE: + case ENET_EVENT_TYPE_RECEIVE: + if (event.packet) + enet_packet_destroy(event.packet); + break; + + case ENET_EVENT_TYPE_DISCONNECT: + numplayers = g_mostConcurrentPlayers = ud.multimode = 1; + myconnectindex = screenpeek = 0; + G_BackToMenu(); + break; + + default: + break; + } + } + + enet_peer_reset(g_netClientPeer); + g_netClientPeer = NULL; + enet_host_destroy(g_netClient); + g_netClient = NULL; + return; + } + + if (g_netServer) + { + int32_t i; + ENetEvent event; + + for (i=0; i<(signed)g_netServer->peerCount; i++) + enet_peer_disconnect_later(&g_netServer->peers[i], DISC_SERVER_QUIT); + + while (enet_host_service(g_netServer, & event, 3000) > 0) + { + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + case ENET_EVENT_TYPE_NONE: + case ENET_EVENT_TYPE_RECEIVE: + case ENET_EVENT_TYPE_DISCONNECT: + if (event.packet) + enet_packet_destroy(event.packet); + break; + default: + break; + } + } + enet_host_destroy(g_netServer); + g_netServer = NULL; + } +} + +void Net_ReceiveDisconnect(ENetEvent *event) +{ + g_netDisconnect = 1; + numplayers = g_mostConcurrentPlayers = ud.multimode = 1; + myconnectindex = screenpeek = 0; + G_BackToMenu(); + + switch (event->data) + { + case DISC_GAME_STARTED: + Printf("Game already started.\n"); + return; + case DISC_BAD_PASSWORD: + Printf("Bad password.\n"); + return; + case DISC_VERSION_MISMATCH: + Printf("Version mismatch.\n"); + return; + case DISC_INVALID: + Printf("Invalid data detected.\n"); + return; + case DISC_SERVER_QUIT: + Printf("The server is quitting.\n"); + return; + case DISC_SERVER_FULL: + Printf("The server is full.\n"); + return; + case DISC_KICKED: + Printf("You have been kicked from the server.\n"); + return; + case DISC_BANNED: + Printf("You are banned from this server.\n"); + return; + default: + Printf("Disconnected.\n"); + return; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Packet Handlers + +#endif + +void Net_GetPackets(void) +{ + if (g_netDisconnect) + { + Net_Disconnect(); + g_netDisconnect = 0; + + if (g_gameQuit) + G_GameExit(" "); + + return; + } + + if (g_netServer) + { + Net_HandleClientPackets(); + } + else if (g_netClient) + { + Net_HandleServerPackets(); + } +} + +#ifndef NETCODE_DISABLE + +static void P_RemovePlayer(int32_t p); + +void Net_HandleClientPackets(void) +{ + ENetEvent event; + + // pull events from the wire into the packet queue without dispatching them, once per Net_GetPackets() call + enet_host_service(g_netServer, NULL, 0); + + // dispatch any pending events from the local packet queue + while (enet_host_check_events(g_netServer, &event) > 0) + { + const intptr_t playeridx = (intptr_t)event.peer->data; + + if (playeridx < 0 || playeridx >= MAXPLAYERS) + { + enet_peer_disconnect_later(event.peer, DISC_INVALID); + buildprint("Invalid player id (", playeridx, ") from client.\n"); + continue; + } + + switch (event.type) + { + case ENET_EVENT_TYPE_CONNECT: + { + char ipaddr[32]; + + enet_address_get_host_ip(&event.peer->address, ipaddr, sizeof(ipaddr)); + + Printf("A new client connected from %s:%u.\n", ipaddr, event.peer->address.port); + + Net_SendAcknowledge(event.peer); + break; + } + + case ENET_EVENT_TYPE_RECEIVE: + /* + Printf ("A packet of length %u containing %s was received from player %d on channel %u.\n", + event.packet -> dataLength, + event.packet -> data, + event.peer -> data, + event.channelID); + */ + Net_ParseClientPacket(&event); + // broadcast takes care of enet_packet_destroy itself + // we set the state to disconnected so enet_host_broadcast + // doesn't send the player back his own packets + if ((event.channelID == CHAN_GAMESTATE && event.packet->data[0] > PACKET_BROADCAST) + || event.channelID == CHAN_CHAT) + { + const ENetPacket *pak = event.packet; + + event.peer->state = ENET_PEER_STATE_DISCONNECTED; + enet_host_broadcast(g_netServer, event.channelID, + enet_packet_create(pak->data, pak->dataLength, pak->flags&ENET_PACKET_FLAG_RELIABLE)); + event.peer->state = ENET_PEER_STATE_CONNECTED; + } + + enet_packet_destroy(event.packet); + //g_player[playeridx].ping = (event.peer->lastRoundTripTime + event.peer->roundTripTime)/2; + break; + + case ENET_EVENT_TYPE_DISCONNECT: + numplayers--; + ud.multimode--; + + P_RemovePlayer(playeridx); + + packbuf[0] = PACKET_PLAYER_DISCONNECTED; + packbuf[1] = playeridx; + packbuf[2] = numplayers; + packbuf[3] = ud.multimode; + packbuf[4] = g_mostConcurrentPlayers; + packbuf[5] = myconnectindex; + + enet_host_broadcast(g_netServer, CHAN_GAMESTATE, + enet_packet_create(packbuf, 6, ENET_PACKET_FLAG_RELIABLE)); + + Printf("%s disconnected.\n", g_player[playeridx].user_name); + event.peer->data = NULL; + break; + + default: + break; + } + } +} + +void Net_HandleServerPackets(void) +{ + ENetEvent event; + + enet_host_service(g_netClient, NULL, 0); + + while (enet_host_check_events(g_netClient, &event) > 0) + { + if (event.type == ENET_EVENT_TYPE_DISCONNECT) + { + Net_ReceiveDisconnect(&event); + } + else if (event.type == ENET_EVENT_TYPE_RECEIVE) + { + Net_ParseServerPacket(&event); + } + + enet_packet_destroy(event.packet); + } +} + +void Net_ParseClientPacket(ENetEvent *event) +{ + switch (event->channelID) + { + case CHAN_REROUTE: + { + char *packet = (char*)event->packet->data; + int dest = *packet++; + int source = *packet++; + int size = event->packet->dataLength-2; + if (g_netPlayerPeer[dest]) + { + ENetPacket *netpacket = enet_packet_create(NULL, size+1, ENET_PACKET_FLAG_RELIABLE); + char *buffer = (char*)netpacket->data; + *buffer++ = source; + Bmemcpy(buffer, packet, size); + enet_peer_send(g_netPlayerPeer[dest], CHAN_GAMESTATE, netpacket); + enet_host_service(g_netServer, NULL, 0); + } + break; + } + case CHAN_GAME: + Net_ParsePacket(event->packet->data, event->packet->dataLength); + break; + default: + { + uint8_t *pbuf = event->packet->data; + int32_t packbufleng = event->packet->dataLength; + int32_t other = pbuf[--packbufleng]; + switch (pbuf[0]) + { + //case PACKET_SLAVE_TO_MASTER: //[1] (receive slave sync buffer) + // Net_ReceiveClientUpdate(event); + // break; + + //case PACKET_PLAYER_READY: + // + // if (other == 0) + // { + // break; + // } + // + // j = g_player[other].ps->i; + // Bmemcpy(g_player[other].ps, g_player[0].ps, sizeof(DukePlayer_t)); + // + // g_player[other].ps->i = j; + // changespritestat(j, STAT_PLAYER); + // + // g_player[other].ps->last_extra = sprite[g_player[other].ps->i].extra = g_player[other].ps->max_player_health; + // sprite[g_player[other].ps->i].cstat = 1+256; + // actor[g_player[other].ps->i].t_data[2] = actor[g_player[other].ps->i].t_data[3] = actor[g_player[other].ps->i].t_data[4] = 0; + // + // P_ResetPlayer(other); + // Net_SpawnPlayer(other); + // + // break; + + //case PACKET_PLAYER_PING: + // if (g_player[myconnectindex].ps->gm & MODE_GAME) + // { + // packbuf[0] = PACKET_PLAYER_PING; + // packbuf[1] = myconnectindex; + // enet_peer_send(event->peer, CHAN_GAMESTATE, enet_packet_create(packbuf, 2, ENET_PACKET_FLAG_RELIABLE)); + // } + // g_player[other].pingcnt++; + // break; + + case PACKET_AUTH: + Net_ReceiveChallenge(pbuf, packbufleng, event); + break; + + default: + Net_ParsePacketCommon(pbuf, packbufleng, 0); + break; + } + break; + } + } + +#if 0 + Printf("Received Packet: type: %d : len %d\n", pbuf[0], packbufleng); +#endif +} + +void Net_ParseServerPacket(ENetEvent *event) +{ + if (event->channelID == CHAN_GAME) + { + Net_ParsePacket(event->packet->data, event->packet->dataLength); + return; + } + uint8_t *pbuf = event->packet->data; + int32_t packbufleng = event->packet->dataLength; + // input_t *nsyn; + + --packbufleng; // int32_t other = pbuf[--packbufleng]; + +#if 0 + Printf("Received Packet: type: %d : len %d\n", pbuf[0], packbufleng); +#endif + switch (pbuf[0]) + { + + //case PACKET_MAP_STREAM: + // + // if (!(g_player[myconnectindex].ps->gm & MODE_GAME)) + // return; + // + // Net_ReceiveMapUpdate(event); + // + // break; + + case PACKET_NEW_GAME: + Net_ReceiveNewGame(event); + break; + + case PACKET_ACK: + Net_ReceiveAcknowledge(pbuf, packbufleng); + break; + + case PACKET_NUM_PLAYERS: + Net_ReceiveNewPlayer(event->packet->data, event->packet->dataLength); + break; + + case PACKET_PLAYER_INDEX: + Net_ReceivePlayerIndex(event->packet->data, event->packet->dataLength); + break; + + case PACKET_PLAYER_DISCONNECTED: + //if ((g_player[myconnectindex].ps->gm & MODE_GAME)) + P_RemovePlayer(pbuf[1]); + numplayers = pbuf[2]; + ud.multimode = pbuf[3]; + g_mostConcurrentPlayers = pbuf[4]; + break; + + //case PACKET_PLAYER_SPAWN: + // if (!(g_player[myconnectindex].ps->gm & MODE_GAME)) break; + // + // P_ResetPlayer(pbuf[1]); + // Bmemcpy(&g_player[pbuf[1]].ps->pos.x, &pbuf[2], sizeof(vec3_t) * 2); + // Bmemcpy(&sprite[g_player[pbuf[1]].ps->i], &pbuf[2], sizeof(vec3_t)); + // break; + + //case PACKET_PLAYER_PING: + // g_player[0].pingcnt++; + // return; + + //case PACKET_FRAG: + // if (!(g_player[myconnectindex].ps->gm & MODE_GAME)) break; + // g_player[pbuf[1]].ps->frag_ps = pbuf[2]; + // actor[g_player[pbuf[1]].ps->i].picnum = pbuf[3]; + // ticrandomseed = B_UNBUF32(&pbuf[4]); + // P_FragPlayer(pbuf[1]); + // break; + + default: + Net_ParsePacketCommon(pbuf, packbufleng, 1); + break; + } +} + +void Net_SendPacket(int dest, uint8_t *pbuf, int32_t packbufleng) +{ + if (g_networkMode == NET_SERVER) + { + if (!g_netServer) + return; + if (g_netPlayerPeer[dest] != NULL) + { + ENetPacket* packet = enet_packet_create(NULL, packbufleng+1, ENET_PACKET_FLAG_RELIABLE); + uint8_t* buffer = packet->data; + *buffer++ = myconnectindex; + Bmemcpy(buffer, pbuf, packbufleng); + enet_peer_send(g_netPlayerPeer[dest], CHAN_GAME, packet); + enet_host_service(g_netServer, NULL, 0); + } + } + if (g_networkMode == NET_CLIENT) + { + if (!g_netClient) + return; + if (dest == 0) + { + ENetPacket *packet = enet_packet_create(NULL, packbufleng+1, ENET_PACKET_FLAG_RELIABLE); + uint8_t* buffer = packet->data; + *buffer++ = myconnectindex; + Bmemcpy(buffer, pbuf, packbufleng); + enet_peer_send(g_netClientPeer, CHAN_GAME, packet); + } + else + { + ENetPacket * packet = enet_packet_create(NULL, packbufleng+2, ENET_PACKET_FLAG_RELIABLE); + uint8_t* buffer = packet->data; + *buffer++ = dest; + *buffer++ = myconnectindex; + Bmemcpy(buffer, pbuf, packbufleng); + enet_peer_send(g_netClientPeer, CHAN_REROUTE, packet); + } + enet_host_service(g_netClient, NULL, 0); + } +} + +void Net_ParsePacketCommon(uint8_t *pbuf, int32_t packbufleng, int32_t serverpacketp) +{ + switch (pbuf[0]) + { + case PACKET_MESSAGE: + Net_ReceiveMessage(pbuf, packbufleng); + break; + + case PACKET_CLIENT_INFO: + Net_ReceiveClientInfo(pbuf, packbufleng, serverpacketp); + break; + + case PACKET_RTS: + G_StartRTS(pbuf[1], 0); + break; + + case PACKET_USER_MAP: + Net_ReceiveUserMapName(pbuf, packbufleng); + break; + + case PACKET_MAP_VOTE: + Net_ReceiveMapVote(pbuf); + break; + + case PACKET_MAP_VOTE_INITIATE: // call map vote + Net_ReceiveMapVoteInitiate(pbuf); + break; + + case PACKET_MAP_VOTE_CANCEL: // cancel map vote + Net_ReceiveMapVoteCancel(pbuf); + break; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Acknowledgement Packets + +void Net_SendAcknowledge(ENetPeer *client) +{ + if (!g_netServer) + return; + + tempbuf[0] = PACKET_ACK; + tempbuf[1] = myconnectindex; + + enet_peer_send(client, CHAN_GAMESTATE, enet_packet_create(&tempbuf[0], 2, ENET_PACKET_FLAG_RELIABLE)); +} + +void Net_ReceiveAcknowledge(uint8_t *pbuf, int32_t packbufleng) +{ + UNREFERENCED_PARAMETER(pbuf); // remove when this variable is used + UNREFERENCED_PARAMETER(packbufleng); // remove when this variable is used + + Net_SendChallenge(); +} + +//////////////////////////////////////////////////////////////////////////////// +// Challenge Packets + +// sends the version and a simple crc32 of the current password, all verified by the server before the connection can continue +void Net_SendChallenge() +{ + if (!g_netClientPeer) + { + return; + } + + tempbuf[0] = PACKET_AUTH; + B_BUF16(&tempbuf[1], BYTEVERSION); + B_BUF16(&tempbuf[3], NETVERSION); + B_BUF32(&tempbuf[5], Bcrc32((uint8_t *)g_netPassword, Bstrlen(g_netPassword), 0)); + tempbuf[9] = myconnectindex; + + enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(&tempbuf[0], 10, ENET_PACKET_FLAG_RELIABLE)); +} + +void Net_ReceiveChallenge(uint8_t *pbuf, int32_t packbufleng, ENetEvent *event) +{ + const uint16_t byteVersion = B_UNBUF16(&pbuf[1]); + const uint16_t netVersion = B_UNBUF16(&pbuf[3]); + const uint32_t crc = B_UNBUF32(&pbuf[5]); + + UNREFERENCED_PARAMETER(packbufleng); // remove when this variable is used + + if (g_player[myconnectindex].ps->gm&MODE_GAME) + { + enet_peer_disconnect_later(event->peer, DISC_GAME_STARTED); + Printf("Client attempted to connect to started game\n"); + return; + } + + if (byteVersion != BYTEVERSION || netVersion != NETVERSION) + { + enet_peer_disconnect_later(event->peer, DISC_VERSION_MISMATCH); + Printf("Bad client protocol: version %u.%u\n", byteVersion, netVersion); + return; + } + if (crc != Bcrc32((uint8_t *)g_netPassword, Bstrlen(g_netPassword), 0)) + { + enet_peer_disconnect_later(event->peer, DISC_BAD_PASSWORD); + Printf("Bad password from client.\n"); + return; + } + + Net_SyncPlayer(event); +} + +//////////////////////////////////////////////////////////////////////////////// +// Num Players Packets + +static void P_RemovePlayer(int32_t p) +{ + // server obviously can't leave the game, and index 0 shows up for disconnect events from + // players that haven't gotten far enough into the connection process to get a player ID + + if (p <= 0) return; + + g_player[p].playerquitflag = 0; + + Bsprintf(recbuf,"%s^00 is history!",g_player[p].user_name); + G_AddUserQuote(recbuf); + + if (numplayers == 1) + S_PlaySound(GENERIC_AMBIENCE17); +} + +void Net_SendNewPlayer(int32_t newplayerindex) +{ + packbuf[0] = PACKET_NUM_PLAYERS; + packbuf[1] = numplayers; + packbuf[2] = g_mostConcurrentPlayers; + packbuf[3] = ud.multimode; + packbuf[4] = newplayerindex; + packbuf[5] = g_networkMode; + packbuf[6] = myconnectindex; + enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(packbuf, 7, ENET_PACKET_FLAG_RELIABLE)); +} + +void Net_ReceiveNewPlayer(uint8_t *pbuf, int32_t packbufleng) +{ + int32_t i; + + UNREFERENCED_PARAMETER(packbufleng); // remove when this variable is used + + numplayers = pbuf[1]; + g_mostConcurrentPlayers = pbuf[2]; + ud.multimode = pbuf[3]; + if (pbuf[4]) // ID of new player + { + g_player[pbuf[4]].playerquitflag = 1; + + if (!g_player[pbuf[4]].ps) + { + g_player[pbuf[4]].ps = (DukePlayer_t *) Xcalloc(1,sizeof(DukePlayer_t)); + } + if (!g_player[pbuf[4]].input) + { + g_player[pbuf[4]].input = (input_t *) Xcalloc(1,sizeof(input_t)); + } + } + +//#ifndef NETCODE_DISABLE +// if (pbuf[5] == NET_DEDICATED_SERVER) +// { +// g_networkMode = NET_DEDICATED_CLIENT; +// } +//#endif + + for (i=0; iaim_mode = in_mousemode; + tempbuf[l++] = g_player[myconnectindex].ps->auto_aim = cl_autoaim; + tempbuf[l++] = g_player[myconnectindex].ps->weaponswitch = cl_weaponswitch; + tempbuf[l++] = g_player[myconnectindex].ps->palookup = g_player[myconnectindex].pcolor = G_CheckPlayerColor(playercolor); + + tempbuf[l++] = g_player[myconnectindex].pteam = playerteam; + + for (i=0; i<10; i++) + { + g_player[myconnectindex].wchoice[i] = g_player[0].wchoice[i]; + tempbuf[l++] = (uint8_t)g_player[0].wchoice[i]; + } + + tempbuf[l++] = myconnectindex; + + if (g_netClient) + { + enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(&tempbuf[0], l, ENET_PACKET_FLAG_RELIABLE)); + } + else if (g_netServer) + { + enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(&tempbuf[0], l, ENET_PACKET_FLAG_RELIABLE)); + } +} + +void Net_ReceiveClientInfo(uint8_t *pbuf, int32_t packbufleng, int32_t fromserver) +{ + uint32_t i, j; + int32_t other = pbuf[packbufleng]; + + for (i=1; pbuf[i]; i++) + { + g_player[other].user_name[i-1] = pbuf[i]; + } + + g_player[other].user_name[i-1] = 0; + i++; + + g_player[other].ps->aim_mode = pbuf[i++]; + g_player[other].ps->auto_aim = pbuf[i++]; + g_player[other].ps->weaponswitch = pbuf[i++]; + g_player[other].ps->palookup = g_player[other].pcolor = pbuf[i++]; + g_player[other].pteam = pbuf[i++]; + + for (j=i; i-j<10; i++) + { + g_player[other].wchoice[i-j] = pbuf[i]; + } + + if (fromserver) + { + g_player[other].playerquitflag = 1; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Map Name Packets + +void Net_SendUserMapName(void) +{ + int32_t j; + + if (numplayers < 2) + return; + + packbuf[0] = PACKET_USER_MAP; + + // user map name is sent with a NUL at the end + j = Bstrlen(boardfilename)+1; + Bmemcpy(&packbuf[1], boardfilename, j); + j++; + + packbuf[j++] = myconnectindex; + + if (g_netClient) + { + enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(packbuf, j, ENET_PACKET_FLAG_RELIABLE)); + } + else if (g_netServer) + { + enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(packbuf, j, ENET_PACKET_FLAG_RELIABLE)); + } +} + +void Net_ReceiveUserMapName(uint8_t *pbuf, int32_t packbufleng) +{ + Bstrcpy(boardfilename,(char *)pbuf+1); + boardfilename[packbufleng-1] = 0; + if (boardfilename[0] != 0) + { + if (fileSystem.FileExists(boardfilename)) + { + Bmemset(boardfilename,0,sizeof(boardfilename)); + Net_SendUserMapName(); + } + } + + if (m_level_number == 7 && ud.m_volume_number == 0 && boardfilename[0] == 0) + m_level_number = 0; +} + +void Net_SendMessage(void) +{ +#if 0 + if (g_player[myconnectindex].ps->gm&MODE_SENDTOWHOM) + { + int32_t i, j; + if (g_chatPlayer != -1 || ud.multimode < 3) + { + tempbuf[0] = PACKET_MESSAGE; + tempbuf[2] = 0; + recbuf[0] = 0; + + if (ud.multimode < 3) + g_chatPlayer = 2; + + if (typebuf[0] == '/' && Btoupper(typebuf[1]) == 'M' && Btoupper(typebuf[2]) == 'E') + { + Bstrcat(recbuf,"* "); + i = 3, j = Bstrlen(typebuf); + Bstrcpy(tempbuf,typebuf); + while (i < j) + { + typebuf[i-3] = tempbuf[i]; + i++; + } + typebuf[i-3] = '\0'; + Bstrcat(recbuf,g_player[myconnectindex].user_name); + } + else + { + Bstrcat(recbuf,g_player[myconnectindex].user_name); + Bstrcat(recbuf,": "); + } + + Bstrcat(recbuf,"^00"); + Bstrcat(recbuf,typebuf); + j = Bstrlen(recbuf); + recbuf[j] = 0; + Bstrcat(tempbuf+2,recbuf); + + if (g_chatPlayer >= ud.multimode) + { + tempbuf[1] = 255; + tempbuf[j+2] = myconnectindex; + j++; + if (g_netServer) enet_host_broadcast(g_netServer, CHAN_CHAT, enet_packet_create(tempbuf, j+2, 0)); + else if (g_netClient) enet_peer_send(g_netClientPeer, CHAN_CHAT, enet_packet_create(tempbuf, j+2, 0)); + G_AddUserQuote(recbuf); + } + g_chatPlayer = -1; + g_player[myconnectindex].ps->gm &= ~(MODE_TYPE|MODE_SENDTOWHOM); + } + else if (g_chatPlayer == -1) + { + j = 50; + gametext_center(j, "Send message to..."); + j += 8; + for (TRAVERSE_CONNECT(i)) + { + if (i == myconnectindex) + { + minitextshade((320>>1)-40+1,j+1,"A/ENTER - ALL",26,0,2+8+16); + minitext((320>>1)-40,j,"A/ENTER - ALL",0,2+8+16); + j += 7; + } + else + { + Bsprintf(recbuf," %d - %s",i+1,g_player[i].user_name); + minitextshade((320>>1)-40-6+1,j+1,recbuf,26,0,2+8+16); + minitext((320>>1)-40-6,j,recbuf,0,2+8+16); + j += 7; + } + } + minitextshade((320>>1)-40-4+1,j+1," ESC - Abort",26,0,2+8+16); + minitext((320>>1)-40-4,j," ESC - Abort",0,2+8+16); + j += 7; + + mpgametext(mpgametext_x, ud.screen_size > 0 ? (200-45)<<16 : (200-8)<<16, typebuf, 0, 0, 0, 0); + + if (inputState.keyBufferWaiting()) + { + i = inputState.keyGetChar(); + + if (i == 'A' || i == 'a' || i == 13) + g_chatPlayer = ud.multimode; + else if (i >= '1' || i <= (ud.multimode + '1')) + g_chatPlayer = i - '1'; + else + { + g_chatPlayer = ud.multimode; + if (i == 27) + { + g_player[myconnectindex].ps->gm &= ~(MODE_TYPE|MODE_SENDTOWHOM); + g_chatPlayer = -1; + } + else + typebuf[0] = 0; + } + + inputState.ClearKeyStatus(sc_1); + inputState.ClearKeyStatus(sc_2); + inputState.ClearKeyStatus(sc_3); + inputState.ClearKeyStatus(sc_4); + inputState.ClearKeyStatus(sc_5); + inputState.ClearKeyStatus(sc_6); + inputState.ClearKeyStatus(sc_7); + inputState.ClearKeyStatus(sc_8); + inputState.ClearKeyStatus(sc_A); + inputState.ClearKeyStatus(sc_Escape); + inputState.ClearKeyStatus(sc_Enter); + } + } + } +#endif +} + +void Net_ReceiveMessage(uint8_t *pbuf, int32_t packbufleng) +{ + Bstrncpy(recbuf, (char *)pbuf+2, packbufleng-2); + recbuf[packbufleng-2] = 0; + + G_AddUserQuote(recbuf); + S_PlaySound(EXITMENUSOUND, CHAN_AUTO, CHANF_UI); + + pus = pub = NUMPAGES; +} + +//////////////////////////////////////////////////////////////////////////////// +// New Game Packets + +void Net_StartNewGame() +{ + int32_t i; + + for (TRAVERSE_CONNECT(i)) + { + P_ResetWeapons(i); + P_ResetInventory(i); + //g_player[i].revision = 0; + } + + Net_ExtractNewGame(&pendingnewgame, 0); + G_NewGame(ud.volume_number,ud.level_number,ud.player_skill); + ud.coop = m_coop; + + //g_netMapRevision = 0; + + if (G_EnterLevel(MODE_GAME)) + { + G_BackToMenu(); + } +} + +void Net_NotifyNewGame() +{ +} + +void Net_SendNewGame(int32_t frommenu, ENetPeer *peer) +{ + newgame_t newgame; + + newgame.header = PACKET_NEW_GAME; + Net_FillNewGame(&newgame, frommenu); + + if (peer) + { + enet_peer_send(peer, CHAN_GAMESTATE, enet_packet_create(&newgame, sizeof(newgame_t), ENET_PACKET_FLAG_RELIABLE)); + } + else + { + enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(&newgame, sizeof(newgame_t), ENET_PACKET_FLAG_RELIABLE)); + } +} + +void Net_ReceiveNewGame(ENetEvent *event) +{ + if ((vote_map + vote_episode + voting) != -3) + G_AddUserQuote("Vote Succeeded"); + + Bmemcpy(&pendingnewgame, event->packet->data, sizeof(newgame_t)); + Net_StartNewGame(); + + //packbuf[0] = PACKET_PLAYER_READY; + //packbuf[1] = myconnectindex; + // + //if (g_netClientPeer) + //{ + // enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(packbuf, 2, ENET_PACKET_FLAG_RELIABLE)); + //} + // + //g_player[myconnectindex].ps->gm = MODE_GAME; + //ready2send = 1; +} + +void Net_FillNewGame(newgame_t *newgame, int32_t frommenu) +{ + if (frommenu) + { + newgame->level_number = m_level_number; + newgame->volume_number = ud.m_volume_number; + newgame->player_skill = ud.m_player_skill; + newgame->monsters_off = ud.m_monsters_off; + newgame->respawn_monsters = ud.m_respawn_monsters; + newgame->respawn_items = ud.m_respawn_items; + newgame->respawn_inventory = ud.m_respawn_inventory; + newgame->ffire = m_ffire; + newgame->noexits = m_noexits; + newgame->coop = m_coop; + } + else + { + newgame->level_number = ud.level_number; + newgame->volume_number = ud.volume_number; + newgame->player_skill = ud.player_skill; + newgame->monsters_off = ud.monsters_off; + newgame->respawn_monsters = ud.respawn_monsters; + newgame->respawn_items = ud.respawn_items; + newgame->respawn_inventory = ud.respawn_inventory; + newgame->ffire = ud.ffire; + newgame->noexits = ud.noexits; + newgame->coop = ud.coop; + } +} + +void Net_ExtractNewGame(newgame_t *newgame, int32_t menuonly) +{ + m_level_number = newgame->level_number; + ud.m_volume_number = newgame->volume_number; + ud.m_player_skill = newgame->player_skill; + ud.m_monsters_off = newgame->monsters_off; + ud.m_respawn_monsters = newgame->respawn_monsters; + ud.m_respawn_items = newgame->respawn_items; + ud.m_respawn_inventory = newgame->respawn_inventory; + m_ffire = newgame->ffire; + m_noexits = newgame->noexits; + m_coop = newgame->coop; + + if (!menuonly) + { + ud.level_number = newgame->level_number; + ud.volume_number = newgame->volume_number; + ud.player_skill = newgame->player_skill; + ud.monsters_off = newgame->monsters_off; + ud.respawn_monsters = newgame->respawn_monsters; + ud.respawn_monsters = newgame->respawn_items; + ud.respawn_inventory = newgame->respawn_inventory; + ud.ffire = newgame->ffire; + ud.noexits = newgame->noexits; + ud.coop = newgame->coop; + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Map Vote Packets + +void Net_SendMapVoteInitiate(void) +{ + newgame_t newgame; + + if (!g_netClient) + { + return; + } + + voting = myconnectindex; + + newgame.header = PACKET_MAP_VOTE_INITIATE; + newgame.connection = myconnectindex; + Net_FillNewGame(&newgame, 1); + + enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(&newgame, sizeof(newgame_t), ENET_PACKET_FLAG_RELIABLE)); +} + +void Net_ReceiveMapVoteInitiate(uint8_t *pbuf) +{ + int32_t i; + + Bmemcpy(&pendingnewgame, pbuf, sizeof(newgame_t)); + Net_ExtractNewGame(&pendingnewgame, 1); + + voting = pendingnewgame.connection; + vote_episode = pendingnewgame.volume_number; + vote_map = pendingnewgame.level_number; + + Bsprintf(tempbuf,"%s^00 has called a vote to change map to %s (E%dL%d)", + g_player[voting].user_name, + mapList[(uint8_t)(vote_episode*MAXLEVELS + vote_map)].DisplayName(), + vote_episode+1,vote_map+1); + G_AddUserQuote(tempbuf); + + Bsprintf(tempbuf,"Press F1 to Accept, F2 to Decline"); + G_AddUserQuote(tempbuf); + + for (i=MAXPLAYERS-1; i>=0; i--) + { + g_player[i].vote = 0; + g_player[i].gotvote = 0; + } + + g_player[voting].gotvote = g_player[voting].vote = 1; +} + +void Net_SendMapVote(int32_t votefor) +{ + voting = -1; + g_player[myconnectindex].gotvote = 1; + g_player[myconnectindex].vote = votefor; + + tempbuf[0] = PACKET_MAP_VOTE; + tempbuf[1] = myconnectindex; + tempbuf[2] = votefor; + tempbuf[3] = myconnectindex; + + if (g_netClient) + { + enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE)); + } + else if (g_netServer) + { + enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 4, ENET_PACKET_FLAG_RELIABLE)); + } + + Net_CheckForEnoughVotes(); +} + +void Net_ReceiveMapVote(uint8_t *pbuf) +{ + if (voting == myconnectindex && g_player[(uint8_t)pbuf[1]].gotvote == 0) + { + Bsprintf(tempbuf,"Confirmed vote from %s",g_player[(uint8_t)pbuf[1]].user_name); + G_AddUserQuote(tempbuf); + } + + if (!g_netServer) + { + return; + } + + g_player[(uint8_t)pbuf[1]].gotvote = 1; + g_player[(uint8_t)pbuf[1]].vote = pbuf[2]; + Net_CheckForEnoughVotes(); +} + +void Net_CheckForEnoughVotes() +{ + int32_t i; + int32_t requiredvotes; + int32_t numfor, numagainst; + + // Only the server can decide map changes + if (!g_netServer || numplayers <= 1) + { + return; + } + + // If there are just two players, both of them deserve a vote + if (numplayers == 2) + { + requiredvotes = 2; + } + else + { + // If more than two players, we need at least 50% of the players to vote + // Which means that if there's an odd number of players, we'll need slightly more than 50% of the vote. + requiredvotes = numplayers / 2; + if (numplayers % 2 == 1) + { + requiredvotes++; + } + } + + numfor = numagainst = 0; + for (i=0; i= requiredvotes) + { + Net_StartNewGame(); + Net_SendNewGame(1, NULL); + } + else if (numagainst >= requiredvotes || (numfor + numagainst) == numplayers) + { + Net_SendMapVoteCancel(1); + } +} + +// If failed is true, that means the vote lost. Otherwise it was cancelled by the client who initiated it. +void Net_SendMapVoteCancel(int32_t failed) +{ + // Only the server or the client that initiated the vote can cancel the vote + if (g_netClient && voting != myconnectindex) + { + return; + } + + tempbuf[0] = PACKET_MAP_VOTE_CANCEL; + tempbuf[1] = myconnectindex; + + // If we're forwarding a cancelled message, change the connection index to the one who cancelled it. + if (g_netServer && !failed) + { + tempbuf[1] = voting; + } + + voting = -1; + + if (g_netClient) + { + enet_peer_send(g_netClientPeer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 2, ENET_PACKET_FLAG_RELIABLE)); + } + else if (g_netServer) + { + enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(tempbuf, 2, ENET_PACKET_FLAG_RELIABLE)); + } +} + +void Net_ReceiveMapVoteCancel(uint8_t *pbuf) +{ + // int32_t numvotes; + + // Ignore if we're not voting + if (voting == -1) + { + return; + } + + // Ignore cancellations from clients that did not initiate the map vote + if (voting != pbuf[1] && voting != myconnectindex) + { + return; + } + + if (voting == myconnectindex || voting != pbuf[1]) + { + Bsprintf(tempbuf,"Vote Failed"); + } + else if (voting == pbuf[1]) + { + Bsprintf(tempbuf,"%s^00 has canceled the vote",g_player[voting].user_name); + } + + G_AddUserQuote(tempbuf); + + if (g_netServer) + { + Net_SendMapVoteCancel(0); + } + + voting = -1; +} + +void Net_SendTaunt(int ridiculeNum) +{ + tempbuf[0] = PACKET_MESSAGE; + tempbuf[1] = 255; + tempbuf[2] = 0; + Bstrcat(tempbuf + 2, *CombatMacros[ridiculeNum - 1]); + + ridiculeNum = 2 + strlen(*CombatMacros[ridiculeNum - 1]); + + tempbuf[ridiculeNum++] = myconnectindex; + + if (g_netClient) + enet_peer_send(g_netClientPeer, CHAN_CHAT, enet_packet_create(&tempbuf[0], ridiculeNum, 0)); + else if (g_netServer) + enet_host_broadcast(g_netServer, CHAN_CHAT, enet_packet_create(&tempbuf[0], ridiculeNum, 0)); + +} + +void Net_SendRTS(int ridiculeNum) +{ + if ((g_netServer || ud.multimode > 1)) + { + tempbuf[0] = PACKET_RTS; + tempbuf[1] = ridiculeNum; + tempbuf[2] = myconnectindex; + + if (g_netClient) + enet_peer_send(g_netClientPeer, CHAN_CHAT, enet_packet_create(&tempbuf[0], 3, 0)); + else if (g_netServer) + enet_host_broadcast(g_netServer, CHAN_CHAT, enet_packet_create(&tempbuf[0], 3, 0)); + } +} + +void Net_InitNetwork() +{ + if (g_networkMode == NET_SERVER/* || g_networkMode == NET_DEDICATED_SERVER*/) + { + ENetAddress address = { ENET_HOST_ANY, g_netPort }; + g_netServer = enet_host_create(&address, MAXPLAYERS, CHAN_MAX, 0, 0); + + if (g_netServer == NULL) + Printf("An error occurred while trying to create an ENet server host.\n"); + else Printf("Multiplayer server initialized\n"); + } +} + +void Net_PrintLag(FString& output) +{ + // lag meter + if (g_netClientPeer) + { + output.AppendFormat("%d +- %d ms\n", (g_netClientPeer->lastRoundTripTime + g_netClientPeer->roundTripTime) / 2, + (g_netClientPeer->lastRoundTripTimeVariance + g_netClientPeer->roundTripTimeVariance) / 2); + } +} + +int osdcmd_listplayers(CCmdFuncPtr parm) +{ + ENetPeer* currentPeer; + char ipaddr[32]; + + if (parm && parm->numparms != 0) + return OSDCMD_SHOWHELP; + + if (!g_netServer) + { + Printf("You are not the server.\n"); + return OSDCMD_OK; + } + + Printf("Connected clients:\n"); + + for (currentPeer = g_netServer->peers; + currentPeer < &g_netServer->peers[g_netServer->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + + enet_address_get_host_ip(¤tPeer->address, ipaddr, sizeof(ipaddr)); + Printf("%s %s\n", ipaddr, + g_player[(intptr_t)currentPeer->data].user_name); + } + + return OSDCMD_OK; +} + +#if 0 +static int osdcmd_kick(CCmdFuncPtr parm) +{ + ENetPeer* currentPeer; + uint32_t hexaddr; + + if (parm->numparms != 1) + return OSDCMD_SHOWHELP; + + if (!g_netServer) + { + Printf("You are not the server.\n"); + return OSDCMD_OK; + } + + for (currentPeer = g_netServer->peers; + currentPeer < &g_netServer->peers[g_netServer->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + + sscanf(parm->parms[0], "%" SCNx32 "", &hexaddr); + + if (currentPeer->address.host == hexaddr) + { + Printf("Kicking %x (%s)\n", currentPeer->address.host, + g_player[(intptr_t)currentPeer->data].user_name); + enet_peer_disconnect(currentPeer, DISC_KICKED); + return OSDCMD_OK; + } + } + + Printf("Player %s not found!\n", parm->parms[0]); + osdcmd_listplayers(NULL); + + return OSDCMD_OK; +} + +static int osdcmd_kickban(CCmdFuncPtr parm) +{ + ENetPeer* currentPeer; + uint32_t hexaddr; + + if (parm->numparms != 1) + return OSDCMD_SHOWHELP; + + if (!g_netServer) + { + Printf("You are not the server.\n"); + return OSDCMD_OK; + } + + for (currentPeer = g_netServer->peers; + currentPeer < &g_netServer->peers[g_netServer->peerCount]; + ++currentPeer) + { + if (currentPeer->state != ENET_PEER_STATE_CONNECTED) + continue; + + sscanf(parm->parms[0], "%" SCNx32 "", &hexaddr); + + // TODO: implement banning logic + + if (currentPeer->address.host == hexaddr) + { + char ipaddr[32]; + + enet_address_get_host_ip(¤tPeer->address, ipaddr, sizeof(ipaddr)); + Printf("Host %s is now banned.\n", ipaddr); + Printf("Kicking %x (%s)\n", currentPeer->address.host, + g_player[(intptr_t)currentPeer->data].user_name); + enet_peer_disconnect(currentPeer, DISC_BANNED); + return OSDCMD_OK; + } + } + + Printf("Player %s not found!\n", parm->parms[0]); + osdcmd_listplayers(NULL); + + return OSDCMD_OK; +} +#endif + + +#endif // !defined NETCODE_DISABLE + +END_DUKE_NS diff --git a/source/duke/src/net.h b/source/duke/src/net.h new file mode 100644 index 000000000..e6cdf020a --- /dev/null +++ b/source/duke/src/net.h @@ -0,0 +1,411 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef netplay_h_ +#define netplay_h_ + +struct ENetHost; +struct ENetPeer; +struct ENetEvent; +struct ENetPacket; + +BEGIN_DUKE_NS + +// net packet specification/compatibility version +#define NETVERSION 1 + +extern ENetHost *g_netClient; +extern ENetHost *g_netServer; +extern ENetPeer *g_netClientPeer; +extern char g_netPassword[32]; +extern int32_t g_netDisconnect; +extern int32_t g_netPlayersWaiting; +extern uint16_t g_netPort; +#ifndef NETCODE_DISABLE +extern int32_t g_networkMode; +#else +#define g_networkMode 0 +#endif +extern int32_t g_netIndex; +extern int32_t lastsectupdate[MAXSECTORS]; +extern int32_t lastupdate[MAXSPRITES]; +extern int32_t lastwallupdate[MAXWALLS]; +extern int16_t g_netStatnums[]; + +#define NET_REVISIONS 64 + +enum netchan_t +{ + CHAN_REROUTE, + CHAN_GAME, + //CHAN_MOVE, // unreliable movement packets + CHAN_GAMESTATE, // gamestate changes... frags, respawns, player names, etc + CHAN_CHAT, // chat and RTS + //CHAN_MISC, // whatever else + CHAN_MAX +}; + +enum ServicePacket_t +{ + SERVICEPACKET_TYPE_SENDTOID, +}; + +enum DukePacket_t +{ + PACKET_TYPE_MASTER_TO_SLAVE, + PACKET_TYPE_SLAVE_TO_MASTER, + PACKET_TYPE_BROADCAST, + SERVER_GENERATED_BROADCAST, + //PACKET_TYPE_VERSION, + + /* don't change anything above this line */ + + //PACKET_TYPE_MESSAGE, + // + //PACKET_TYPE_NEW_GAME, + //PACKET_TYPE_RTS, + //PACKET_TYPE_MENU_LEVEL_QUIT, + //PACKET_TYPE_WEAPON_CHOICE, + //PACKET_TYPE_PLAYER_OPTIONS, + //PACKET_TYPE_PLAYER_NAME, + //PACKET_TYPE_INIT_SETTINGS, + // + //PACKET_TYPE_USER_MAP, + // + //PACKET_TYPE_MAP_VOTE, + //PACKET_TYPE_MAP_VOTE_INITIATE, + //PACKET_TYPE_MAP_VOTE_CANCEL, + // + //PACKET_TYPE_LOAD_GAME, + PACKET_TYPE_NULL_PACKET, + PACKET_TYPE_PLAYER_READY, + //PACKET_TYPE_FRAGLIMIT_CHANGED, + //PACKET_TYPE_EOL, + //PACKET_TYPE_QUIT = 255, // should match mmulti I think + + + //PACKET_MASTER_TO_SLAVE, + //PACKET_SLAVE_TO_MASTER, + + PACKET_NUM_PLAYERS, + PACKET_PLAYER_INDEX, + PACKET_PLAYER_DISCONNECTED, + //PACKET_PLAYER_SPAWN, + //PACKET_FRAG, + PACKET_ACK, + PACKET_AUTH, + //PACKET_PLAYER_PING, + //PACKET_PLAYER_READY, + //PACKET_MAP_STREAM, + + // any packet with an ID higher than PACKET_BROADCAST is rebroadcast by server + // so hacked clients can't create fake server packets and get the server to + // send them to everyone + // newer versions of the netcode also make this determination based on which + // channel the packet was broadcast on + + PACKET_BROADCAST, + PACKET_NEW_GAME, + PACKET_RTS, + PACKET_CLIENT_INFO, + PACKET_MESSAGE, + PACKET_USER_MAP, + + PACKET_MAP_VOTE, + PACKET_MAP_VOTE_INITIATE, + PACKET_MAP_VOTE_CANCEL, +}; + +enum netdisconnect_t +{ + DISC_BAD_PASSWORD = 1, + DISC_GAME_STARTED, + DISC_VERSION_MISMATCH, + DISC_INVALID, + DISC_SERVER_QUIT, + DISC_SERVER_FULL, + DISC_KICKED, + DISC_BANNED +}; + +enum netmode_t +{ + NET_CLIENT = 0, + NET_SERVER, + //NET_DEDICATED_CLIENT, // client on dedicated server + //NET_DEDICATED_SERVER +}; + +#define MAXSYNCBYTES 16 +#define SYNCFIFOSIZ 1024 + +// TENSW: on really bad network connections, the sync FIFO queue can overflow if it is the +// same size as the move fifo. +#if MOVEFIFOSIZ >= SYNCFIFOSIZ +#error "MOVEFIFOSIZ is greater than or equal to SYNCFIFOSIZ!" +#endif + +extern char syncstat[MAXSYNCBYTES]; +extern char g_szfirstSyncMsg[MAXSYNCBYTES][60]; + +extern int g_numSyncBytes; +extern int g_foundSyncError; +extern int syncvaltail, syncvaltottail; + +#pragma pack(push,1) +typedef struct +{ + int8_t header; + int8_t connection; + int8_t level_number; + int8_t volume_number; + int8_t player_skill; + int8_t monsters_off; + int8_t respawn_monsters; + int8_t respawn_items; + int8_t respawn_inventory; + int8_t marker; + int8_t ffire; + int8_t noexits; + int8_t coop; +} newgame_t; +#pragma pack(pop) + +extern newgame_t pendingnewgame; + +#ifndef NETCODE_DISABLE + +// Sync +void initsynccrc(void); +char Net_PlayerSync(void); +char Net_PlayerSync2(void); +char Net_ActorSync(void); +char Net_WeaponSync(void); +char Net_MapSync(void); +char Net_RandomSync(void); +void Net_GetSyncStat(void); +void Net_DisplaySyncMsg(void); +void Net_AddSyncInfoToPacket(int* j); +void Net_GetSyncInfoFromPacket(uint8_t* packbuf, int packbufleng, int* j, int otherconnectindex); + + +// Connect/Disconnect +void Net_Connect(const char *srvaddr); +void Net_Disconnect(void); +void Net_ReceiveDisconnect(ENetEvent *event); + +// Packet Handlers +#endif +void Net_ClearFIFO(void); +void Net_GetInput(void); +void Net_GetPackets(void); +#ifndef NETCODE_DISABLE +void Net_SendPacket(int32_t dest, uint8_t* pbuf, int32_t packbufleng); +void Net_HandleServerPackets(void); +void Net_HandleClientPackets(void); +void Net_ParseClientPacket(ENetEvent *event); +void Net_ParseServerPacket(ENetEvent *event); +void Net_ParsePacketCommon(uint8_t *pbuf, int32_t packbufleng, int32_t serverpacketp); + +void Net_SendAcknowledge(ENetPeer *client); +void Net_ReceiveAcknowledge(uint8_t *pbuf, int32_t packbufleng); + +void Net_SendChallenge(); +void Net_ReceiveChallenge(uint8_t *pbuf, int32_t packbufleng, ENetEvent *event); + +void Net_SendNewPlayer(int32_t newplayerindex); +void Net_ReceiveNewPlayer(uint8_t *pbuf, int32_t packbufleng); + +void Net_SendPlayerIndex(int32_t index, ENetPeer *peer); +void Net_ReceivePlayerIndex(uint8_t *pbuf, int32_t packbufleng); + +void Net_SendClientInfo(void); +void Net_ReceiveClientInfo(uint8_t *pbuf, int32_t packbufleng, int32_t fromserver); + +void Net_SendUserMapName(void); +void Net_ReceiveUserMapName(uint8_t *pbuf, int32_t packbufleng); + +//netmapstate_t *Net_GetRevision(uint8_t revision, uint8_t cancreate); + +//void Net_SendMapUpdate(void); +//void Net_ReceiveMapUpdate(ENetEvent *event); + +//void Net_FillMapDiff(uint32_t fromRevision, uint32_t toRevision); +//void Net_SaveMapState(netmapstate_t *save); +//void Net_RestoreMapState(); + +//void Net_CopyToNet(int32_t i, netactor_t *netactor); +//void Net_CopyFromNet(int32_t i, netactor_t *netactor); +//int32_t Net_ActorsAreDifferent(netactor_t *actor1, netactor_t *actor2); +//int32_t Net_IsRelevantSprite(int32_t i); +//int32_t Net_IsRelevantStat(int32_t stat); +//int32_t Net_InsertSprite(int32_t sect, int32_t stat); +//void Net_DeleteSprite(int32_t spritenum); + +//void Net_FillPlayerUpdate(playerupdate_t *update, int32_t player); +//void Net_ExtractPlayerUpdate(playerupdate_t *update, int32_t type); + +void Net_SendServerUpdates(void); +void Net_ReceiveServerUpdate(ENetEvent *event); + +void Net_SendClientUpdate(void); +void Net_ReceiveClientUpdate(ENetEvent *event); + +void Net_SendMessage(void); +void Net_ReceiveMessage(uint8_t *pbuf, int32_t packbufleng); + +void Net_StartNewGame(); +void Net_NotifyNewGame(); +void Net_SendNewGame(int32_t frommenu, ENetPeer *peer); +void Net_ReceiveNewGame(ENetEvent* event); + +void Net_FillNewGame(newgame_t *newgame, int32_t frommenu); +void Net_ExtractNewGame(newgame_t *newgame, int32_t menuonly); + +void Net_SendMapVoteInitiate(void); +void Net_ReceiveMapVoteInitiate(uint8_t *pbuf); + +void Net_SendMapVote(int32_t votefor); +void Net_ReceiveMapVote(uint8_t *pbuf); +void Net_CheckForEnoughVotes(); + +void Net_SendMapVoteCancel(int32_t failed); +void Net_ReceiveMapVoteCancel(uint8_t *pbuf); + +////////// + +void Net_ResetPrediction(void); +void Net_DoPrediction(void); +void Net_CorrectPrediction(void); +void Net_SpawnPlayer(int32_t player); +void Net_SyncPlayer(ENetEvent *event); +void Net_WaitForEverybody(void); +void Net_Update(void); +void Net_PostPacket(ENetPacket *packet); +void faketimerhandler(void); + +void Net_SendTaunt(int ridiculeNum); +void Net_SendRTS(int ridiculeNum); +void Net_InitNetwork(); +void Net_PrintLag(FString& output); + +#else + +/* NETCODE_ENABLE is not defined */ + +// Connect/Disconnect +#define Net_Connect(...) ((void)0) +#define Net_Disconnect(...) ((void)0) +#define Net_ReceiveDisconnect(...) ((void)0) + +// Packet Handlers +#define Net_HandleServerPackets(...) ((void)0) +#define Net_HandleClientPackets(...) ((void)0) +#define Net_ParseClientPacket(...) ((void)0) +#define Net_ParseServerPacket(...) ((void)0) +#define Net_ParsePacketCommon(...) ((void)0) + +#define Net_SendAcknowledge(...) ((void)0) +#define Net_ReceiveAcknowledge(...) ((void)0) + +#define Net_SendChallenge(...) ((void)0) +#define Net_ReceiveChallenge(...) ((void)0) + +#define Net_SendNewPlayer(...) ((void)0) +#define Net_ReceiveNewPlayer(...) ((void)0) + +#define Net_SendPlayerIndex(...) ((void)0) +#define Net_ReceivePlayerIndex(...) ((void)0) + +#define Net_SendClientInfo(...) ((void)0) +#define Net_ReceiveClientInfo(...) ((void)0) + +#define Net_SendUserMapName(...) ((void)0) +#define Net_ReceiveUserMapName(...) ((void)0) + +#define Net_SendClientSync(...) ((void)0) +#define Net_ReceiveClientSync(...) ((void)0) + +#define Net_SendMapUpdate(...) ((void)0) +#define Net_ReceiveMapUpdate(...) ((void)0) + +#define Net_FillPlayerUpdate(...) ((void)0) +#define Net_ExtractPlayerUpdate(...) ((void)0) + +#define Net_SendServerUpdates(...) ((void)0) +#define Net_ReceiveServerUpdate(...) ((void)0) + +#define Net_SendClientUpdate(...) ((void)0) +#define Net_ReceiveClientUpdate(...) ((void)0) + +#define Net_SendMessage(...) ((void)0) +#define Net_ReceiveMessage(...) ((void)0) + +#define Net_StartNewGame(...) ((void)0) +#define Net_SendNewGame(...) ((void)0) +#define Net_ReceiveNewGame(...) ((void)0) + +#define Net_FillNewGame(...) ((void)0) +#define Net_ExtractNewGame(...) ((void)0) + +#define Net_SendMapVoteInitiate(...) ((void)0) +#define Net_ReceiveMapVoteInitiate(...) ((void)0) + +#define Net_SendMapVote(...) ((void)0) +#define Net_ReceiveMapVote(...) ((void)0) +#define Net_CheckForEnoughVotes(...) ((void)0) + +#define Net_SendMapVoteCancel(...) ((void)0) +#define Net_ReceiveMapVoteCancel(...) ((void)0) + +////////// + +#define Net_ResetPrediction(...) ((void)0) +#define Net_DoPrediction(...) ((void)0) +#define Net_CorrectPrediction(...) ((void)0) +#define Net_RestoreMapState(...) ((void)0) +#define Net_SyncPlayer(...) ((void)0) +#define Net_WaitForServer(...) ((void)0) + +#define Net_ActorsAreDifferent(...) 0 +#define Net_IsRelevantSprite(...) 0 +#define Net_IsRelevantStat(...) 0 +#define Net_InsertSprite(...) 0 +#define Net_DeleteSprite(...) ((void)0) + +#define Net_NotifyNewGame(...) ((void)0) + +#define Net_SendTaunt(...) ((void)0) +#define Net_SendRTS(...) ((void)0) + +#define Net_WaitForEverybody(...) ((void)0) +#define initsynccrc(...) ((void)0) +#define Net_GetSyncStat(...) ((void)0) +#define Net_DisplaySyncMsg(...) ((void)0) +#define Net_ClearFIFO(...) ((void)0) +#define Net_GetInput(...) ((void)0) + +#endif + +END_DUKE_NS + +#endif // netplay_h_ diff --git a/source/duke/src/osdcmds.cpp b/source/duke/src/osdcmds.cpp new file mode 100644 index 000000000..483d81725 --- /dev/null +++ b/source/duke/src/osdcmds.cpp @@ -0,0 +1,495 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors +Copyright (C) 2020 Raze developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- +#include "ns.h" // Must come before everything else! + +#include "cheats.h" +#include "cmdline.h" +#include "demo.h" // g_firstDemoFile[] +#include "duke3d.h" +#include "menus.h" +#include "osdcmds.h" +#include "savegame.h" +#include "sbar.h" +#include "mapinfo.h" + +BEGIN_DUKE_NS + +struct osdcmd_cheatsinfo osdcmd_cheatsinfo_stat = { -1, 0, 0 }; + +static int osdcmd_levelwarp(CCmdFuncPtr parm) +{ + if (parm->numparms != 2) + return OSDCMD_SHOWHELP; + int e = atoi(parm->parms[0]); + int m = atoi(parm->parms[1]); + if (e == 0 || m == 0) + { + Printf(TEXTCOLOR_RED "Invalid level!: E%sL%s\n", parm->parms[0], parm->parms[1]); + return OSDCMD_OK; + } + + osdcmd_cheatsinfo_stat.cheatnum = -1; + ud.m_volume_number = e - 1; + m_level_number = m - 1; + + ud.m_monsters_off = ud.monsters_off = 0; + + ud.m_respawn_items = 0; + ud.m_respawn_inventory = 0; + + ud.multimode = 1; + + if (g_player[myconnectindex].ps->gm & MODE_GAME) + { + G_NewGame(ud.m_volume_number, m_level_number, ud.m_player_skill); + g_player[myconnectindex].ps->gm = MODE_RESTART; + } + else G_NewGame_EnterLevel(); + + return OSDCMD_OK; +} + +static int osdcmd_map(CCmdFuncPtr parm) +{ + if (parm->numparms != 1) + { + return OSDCMD_SHOWHELP; + } + FString mapname = parm->parms[0]; + + if (!fileSystem.Lookup(mapname, "MAP")) + { + Printf(TEXTCOLOR_RED "map: file \"%s\" not found.\n", mapname.GetChars()); + return OSDCMD_OK; + } + + // Check if the map is already defined. + for (int i = 0; i < 512; i++) + { + if (mapList[i].labelName.CompareNoCase(mapname) == 0) + { + ud.m_volume_number = i / MAXLEVELS; + m_level_number = i % MAXLEVELS; + goto foundone; + } + } + if (VOLUMEONE) + { + Printf(TEXTCOLOR_RED "Cannot use user maps in shareware.\n"); + return OSDCMD_OK; + } + // Treat as user map + boardfilename[0] = '/'; + boardfilename[1] = 0; + ud.m_volume_number = 0; + m_level_number = 7; + DefaultExtension(mapname, ".map"); + strcat(boardfilename, mapname); +foundone: + if (numplayers > 1) + { + return OSDCMD_OK; + } + + osdcmd_cheatsinfo_stat.cheatnum = -1; + ud.m_monsters_off = ud.monsters_off = 0; + + ud.m_respawn_items = 0; + ud.m_respawn_inventory = 0; + + ud.multimode = 1; + + if (g_player[myconnectindex].ps->gm & MODE_GAME) + { + G_NewGame(ud.m_volume_number, m_level_number, ud.m_player_skill); + g_player[myconnectindex].ps->gm = MODE_RESTART; + } + else G_NewGame_EnterLevel(); + + return OSDCMD_OK; +} + + +// demo [] +// +// To profile a demo ("timedemo mode"), can be given in the range 0-8, +// which will start to replay it as fast as possible, rendering frames +// for each gametic. +// +// Notes: +// * The demos should be recorded with demorec_diffs set to 0, so that the +// game state updates are actually computed. +// * Currently, the profiling can only be aborted on SDL 1.2 builds by +// pressing any key. +// * With greater than 1, interpolation should be calculated properly, +// though this has not been verified by looking at the frames. +// * When testing whether a change in the source has an effect on performance, +// the variance of the run times MUST be taken into account (that is, the +// replaying must be performed multiple times for the old and new versions, +// etc.) +static int osdcmd_demo(CCmdFuncPtr parm) +{ + if (numplayers > 1) + { + Printf("Command not allowed in multiplayer\n"); + return OSDCMD_OK; + } + + if (g_player[myconnectindex].ps->gm & MODE_GAME) + { + Printf("demo: Must not be in a game.\n"); + return OSDCMD_OK; + } + + if (parm->numparms != 1 && parm->numparms != 2) + return OSDCMD_SHOWHELP; + + { + int32_t prof = parm->numparms==2 ? Batoi(parm->parms[1]) : -1; + + Demo_SetFirst(parm->parms[0]); + Demo_PlayFirst(clamp(prof, -1, 8)+1, 0); + } + + return OSDCMD_OK; +} + +static int osdcmd_activatecheat(CCmdFuncPtr parm) +{ + if (parm->numparms != 1) + return OSDCMD_SHOWHELP; + + if (numplayers == 1 && g_player[myconnectindex].ps->gm & MODE_GAME) + osdcmd_cheatsinfo_stat.cheatnum = Batoi(parm->parms[0]); + else + Printf("activatecheat: Not in a single-player game.\n"); + + return OSDCMD_OK; +} + +static int osdcmd_god(CCmdFuncPtr UNUSED(parm)) +{ + UNREFERENCED_CONST_PARAMETER(parm); + if (numplayers == 1 && g_player[myconnectindex].ps->gm & MODE_GAME) + osdcmd_cheatsinfo_stat.cheatnum = CHEAT_CORNHOLIO; + else + Printf("god: Not in a single-player game.\n"); + + return OSDCMD_OK; +} + +static int osdcmd_noclip(CCmdFuncPtr UNUSED(parm)) +{ + UNREFERENCED_CONST_PARAMETER(parm); + + if (numplayers == 1 && g_player[myconnectindex].ps->gm & MODE_GAME) + { + osdcmd_cheatsinfo_stat.cheatnum = CHEAT_CLIP; + } + else + { + Printf("noclip: Not in a single-player game.\n"); + } + + return OSDCMD_OK; +} + +int osdcmd_restartmap(CCmdFuncPtr UNUSED(parm)) +{ + UNREFERENCED_CONST_PARAMETER(parm); + + if (g_player[myconnectindex].ps->gm & MODE_GAME && ud.multimode == 1) + g_player[myconnectindex].ps->gm = MODE_RESTART; + + return OSDCMD_OK; +} + +static int osdcmd_spawn(CCmdFuncPtr parm) +{ + int32_t picnum = 0; + uint16_t cstat=0; + char pal=0; + int16_t ang=0; + int16_t set=0, idx; + vec3_t vect; + + if (numplayers > 1 || !(g_player[myconnectindex].ps->gm & MODE_GAME)) + { + Printf("spawn: Can't spawn sprites in multiplayer games or demos\n"); + return OSDCMD_OK; + } + + switch (parm->numparms) + { + case 7: // x,y,z + vect.x = Batol(parm->parms[4]); + vect.y = Batol(parm->parms[5]); + vect.z = Batol(parm->parms[6]); + set |= 8; + fallthrough__; + case 4: // ang + ang = Batol(parm->parms[3]) & 2047; + set |= 4; + fallthrough__; + case 3: // cstat + cstat = (uint16_t)Batol(parm->parms[2]); + set |= 2; + fallthrough__; + case 2: // pal + pal = (uint8_t)Batol(parm->parms[1]); + set |= 1; + fallthrough__; + case 1: // tile number + if (isdigit(parm->parms[0][0])) + { + picnum = Batol(parm->parms[0]); + } + else + { + int32_t i; + int32_t j; + + for (j=0; j<2; j++) + { + for (i=0; iparms[0])) || + (j == 1 && !Bstrcasecmp(label+(i<<6), parm->parms[0]))) + { + picnum = labelcode[i]; + break; + } + } + + if (i < g_labelCnt) + break; + } + if (i==g_labelCnt) + { + Printf("spawn: Invalid tile label given\n"); + return OSDCMD_OK; + } + } + + if ((uint32_t)picnum >= MAXUSERTILES) + { + Printf("spawn: Invalid tile number\n"); + return OSDCMD_OK; + } + break; + + default: + return OSDCMD_SHOWHELP; + } + + idx = A_Spawn(g_player[myconnectindex].ps->i, picnum); + if (set & 1) sprite[idx].pal = (uint8_t)pal; + if (set & 2) sprite[idx].cstat = (int16_t)cstat; + if (set & 4) sprite[idx].ang = ang; + if (set & 8) + { + if (setsprite(idx, &vect) < 0) + { + Printf("spawn: Sprite can't be spawned into null space\n"); + A_DeleteSprite(idx); + } + } + + return OSDCMD_OK; +} + + +static int osdcmd_give(CCmdFuncPtr parm) +{ + int32_t i; + + if (numplayers != 1 || (g_player[myconnectindex].ps->gm & MODE_GAME) == 0 || + g_player[myconnectindex].ps->dead_flag != 0) + { + Printf("give: Cannot give while dead or not in a single-player game.\n"); + return OSDCMD_OK; + } + + if (parm->numparms != 1) return OSDCMD_SHOWHELP; + + if (!Bstrcasecmp(parm->parms[0], "all")) + { + osdcmd_cheatsinfo_stat.cheatnum = CHEAT_STUFF; + return OSDCMD_OK; + } + else if (!Bstrcasecmp(parm->parms[0], "health")) + { + sprite[g_player[myconnectindex].ps->i].extra = g_player[myconnectindex].ps->max_player_health<<1; + return OSDCMD_OK; + } + else if (!Bstrcasecmp(parm->parms[0], "weapons")) + { + osdcmd_cheatsinfo_stat.cheatnum = CHEAT_WEAPONS; + return OSDCMD_OK; + } + else if (!Bstrcasecmp(parm->parms[0], "ammo")) + { + for (i=MAX_WEAPONS-(VOLUMEONE?6:1)-1; i>=PISTOL_WEAPON; i--) + P_AddAmmo(g_player[myconnectindex].ps,i,g_player[myconnectindex].ps->max_ammo_amount[i]); + return OSDCMD_OK; + } + else if (!Bstrcasecmp(parm->parms[0], "armor")) + { + g_player[myconnectindex].ps->inv_amount[GET_SHIELD] = 100; + return OSDCMD_OK; + } + else if (!Bstrcasecmp(parm->parms[0], "keys")) + { + osdcmd_cheatsinfo_stat.cheatnum = CHEAT_KEYS; + return OSDCMD_OK; + } + else if (!Bstrcasecmp(parm->parms[0], "inventory")) + { + osdcmd_cheatsinfo_stat.cheatnum = CHEAT_INVENTORY; + return OSDCMD_OK; + } + return OSDCMD_SHOWHELP; +} + +#if !defined NETCODE_DISABLE +static int osdcmd_disconnect(CCmdFuncPtr UNUSED(parm)) +{ + UNREFERENCED_CONST_PARAMETER(parm); + // NUKE-TODO: + if (g_player[myconnectindex].ps->gm&MODE_MENU) + g_netDisconnect = 1; + return OSDCMD_OK; +} + +static int osdcmd_connect(CCmdFuncPtr parm) +{ + if (parm->numparms != 1) + return OSDCMD_SHOWHELP; + + Net_Connect(parm->parms[0]); + G_BackToMenu(); + return OSDCMD_OK; +} + +static int osdcmd_password(CCmdFuncPtr parm) +{ + if (parm->numparms < 1) + { + Bmemset(g_netPassword, 0, sizeof(g_netPassword)); + return OSDCMD_OK; + } + Bstrncpy(g_netPassword, (parm->raw) + 9, sizeof(g_netPassword)-1); + + return OSDCMD_OK; +} + +int osdcmd_listplayers(CCmdFuncPtr parm); +#endif + +static int osdcmd_printtimes(CCmdFuncPtr UNUSED(parm)) +{ + UNREFERENCED_CONST_PARAMETER(parm); + + char buf[32]; + int32_t maxlen = 0; + int32_t haveac=0; + + for (int i=0; i: loads the given map", osdcmd_map); + if (!VOLUMEONE) + { + C_RegisterFunction("demo","demo : starts the given demo", osdcmd_demo); + } + C_RegisterFunction("levelwarp","levelwarp : warp to episode 'e' and map 'm'", osdcmd_levelwarp); + +#if !defined NETCODE_DISABLE + C_RegisterFunction("connect","connect: connects to a multiplayer game", osdcmd_connect); + C_RegisterFunction("disconnect","disconnect: disconnects from the local multiplayer game", osdcmd_disconnect); +#endif + + C_RegisterFunction("give","give : gives requested item", osdcmd_give); + C_RegisterFunction("god","god: toggles god mode", osdcmd_god); + C_RegisterFunction("activatecheat","activatecheat : activates a cheat code", osdcmd_activatecheat); + +#ifdef DEBUGGINGAIDS + C_RegisterFunction("inittimer","debug", osdcmd_inittimer); +#endif +#if !defined NETCODE_DISABLE +#if 0 + C_RegisterFunction("kick","kick : kicks a multiplayer client. See listplayers.", osdcmd_kick); + C_RegisterFunction("kickban","kickban : kicks a multiplayer client and prevents them from reconnecting. See listplayers.", osdcmd_kickban); +#endif + + C_RegisterFunction("listplayers","listplayers: lists currently connected multiplayer clients", osdcmd_listplayers); +#endif + C_RegisterFunction("noclip","noclip: toggles clipping mode", osdcmd_noclip); + +#if !defined NETCODE_DISABLE + C_RegisterFunction("password","password: sets multiplayer game password", osdcmd_password); +#endif + + C_RegisterFunction("printtimes", "printtimes: prints VM timing statistics", osdcmd_printtimes); + + C_RegisterFunction("restartmap", "restartmap: restarts the current map", osdcmd_restartmap); + + C_RegisterFunction("spawn","spawn [palnum] [cstat] [ang] [x y z]: spawns a sprite with the given properties",osdcmd_spawn); + + return 0; +} + +END_DUKE_NS diff --git a/source/duke/src/osdcmds.h b/source/duke/src/osdcmds.h new file mode 100644 index 000000000..1da5de9c6 --- /dev/null +++ b/source/duke/src/osdcmds.h @@ -0,0 +1,48 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef osdcmds_h_ +#define osdcmds_h_ + +BEGIN_DUKE_NS + +struct osdcmd_cheatsinfo { + int32_t cheatnum; // -1 = none, else = see DoCheats() + int32_t volume,level; +}; + +extern struct osdcmd_cheatsinfo osdcmd_cheatsinfo_stat; + +int32_t registerosdcommands(void); + +// key bindings stuff +typedef struct { + const char *name; + int32_t id; +} keydef_t; + +extern const char *const ConsoleButtons[]; + +END_DUKE_NS + +#endif // osdcmds_h_ + diff --git a/source/duke/src/player.cpp b/source/duke/src/player.cpp new file mode 100644 index 000000000..5694bcabc --- /dev/null +++ b/source/duke/src/player.cpp @@ -0,0 +1,9592 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- +#include "ns.h" // Must come before everything else! + +#include "duke3d.h" +#include "gameexec.h" +#include "demo.h" +#include "d_event.h" + +BEGIN_DUKE_NS + + +int32_t PHEIGHT = PHEIGHT_DUKE; + +int32_t lastvisinc; +hudweapon_t hudweap; + +#ifdef SPLITSCREEN_MOD_HACKS +static int32_t g_snum; +#endif + +extern int32_t g_levelTextTime, ticrandomseed; + +int32_t g_numObituaries = 0; +int32_t g_numSelfObituaries = 0; + + +int const icon_to_inv[ICON_MAX] = { GET_FIRSTAID, GET_FIRSTAID, GET_STEROIDS, GET_HOLODUKE, + GET_JETPACK, GET_HEATS, GET_SCUBA, GET_BOOTS }; + +int const inv_to_icon[GET_MAX] = { ICON_STEROIDS, ICON_NONE, ICON_SCUBA, ICON_HOLODUKE, ICON_JETPACK, ICON_NONE, + ICON_NONE, ICON_HEATS, ICON_NONE, ICON_FIRSTAID, ICON_BOOTS }; + +void P_AddKills(DukePlayer_t * const pPlayer, uint16_t kills) +{ + pPlayer->actors_killed += kills; +} + +void P_UpdateScreenPal(DukePlayer_t * const pPlayer) +{ + int inWater = 0; + int const playerSectnum = pPlayer->cursectnum; + + if (pPlayer->drug_mode) + pPlayer->palette = DRUGPAL; + else if (pPlayer->heat_on) + pPlayer->palette = SLIMEPAL; + else if (playerSectnum < 0) + pPlayer->palette = BASEPAL; + else if (sector[playerSectnum].ceilingpicnum >= FLOORSLIME && sector[playerSectnum].ceilingpicnum <= FLOORSLIME + 2) + { + pPlayer->palette = SLIMEPAL; + inWater = 1; + } + else + { + pPlayer->palette = (sector[pPlayer->cursectnum].lotag == ST_2_UNDERWATER) ? WATERPAL : BASEPAL; + inWater = 1; + } + + g_restorePalette = 1+inWater; +} + +static void P_IncurDamage(DukePlayer_t * const pPlayer) +{ + sprite[pPlayer->i].extra -= pPlayer->extra_extra8>>8; + + int playerDamage = sprite[pPlayer->i].extra - pPlayer->last_extra; + + if (playerDamage >= 0) + return; + + pPlayer->extra_extra8 = 0; + + if ((!RR && pPlayer->inv_amount[GET_SHIELD] > 0) || (RR && pPlayer->inv_amount[GET_STEROIDS] > 0 && pPlayer->inv_amount[GET_STEROIDS] < 400)) + { + int const shieldDamage = playerDamage * (20 + (krand2()%30)) / 100; + + playerDamage -= shieldDamage; + if (!RR) + { + pPlayer->inv_amount[GET_SHIELD] += shieldDamage; + + if (pPlayer->inv_amount[GET_SHIELD] < 0) + { + playerDamage += pPlayer->inv_amount[GET_SHIELD]; + pPlayer->inv_amount[GET_SHIELD] = 0; + } + } + } + + if (RR) + { + int guts = 0; + if (pPlayer->drink_amt > 31 && pPlayer->drink_amt < 65) + guts++; + if (pPlayer->eat_amt > 31 && pPlayer->eat_amt < 65) + guts++; + + switch (guts) + { + case 1: + playerDamage = (int)(playerDamage*0.75); + break; + case 2: + playerDamage = (int)(playerDamage*0.25); + break; + } + } + + sprite[pPlayer->i].extra = pPlayer->last_extra + playerDamage; +} + +void P_QuickKill(DukePlayer_t * const pPlayer) +{ + P_PalFrom(pPlayer, 48, 48,48,48); + + sprite[pPlayer->i].extra = 0; + sprite[pPlayer->i].cstat |= 32768; + + if (ud.god == 0) + A_DoGuts(pPlayer->i,JIBS6,8); +} + +static void Proj_DoWaterTracers(vec3_t startPos, vec3_t const *endPos, int n, int16_t sectNum) +{ + if ((klabs(startPos.x - endPos->x) + klabs(startPos.y - endPos->y)) < 3084) + return; + + vec3_t const v_inc = { tabledivide32_noinline(endPos->x - startPos.x, n + 1), tabledivide32_noinline(endPos->y - startPos.y, n + 1), + tabledivide32_noinline(endPos->z - startPos.z, n + 1) }; + + for (bssize_t i=n; i>0; i--) + { + startPos.x += v_inc.x; + startPos.y += v_inc.y; + startPos.z += v_inc.z; + + updatesector(startPos.x, startPos.y, §Num); + + if (sectNum < 0) + break; + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(); + A_InsertSprite(sectNum, startPos.x, startPos.y, startPos.z, WATERBUBBLE, -32, 4 + (r3 & 3), 4 + (r2 & 3), r1 & 2047, 0, 0, + g_player[0].ps->i, 5); + } +} + +int32_t A_GetHitscanRange(int spriteNum) +{ + int const zOffset = (PN(spriteNum) == APLAYER) ? (40<<8) : 0; + hitdata_t hitData; + + SZ(spriteNum) -= zOffset; + hitscan((const vec3_t *)&sprite[spriteNum], SECT(spriteNum), sintable[(SA(spriteNum) + 512) & 2047], + sintable[SA(spriteNum) & 2047], 0, &hitData, CLIPMASK1); + SZ(spriteNum) += zOffset; + + return (FindDistance2D(hitData.pos.x - SX(spriteNum), hitData.pos.y - SY(spriteNum))); +} + +static int A_FindTargetSprite(const spritetype *pSprite, int projAng, int projecTile) +{ + static int const aimstats[] = { + STAT_PLAYER, STAT_DUMMYPLAYER, STAT_ACTOR, STAT_ZOMBIEACTOR + }; + + int const playerNum = pSprite->picnum == APLAYER ? P_GetP(pSprite) : -1; + + if (playerNum != -1) + { + if (!g_player[playerNum].ps->auto_aim && (!RRRA || projecTile != RPG2)) + return -1; + + if (g_player[playerNum].ps->auto_aim == 2) + { + switch (DYNAMICTILEMAP(projecTile)) + { + case TONGUE__STATIC: + case FREEZEBLAST__STATIC: + case SHRINKSPARK__STATIC: + case SHRINKER__STATIC: + case RPG__STATIC: + case FIRELASER__STATIC: + case SPIT__STATIC: + case COOLEXPLOSION1__STATIC: + return -1; + default: + break; + } + } + } + + int const spriteAng = pSprite->ang; + + int isShrinker = (!RR && pSprite->picnum == APLAYER && g_player[playerNum].ps->curr_weapon == SHRINKER_WEAPON); + int isFreezer = (!RR && pSprite->picnum == APLAYER && g_player[playerNum].ps->curr_weapon == FREEZE_WEAPON); + + if (WW2GI) + { + isShrinker = (pSprite->picnum == APLAYER && PWEAPON(playerNum, g_player[playerNum].ps->curr_weapon, WorksLike) == SHRINKER_WEAPON); + isFreezer = (pSprite->picnum == APLAYER && PWEAPON(playerNum, g_player[playerNum].ps->curr_weapon, WorksLike) == FREEZE_WEAPON); + } + + vec2_t const d1 = { sintable[(spriteAng + 512 - projAng) & 2047], sintable[(spriteAng - projAng) & 2047] }; + vec2_t const d2 = { sintable[(spriteAng + 512 + projAng) & 2047], sintable[(spriteAng + projAng) & 2047] }; + vec2_t const d3 = { sintable[(spriteAng + 512) & 2047], sintable[spriteAng & 2047] }; + + int lastDist = INT32_MAX; + int bestSprite = -1; + + for (bssize_t k=0; k<4; k++) + { + if (bestSprite >= 0) + break; + + for (bssize_t spriteNum=headspritestat[aimstats[k]]; spriteNum >= 0; spriteNum=nextspritestat[spriteNum]) + { + if ((sprite[spriteNum].xrepeat > 0 && sprite[spriteNum].extra >= 0 && + (sprite[spriteNum].cstat & (257 + 32768)) == 257) && + (A_CheckEnemySprite(&sprite[spriteNum]) || k < 2)) + { + if (A_CheckEnemySprite(&sprite[spriteNum]) || PN(spriteNum) == APLAYER) + { + if (PN(spriteNum) == APLAYER && pSprite->picnum == APLAYER && pSprite != &sprite[spriteNum] && + (GTFLAGS(GAMETYPE_PLAYERSFRIENDLY) || + (GTFLAGS(GAMETYPE_TDM) && g_player[P_Get(spriteNum)].ps->team == g_player[playerNum].ps->team))) + continue; + + if ((isShrinker && sprite[spriteNum].xrepeat < 30 + && (PN(spriteNum) == SHARK || !(!RR && PN(spriteNum) >= GREENSLIME && PN(spriteNum) <= GREENSLIME + 7))) + || (isFreezer && sprite[spriteNum].pal == 1)) + continue; + } + + vec2_t const vd = { (SX(spriteNum) - pSprite->x), (SY(spriteNum) - pSprite->y) }; + + if ((d1.y * vd.x <= d1.x * vd.y) && (d2.y * vd.x >= d2.x * vd.y)) + { + int const spriteDist = mulscale14(d3.x, vd.x) + mulscale14(d3.y, vd.y); + + if (spriteDist > 512 && spriteDist < lastDist) + { + int onScreen = 1; + + if (pSprite->picnum == APLAYER) + { + const DukePlayer_t *const ps = g_player[P_GetP(pSprite)].ps; + onScreen = (klabs(scale(SZ(spriteNum)-pSprite->z,10,spriteDist)-fix16_to_int(ps->q16horiz+ps->q16horizoff-F16(100))) < 100); + } + + int const zOffset = (!RR && (PN(spriteNum) == ORGANTIC || PN(spriteNum) == ROTATEGUN)) ? 0 : ZOFFSET5; + int const canSee = cansee(SX(spriteNum), SY(spriteNum), SZ(spriteNum) - zOffset, SECT(spriteNum), + pSprite->x, pSprite->y, pSprite->z - ZOFFSET5, pSprite->sectnum); + + if (onScreen && canSee) + { + lastDist = spriteDist; + bestSprite = spriteNum; + } + } + } + } + } + } + + return bestSprite; +} + +static int CheckShootSwitchTile(int tileNum) +{ + return tileNum == DIPSWITCH || tileNum == DIPSWITCH + 1 || tileNum == DIPSWITCH2 || tileNum == DIPSWITCH2 + 1 || + tileNum == DIPSWITCH3 || tileNum == DIPSWITCH3 + 1 || tileNum == HANDSWITCH || tileNum == HANDSWITCH + 1 || + (RRRA && tileNum == RRTILE8660); +} + +static int32_t safeldist(int32_t spriteNum, const void *pSprite) +{ + int32_t distance = ldist(&sprite[spriteNum], pSprite); + return distance ? distance : 1; +} + +// flags: +// 1: do sprite center adjustment (cen-=(8<<8)) for GREENSLIME or ROTATEGUN +// 2: do auto getangle only if not RECON (if clear, do unconditionally) +static int GetAutoAimAng(int spriteNum, int playerNum, int projecTile, int zAdjust, int aimFlags, + const vec3_t *startPos, int projVel, int32_t *pZvel, int *pAng) +{ + int returnSprite = -1; + + Bassert((unsigned)playerNum < MAXPLAYERS); + + Gv_SetVar(g_aimAngleVarID, (g_player[playerNum].ps->auto_aim == 3 && (!RRRA || projecTile != RPG2)) ? AUTO_AIM_ANGLE<<1 : AUTO_AIM_ANGLE, spriteNum, playerNum); + + VM_OnEvent(EVENT_GETAUTOAIMANGLE, spriteNum, playerNum); + + int aimang = Gv_GetVar(g_aimAngleVarID, spriteNum, playerNum); + if (aimang > 0) + returnSprite = A_FindTargetSprite(&sprite[spriteNum], aimang, projecTile); + + if (returnSprite >= 0) + { + const uspritetype *const pSprite = (uspritetype *)&sprite[returnSprite]; + int zCenter = 2 * (pSprite->xrepeat * tilesiz[pSprite->picnum].y) + zAdjust; + + if ((aimFlags&1) && !RR && + ((pSprite->picnum >= GREENSLIME && pSprite->picnum <= GREENSLIME + 7) || pSprite->picnum == ROTATEGUN)) + zCenter -= ZOFFSET3; + + int spriteDist = safeldist(g_player[playerNum].ps->i, &sprite[returnSprite]); + *pZvel = tabledivide32_noinline((pSprite->z - startPos->z - zCenter) * projVel, spriteDist); + + if (!(aimFlags&2) || sprite[returnSprite].picnum != RECON) + *pAng = getangle(pSprite->x-startPos->x, pSprite->y-startPos->y); + } + + return returnSprite; +} + +static void Proj_MaybeAddSpread(int doSpread, int32_t *zvel, int *shootAng, int zRange, int angRange) +{ + if (doSpread) + { + // Ranges <= 1 mean no spread at all. A range of 1 calls krand2() though. + if (zRange > 0) + *zvel += (zRange >> 1) - krand2() % zRange; + + if (angRange > 0) + *shootAng += (angRange >> 1) - krand2() % angRange; + } +} + +static void Proj_MaybeAddSpreadSwapped(int doSpread, int32_t *zvel, int *shootAng, int zRange, int angRange) +{ + if (doSpread) + { + // Ranges <= 1 mean no spread at all. A range of 1 calls krand2() though. + if (angRange > 0) + *shootAng += (angRange >> 1) - krand2() % angRange; + + if (zRange > 0) + *zvel += (zRange >> 1) - krand2() % zRange; + } +} + +// Prepare hitscan weapon fired from player p. +static void P_PreFireHitscan(int spriteNum, int playerNum, int projecTile, vec3_t *srcVect, int32_t *zvel, int *shootAng, + int accurateAim, int doSpread) +{ + int angRange = (RR && projecTile == SHOTGUN) ? 128 : 32; + int zRange = 256; + int aimSprite = GetAutoAimAng(spriteNum, playerNum, projecTile, 5 << 8, 0 + 1, srcVect, 256, zvel, shootAng); + + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + Gv_SetVar(g_angRangeVarID, angRange, spriteNum, playerNum); + Gv_SetVar(g_zRangeVarID, zRange, spriteNum, playerNum); + + VM_OnEvent(EVENT_GETSHOTRANGE, spriteNum, playerNum); + + angRange = Gv_GetVar(g_angRangeVarID, spriteNum, playerNum); + zRange = Gv_GetVar(g_zRangeVarID, spriteNum, playerNum); + + if (accurateAim) + { + if (!pPlayer->auto_aim) + { + hitdata_t hitData; + + *zvel = fix16_to_int(F16(100)-pPlayer->q16horiz-pPlayer->q16horizoff)<<5; + + hitscan(srcVect, sprite[spriteNum].sectnum, sintable[(*shootAng + 512) & 2047], + sintable[*shootAng & 2047], *zvel << 6, &hitData, CLIPMASK1); + + if (hitData.sprite != -1) + { + int const statNumMap = ((1 << STAT_ACTOR) | (1 << STAT_ZOMBIEACTOR) | (1 << STAT_PLAYER) | (1 << STAT_DUMMYPLAYER)); + int const statNum = sprite[hitData.sprite].statnum; + + if ((unsigned)statNum <= 30 && (statNumMap & (1 << statNum))) + aimSprite = hitData.sprite; + } + } + + if (aimSprite == -1) + goto notarget; + } + else + { + if (aimSprite == -1) // no target + { +notarget: + *zvel = fix16_to_int(F16(100)-pPlayer->q16horiz-pPlayer->q16horizoff)<<5; + } + + Proj_MaybeAddSpreadSwapped(doSpread, zvel, shootAng, zRange, angRange); + } + + srcVect->z -= (2<<8); +} + +// Hitscan weapon fired from actor (sprite s); +static void A_PreFireHitscan(const spritetype *pSprite, vec3_t * const srcVect, int32_t * const zvel, int * const shootAng, int const doSpread) +{ + int const playerNum = A_FindPlayer(pSprite, NULL); + const DukePlayer_t *pPlayer = g_player[playerNum].ps; + int const playerDist = safeldist(pPlayer->i, pSprite); + + srcVect->z -= ZOFFSET6; + + *zvel = tabledivide32_noinline((pPlayer->pos.z - srcVect->z) << 8, playerDist); + + if (pSprite->picnum == BOSS1) + *shootAng = getangle(pPlayer->pos.x - srcVect->x, pPlayer->pos.y - srcVect->y); + + Proj_MaybeAddSpread(doSpread, zvel, shootAng, 256, 128 >> (uint8_t)(pSprite->picnum != BOSS1)); +} + +static int Proj_DoHitscan(int spriteNum, int32_t const cstatmask, const vec3_t * const srcVect, int zvel, int const shootAng, hitdata_t * const hitData) +{ + spritetype *const pSprite = &sprite[spriteNum]; + + pSprite->cstat &= ~cstatmask; + hitscan(srcVect, pSprite->sectnum, sintable[(shootAng + 512) & 2047], sintable[shootAng & 2047], zvel << 6, hitData, CLIPMASK1); + + if (RRRA) + { + if (((sector[hitData->sect].lotag == 160 && zvel > 0) || (sector[hitData->sect].lotag == 161 && zvel < 0)) + && hitData->sprite == -1 && hitData->wall == -1) + { + for (int spriteNum = 0; spriteNum < MAXSPRITES; spriteNum++) + { + if (sprite[spriteNum].sectnum == hitData->sect && sprite[spriteNum].picnum == SECTOREFFECTOR + && sprite[spriteNum].lotag == SE_7_TELEPORT) + { + vec3_t const newVect = { + hitData->pos.x + (sprite[OW(spriteNum)].x - sprite[spriteNum].x), + hitData->pos.y + (sprite[OW(spriteNum)].y - sprite[spriteNum].y), + sector[hitData->sect].lotag == 161 ? sector[sprite[OW(spriteNum)].sectnum].floorz + : sector[sprite[OW(spriteNum)].sectnum].ceilingz + }; + + hitscan(&newVect, sprite[OW(spriteNum)].sectnum, sintable[(shootAng + 512) & 2047], sintable[shootAng & 2047], zvel << 6, + hitData, CLIPMASK1); + break; + } + } + } + } + pSprite->cstat |= cstatmask; + + return (hitData->sect < 0); +} + +static int SectorContainsSE13(int const sectNum) +{ + if (sectNum >= 0) + { + for (bssize_t SPRITES_OF_SECT(sectNum, i)) + { + if (sprite[i].statnum == STAT_EFFECTOR && sprite[i].lotag == SE_13_EXPLOSIVE) + return 1; + } + } + return 0; +} + +// Maybe handle bit 2 (swap wall bottoms). +// (in that case walltype *hitwal may be stale) +static inline void HandleHitWall(hitdata_t *hitData) +{ + uwalltype const * const hitWall = (uwalltype *)&wall[hitData->wall]; + + if ((hitWall->cstat & 2) && redwallp(hitWall) && (hitData->pos.z >= sector[hitWall->nextsector].floorz)) + hitData->wall = hitWall->nextwall; +} + +// Common "spawn blood?" predicate. +// minzdiff: minimal "step" height for blood to be spawned +static int Proj_CheckBlood(vec3_t const *const srcVect, hitdata_t const *const hitData, int const bloodRange, int const minZdiff) +{ + if (hitData->wall < 0 || hitData->sect < 0) + return 0; + + uwalltype const *const hitWall = (uwalltype *)&wall[hitData->wall]; + + if ((FindDistance2D(srcVect->x - hitData->pos.x, srcVect->y - hitData->pos.y) < bloodRange) + && (hitWall->overpicnum != BIGFORCE && (hitWall->cstat & 16) == 0) + && (sector[hitData->sect].lotag == 0) + && (hitWall->nextsector < 0 || (sector[hitWall->nextsector].lotag == 0 && sector[hitData->sect].lotag == 0 + && sector[hitData->sect].floorz - sector[hitWall->nextsector].floorz > minZdiff))) + return 1; + + return 0; +} + +int A_Shoot(int const spriteNum, int const projecTile) +{ + Bassert(projecTile >= 0); + + spritetype *const pSprite = &sprite[spriteNum]; + int const spriteSectnum = pSprite->sectnum; + int const playerNum = (pSprite->picnum == APLAYER) ? P_GetP(pSprite) : -1; + DukePlayer_t *const pPlayer = playerNum >= 0 ? g_player[playerNum].ps : NULL; + int32_t Zvel = 0; + + hitdata_t hitData; + int shootAng; + vec3_t startPos; + int vel; + + if (pPlayer != NULL) + { + startPos = *(vec3_t *)pPlayer; + startPos.z += pPlayer->pyoff + ZOFFSET6; + shootAng = fix16_to_int(pPlayer->q16ang); + if (!RRRA) + pPlayer->crack_time = 777; + } + else + { + shootAng = pSprite->ang; + startPos = *(vec3_t *)pSprite; + startPos.z -= (((pSprite->yrepeat * tilesiz[pSprite->picnum].y)<<1) - ZOFFSET6); + + if (RR || pSprite->picnum != ROTATEGUN) + { + startPos.z -= (7<<8); + + if (A_CheckEnemySprite(pSprite) && (RR || PN(spriteNum) != COMMANDER)) + { + startPos.x += (sintable[(shootAng+1024+96)&2047]>>7); + startPos.y += (sintable[(shootAng+512+96)&2047]>>7); + } + } + +#ifdef POLYMER + switch (DYNAMICTILEMAP(projecTile)) + { + case FIRELASER__STATIC: + case SHOTGUN__STATIC: + case SHOTSPARK1__STATIC: + case CHAINGUN__STATIC: + case RPG__STATIC: + case MORTER__STATIC: + { + vec2_t const v = { ((sintable[(pSprite->ang + 512) & 2047]) >> 7), + ((sintable[(pSprite->ang) & 2047]) >> 7) }; + + pSprite->x += v.x; + pSprite->y += v.y; + G_AddGameLight(0, spriteNum, PHEIGHT, 8192, 255 + (95 << 8), PR_LIGHT_PRIO_MAX_GAME); + actor[spriteNum].lightcount = 2; + pSprite->x -= v.x; + pSprite->y -= v.y; + } + + break; + } +#endif // POLYMER + } + + switch (DYNAMICTILEMAP(projecTile)) + { + case BLOODSPLAT1__STATIC: + case BLOODSPLAT2__STATIC: + case BLOODSPLAT3__STATIC: + case BLOODSPLAT4__STATIC: + shootAng += 64 - (krand2() & 127); + if (playerNum < 0) + shootAng += 1024; + Zvel = 1024 - (krand2() & 2047); + fallthrough__; + case KNEE__STATIC: + case SLINGBLADE__STATICRR: + if (RR && !RRRA && projecTile == SLINGBLADE) + break; +growspark_rr: + if (projecTile == KNEE || (RR && projecTile == GROWSPARK) || (RRRA && projecTile == SLINGBLADE)) + { + if (playerNum >= 0) + { + Zvel = fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) << 5; + startPos.z += (6 << 8); + shootAng += 15; + } + else + { + int32_t playerDist; + int const playerSprite = g_player[A_FindPlayer(pSprite, &playerDist)].ps->i; + Zvel = tabledivide32_noinline((sprite[playerSprite].z - startPos.z) << 8, playerDist + 1); + shootAng = getangle(sprite[playerSprite].x - startPos.x, sprite[playerSprite].y - startPos.y); + } + } + + Proj_DoHitscan(spriteNum, 0, &startPos, Zvel, shootAng, &hitData); + + if (projecTile >= BLOODSPLAT1 && projecTile <= BLOODSPLAT4) + { + if (Proj_CheckBlood(&startPos, &hitData, 1024, 16 << 8)) + { + const uwalltype *const hitwal = (uwalltype *)&wall[hitData.wall]; + + if (SectorContainsSE13(hitwal->nextsector)) + return -1; + + if (hitwal->nextwall >= 0 && wall[hitwal->nextwall].hitag != 0) + return -1; + + if (hitwal->hitag == 0) + { + int const spawnedSprite = A_Spawn(spriteNum, projecTile); + sprite[spawnedSprite].xvel = -12; + sprite[spawnedSprite].ang + = (getangle(hitwal->x - wall[hitwal->point2].x, hitwal->y - wall[hitwal->point2].y) + 512) & 2047; + *(vec3_t *)&sprite[spawnedSprite] = hitData.pos; + sprite[spawnedSprite].cstat |= (krand2() & 4); + A_SetSprite(spawnedSprite, CLIPMASK0); + setsprite(spawnedSprite, (vec3_t *)&sprite[spawnedSprite]); + if (PN(spriteNum) == OOZFILTER || (!RR && PN(spriteNum) == NEWBEAST)) + sprite[spawnedSprite].pal = 6; + } + } + + return -1; + } + + if (hitData.sect < 0) + break; + + if (klabs(startPos.x - hitData.pos.x) + klabs(startPos.y - hitData.pos.y) < 1024) + { + if (hitData.wall >= 0 || hitData.sprite >= 0) + { + int kneeSprite = A_InsertSprite(hitData.sect, hitData.pos.x, hitData.pos.y, hitData.pos.z, + (RRRA && projecTile == SLINGBLADE) ? SLINGBLADE : KNEE,-15,0,0,shootAng,32,0,spriteNum,4); + sprite[kneeSprite].extra += (RRRA && projecTile == SLINGBLADE) ? 50 : (krand2()&7); + + if (playerNum >= 0) + { + int k = A_Spawn(kneeSprite, SMALLSMOKE); + sprite[k].z -= ZOFFSET3; + if (!RR || projecTile == KNEE) + A_PlaySound(KICK_HIT, kneeSprite); + else if (RRRA && projecTile == SLINGBLADE) + A_PlaySound(260, kneeSprite); + } + + if (pPlayer != NULL && pPlayer->inv_amount[GET_STEROIDS] > 0 && pPlayer->inv_amount[GET_STEROIDS] < 400) + sprite[kneeSprite].extra += (pPlayer->max_player_health>>2); + + if (hitData.sprite >= 0 && sprite[hitData.sprite].picnum != ACCESSSWITCH && sprite[hitData.sprite].picnum != ACCESSSWITCH2) + { + A_DamageObject(hitData.sprite, kneeSprite); + if (playerNum >= 0) + P_ActivateSwitch(playerNum, hitData.sprite, 1); + } + else if (hitData.wall >= 0) + { + HandleHitWall(&hitData); + + if (hitData.wall >= 0 && wall[hitData.wall].picnum != ACCESSSWITCH && wall[hitData.wall].picnum != ACCESSSWITCH2) + { + A_DamageWall(kneeSprite, hitData.wall, &hitData.pos, projecTile); + if (playerNum >= 0) + P_ActivateSwitch(playerNum, hitData.wall, 0); + } + } + } + else if(playerNum >= 0 && hitData.pos.z > 0 && sector[hitData.sect].lotag == 1) + { + int splashSprite = A_Spawn(pPlayer->i, WATERSPLASH2); + sprite[splashSprite].x = hitData.pos.x; + sprite[splashSprite].y = hitData.pos.y; + sprite[splashSprite].ang = fix16_to_int(pPlayer->q16ang); // Total tweek + sprite[splashSprite].xvel = 32; + A_SetSprite(spriteNum, RR ? 0 : CLIPMASK0); + sprite[splashSprite].xvel = 0; + } + } + break; + + case SHOTSPARK1__STATIC: + case SHOTGUN__STATIC: + case CHAINGUN__STATIC: + { + if (pSprite->extra >= 0) + pSprite->shade = -96; + + if (playerNum >= 0) + P_PreFireHitscan(spriteNum, playerNum, projecTile, &startPos, &Zvel, &shootAng, + projecTile == SHOTSPARK1 && !WW2GI, 1); + else + A_PreFireHitscan(pSprite, &startPos, &Zvel, &shootAng, 1); + + if (Proj_DoHitscan(spriteNum, 256 + 1, &startPos, Zvel, shootAng, &hitData)) + return -1; + + if (RR && projecTile == SHOTGUN && sector[hitData.sect].lotag == ST_1_ABOVE_WATER && (krand2()&1) != 0) + return -1; + + if ((krand2() & 15) == 0 && sector[hitData.sect].lotag == ST_2_UNDERWATER) + Proj_DoWaterTracers(hitData.pos, &startPos, 8 - (ud.multimode >> 1), pSprite->sectnum); + + int spawnedSprite; + + if (playerNum >= 0) + { + spawnedSprite = A_InsertSprite(hitData.sect, hitData.pos.x, hitData.pos.y, hitData.pos.z, SHOTSPARK1, -15, 10, 10, shootAng, 0, 0, spriteNum, 4); + sprite[spawnedSprite].extra = G_DefaultActorHealth(projecTile); + sprite[spawnedSprite].extra += (krand2()%6); + + + if (hitData.wall == -1 && hitData.sprite == -1) + { + if (Zvel < 0) + { + if (sector[hitData.sect].ceilingstat & 1) + { + sprite[spawnedSprite].xrepeat = 0; + sprite[spawnedSprite].yrepeat = 0; + return -1; + } + else + Sect_DamageCeiling(hitData.sect); + } + + if (!RR || sector[hitData.sect].lotag != ST_1_ABOVE_WATER) + A_Spawn(spawnedSprite, SMALLSMOKE); + } + + if (hitData.sprite >= 0) + { + if (RR && sprite[hitData.sprite].picnum == TORNADO) + return -1; + A_DamageObject(hitData.sprite, spawnedSprite); + + if (sprite[hitData.sprite].picnum == APLAYER && + (ud.ffire == 1 || (!GTFLAGS(GAMETYPE_PLAYERSFRIENDLY) && GTFLAGS(GAMETYPE_TDM) && + g_player[P_Get(hitData.sprite)].ps->team != g_player[P_Get(spriteNum)].ps->team))) + { + int jibSprite = A_Spawn(spawnedSprite, JIBS6); + + sprite[spawnedSprite].xrepeat = sprite[spawnedSprite].yrepeat = 0; + sprite[jibSprite].z += ZOFFSET6; + sprite[jibSprite].xvel = 16; + sprite[jibSprite].xrepeat = sprite[jibSprite].yrepeat = 24; + sprite[jibSprite].ang += 64 - (krand2() & 127); + } + else + { + A_Spawn(spawnedSprite, SMALLSMOKE); + } + + if (playerNum >= 0 && CheckShootSwitchTile(sprite[hitData.sprite].picnum)) + { + P_ActivateSwitch(playerNum, hitData.sprite, 1); + return -1; + } + } + else if (hitData.wall >= 0) + { + uwalltype const * const hitWall = (uwalltype *)&wall[hitData.wall]; + + A_Spawn(spawnedSprite, SMALLSMOKE); + + if (CheckDoorTile(hitWall->picnum) == 1) + goto SKIPBULLETHOLE; + + if (RR && CheckBlockDoorTile(hitWall->picnum) == 1) + goto SKIPBULLETHOLE; + + if (playerNum >= 0 && CheckShootSwitchTile(hitWall->picnum)) + { + P_ActivateSwitch(playerNum, hitData.wall, 0); + return -1; + } + + if (hitWall->hitag != 0 || (hitWall->nextwall >= 0 && wall[hitWall->nextwall].hitag != 0)) + goto SKIPBULLETHOLE; + + if ((hitData.sect >= 0 && sector[hitData.sect].lotag == 0) && + (hitWall->overpicnum != BIGFORCE && (hitWall->cstat & 16) == 0) && + ((hitWall->nextsector >= 0 && sector[hitWall->nextsector].lotag == 0) || (hitWall->nextsector == -1 && sector[hitData.sect].lotag == 0))) + { + int decalSprite; + + if (SectorContainsSE13(hitWall->nextsector)) + goto SKIPBULLETHOLE; + + for (SPRITES_OF(STAT_MISC, decalSprite)) + if (sprite[decalSprite].picnum == BULLETHOLE && dist(&sprite[decalSprite], &sprite[spawnedSprite]) < (12 + (krand2() & 7))) + goto SKIPBULLETHOLE; + + decalSprite = A_Spawn(spawnedSprite, BULLETHOLE); + + sprite[decalSprite].xvel = -1; + sprite[decalSprite].ang + = (getangle(hitWall->x - wall[hitWall->point2].x, hitWall->y - wall[hitWall->point2].y) + 512) & 2047; + + A_SetSprite(decalSprite, CLIPMASK0); + } + + SKIPBULLETHOLE: + + HandleHitWall(&hitData); + A_DamageWall(spawnedSprite, hitData.wall, &hitData.pos, SHOTSPARK1); + } + } + else + { + spawnedSprite = A_InsertSprite(hitData.sect, hitData.pos.x, hitData.pos.y, hitData.pos.z, SHOTSPARK1, -15, 24, 24, shootAng, 0, 0, spriteNum, 4); + sprite[spawnedSprite].extra = G_DefaultActorHealth(projecTile); + + if (hitData.sprite >= 0) + { + A_DamageObject(hitData.sprite, spawnedSprite); + if (sprite[hitData.sprite].picnum != APLAYER) + A_Spawn(spawnedSprite, SMALLSMOKE); + else + { + sprite[spawnedSprite].xrepeat = 0; + sprite[spawnedSprite].yrepeat = 0; + } + } + else if (hitData.wall >= 0) + A_DamageWall(spawnedSprite, hitData.wall, &hitData.pos, SHOTSPARK1); + } + + if ((krand2() & 255) < (RR ? 10 : 4)) + S_PlaySound3D(PISTOL_RICOCHET, spawnedSprite, &hitData.pos); + + return -1; + } + + case TRIPBOMBSPRITE__STATIC: + { + if (!RR) break; + int const newSprite = A_Spawn(spriteNum, projecTile); + sprite[newSprite].xvel = 32; + sprite[newSprite].ang = sprite[spriteNum].ang; + sprite[newSprite].z -= (5<<8); + break; + } + + case BOWLINGBALL__STATICRR: + { + int const newSprite = A_Spawn(spriteNum, projecTile); + sprite[newSprite].xvel = 250; + sprite[newSprite].ang = sprite[spriteNum].ang; + sprite[newSprite].z -= (15<<8); + break; + } + + case OWHIP__STATICRR: + case UWHIP__STATICRR: + { + if (pSprite->extra >= 0) + pSprite->shade = -96; + + if (projecTile == OWHIP) + { + vel = 300; + startPos.z -= (15<<8); + } + else //if (projecTile == UWHIP) + { + vel = 300; + startPos.z += (4<<8); + } + + if (playerNum >= 0) + { + if (GetAutoAimAng(spriteNum, playerNum, projecTile, -ZOFFSET4, 0, &startPos, vel, &Zvel, &shootAng) < 0) + Zvel = fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) * 98; + } + else + { + int const otherPlayer = A_FindPlayer(pSprite, NULL); + if (pSprite->picnum == VIXEN) + shootAng -= krand2()&16; + else + shootAng += 16 - (krand2() & 31); + hitData.pos.x = safeldist(g_player[otherPlayer].ps->i, pSprite); + Zvel = tabledivide32_noinline((g_player[otherPlayer].ps->opos.z - startPos.z + (3 << 8)) * vel, hitData.pos.x); + } + + int spriteSize = (playerNum >= 0) ? 7 : 8; + + int const returnSprite = A_InsertSprite(spriteSectnum, startPos.x, startPos.y, startPos.z, projecTile, -127, spriteSize, spriteSize, + shootAng, vel, Zvel, spriteNum, 4); + + sprite[returnSprite].extra += (krand2() & 7); + + sprite[returnSprite].cstat = 128; + sprite[returnSprite].clipdist = 4; + + shootAng = pSprite->ang + 32 - (krand2() & 63); + Zvel += 512 - (krand2() & 1023); + + return returnSprite; + } + + + case GROWSPARK__STATIC: + { + if (RR) + goto growspark_rr; + if (playerNum >= 0) + P_PreFireHitscan(spriteNum, playerNum, projecTile, &startPos, &Zvel, &shootAng, 1, 1); + else + A_PreFireHitscan(pSprite, &startPos, &Zvel, &shootAng, 1); + + if (Proj_DoHitscan(spriteNum, 256 + 1, &startPos, Zvel, shootAng, &hitData)) + return -1; + + int const otherSprite = A_InsertSprite(hitData.sect, hitData.pos.x, hitData.pos.y, hitData.pos.z, GROWSPARK, -16, 28, 28, + shootAng, 0, 0, spriteNum, 1); + + sprite[otherSprite].pal = 2; + sprite[otherSprite].cstat |= 130; + sprite[otherSprite].xrepeat = sprite[otherSprite].yrepeat = 1; + + if (hitData.wall == -1 && hitData.sprite == -1 && hitData.sect >= 0 + && Zvel < 0 && (sector[hitData.sprite].ceilingstat & 1) == 0) + { + Sect_DamageCeiling(hitData.sect); + } + else if (hitData.sprite >= 0) + A_DamageObject(hitData.sprite, otherSprite); + else if (hitData.wall >= 0 && wall[hitData.wall].picnum != ACCESSSWITCH && wall[hitData.wall].picnum != ACCESSSWITCH2) + A_DamageWall(otherSprite, hitData.wall, &hitData.pos, projecTile); + } + break; + + case FIRELASER__STATIC: + case SPIT__STATIC: + case COOLEXPLOSION1__STATIC: + { + if ((!RRRA || projecTile != SPIT) && pSprite->extra >= 0) + pSprite->shade = -96; + + switch (projecTile) + { + case SPIT__STATIC: + if (RRRA && pSprite->picnum == MAMA) + vel = 600; + else + vel = RR ? 400 : 292; + break; + case COOLEXPLOSION1__STATIC: + if (!RR) + { + vel = (pSprite->picnum == BOSS2) ? 644 : 348; + startPos.z -= (4 << 7); + break; + } + fallthrough__; + case FIRELASER__STATIC: + default: + vel = 840; + startPos.z -= (4 << 7); + if (RR) + { + if (pSprite->picnum == HULK) + { + startPos.x += sintable[(pSprite->ang+512+256)&2047]>>6; + startPos.y += sintable[(pSprite->ang+256)&2047]>>6; + startPos.z += (12 << 8); + } + else if (pSprite->picnum == VIXEN) + startPos.z -= (12 << 8); + } + break; + } + + if (playerNum >= 0) + { + if (RR) + { + startPos.x += sintable[(pSprite->ang+512+160)&2047]>>7; + startPos.y += sintable[(pSprite->ang+160)&2047]>>7; + } + if (GetAutoAimAng(spriteNum, playerNum, projecTile, -ZOFFSET4, 0, &startPos, vel, &Zvel, &shootAng) < 0) + Zvel = fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) * 98; + } + else + { + int const otherPlayer = A_FindPlayer(pSprite, NULL); + if (RR) + { + if (pSprite->picnum == HULK) + shootAng -= krand2()&31; + else if (pSprite->picnum == VIXEN) + shootAng -= krand2()&16; + else if (pSprite->picnum != UFOBEAM) + shootAng += 16 - (krand2() & 31); + } + else + shootAng += 16 - (krand2() & 31); + hitData.pos.x = safeldist(g_player[otherPlayer].ps->i, pSprite); + Zvel = tabledivide32_noinline((g_player[otherPlayer].ps->opos.z - startPos.z + (3 << 8)) * vel, hitData.pos.x); + } + + int spriteSize = 18; + + if (RR) + { + if (projecTile == SPIT) + { + if (RRRA && pSprite->picnum == MAMA) + startPos.z -= (20 << 8); + else + startPos.z -= (10 << 8); + } + else if (projecTile == COOLEXPLOSION1) + spriteSize = 8; + } + else + { + if (projecTile == SPIT) + startPos.z -= (10 << 8); + } + + if (playerNum >= 0) spriteSize = 7; + + int const returnSprite = A_InsertSprite(spriteSectnum, startPos.x, startPos.y, startPos.z, projecTile, -127, spriteSize, spriteSize, + shootAng, vel, Zvel, spriteNum, 4); + + sprite[returnSprite].extra += (krand2() & 7); + + if (!RR && projecTile == COOLEXPLOSION1) + { + sprite[returnSprite].shade = 0; + + if (PN(spriteNum) == BOSS2) + { + int const saveXvel = sprite[returnSprite].xvel; + sprite[returnSprite].xvel = 1024; + A_SetSprite(returnSprite, CLIPMASK0); + sprite[returnSprite].xvel = saveXvel; + sprite[returnSprite].ang += 128 - (krand2() & 255); + } + } + + sprite[returnSprite].cstat = 128; + sprite[returnSprite].clipdist = 4; + + shootAng = pSprite->ang + 32 - (krand2() & 63); + Zvel += 512 - (krand2() & 1023); + + if (RR && projecTile == FIRELASER) + sprite[returnSprite].xrepeat = sprite[returnSprite].yrepeat = 8; + + return returnSprite; + } + + case FREEZEBLAST__STATIC: + startPos.z += (3 << 8); + fallthrough__; + case RPG__STATIC: + case RPG2__STATICRR: + case RRTILE1790__STATICRR: + case SHRINKSPARK__STATIC: + { + if (!RR && projecTile == SHRINKSPARK) break; + if (RR && !RRRA && (projecTile == RPG2 || projecTile == RRTILE1790)) break; + + int targetSprite = 0; + + // XXX: "CODEDUP" + if (pSprite->extra >= 0) + pSprite->shade = -96; + + vel = 644; + + int otherSprite = -1; + + if (playerNum >= 0) + { + // NOTE: otherSprite is a SPRITE_INDEX + otherSprite = GetAutoAimAng(spriteNum, playerNum, projecTile, 8 << 8, 0 + 2, &startPos, vel, &Zvel, &shootAng); + + if (RRRA && projecTile == RPG2 && otherSprite >= 0) + { + if (sprite[otherSprite].picnum == HEN || sprite[otherSprite].picnum == HENSTAYPUT) + targetSprite = pPlayer->i; + else + targetSprite = otherSprite; + } + + if (otherSprite < 0) + Zvel = fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) * 81; + + if (projecTile == RPG) + A_PlaySound(RPG_SHOOT, spriteNum); + else if (RRRA) + { + if (projecTile == RPG2) + A_PlaySound(244, spriteNum); + else if (projecTile == RRTILE1790) + A_PlaySound(94, spriteNum); + } + } + else + { + // NOTE: otherSprite is a player index + otherSprite = A_FindPlayer(pSprite, NULL); + shootAng = getangle(g_player[otherSprite].ps->opos.x - startPos.x, g_player[otherSprite].ps->opos.y - startPos.y); + if (PN(spriteNum) == BOSS3) + startPos.z -= ZOFFSET5; + else if (PN(spriteNum) == BOSS2) + { + vel += 128; + startPos.z += 24<<8; + } + + Zvel = tabledivide32_noinline((g_player[otherSprite].ps->opos.z - startPos.z) * vel, safeldist(g_player[otherSprite].ps->i, pSprite)); + + if (A_CheckEnemySprite(pSprite) && (AC_MOVFLAGS(pSprite, &actor[spriteNum]) & face_player_smart)) + shootAng = pSprite->ang + (krand2() & 31) - 16; + } + + //if (numplayers > 1 && g_netClient) + // return -1; + + if (RRRA && projecTile == RRTILE1790) + { + Zvel = -(10 << 8); + vel <<= 1; + } + + int const returnSprite = A_InsertSprite(spriteSectnum, startPos.x + (sintable[(348 + shootAng + 512) & 2047] / 448), + startPos.y + (sintable[(shootAng + 348) & 2047] / 448), startPos.z - (1 << 8), + projecTile, 0, 14, 14, shootAng, vel, Zvel, spriteNum, 4); + spritetype *const pReturn = &sprite[returnSprite]; + + if (RRRA) + { + if (projecTile == RRTILE1790) + { + pReturn->extra = 10; + pReturn->zvel = -(10 << 8); + } + else if (projecTile == RPG2) + { + pReturn->lotag = targetSprite; + pReturn->hitag = 0; + A_SpawnMultiple(returnSprite, MONEY, (krand2()&3)+1); + } + } + + pReturn->extra += (krand2() & 7); + if (projecTile != FREEZEBLAST) + pReturn->yvel = (playerNum >= 0 && otherSprite >= 0) ? otherSprite : -1; // RPG_YVEL + else + { + pReturn->yvel = g_numFreezeBounces; + pReturn->xrepeat >>= 1; + pReturn->yrepeat >>= 1; + pReturn->zvel -= (2 << 4); + } + + if (playerNum == -1) + { + if (RR && PN(spriteNum) == HULK) + { + pReturn->xrepeat = 8; + pReturn->yrepeat = 8; + } + else if (!RR && PN(spriteNum) == BOSS3) + { + if (krand2() & 1) + { + pReturn->x -= sintable[shootAng & 2047] >> 6; + pReturn->y -= sintable[(shootAng + 1024 + 512) & 2047] >> 6; + pReturn->ang -= 8; + } + else + { + pReturn->x += sintable[shootAng & 2047] >> 6; + pReturn->y += sintable[(shootAng + 1024 + 512) & 2047] >> 6; + pReturn->ang += 4; + } + pReturn->xrepeat = 42; + pReturn->yrepeat = 42; + } + else if (!RR && PN(spriteNum) == BOSS2) + { + pReturn->x -= sintable[shootAng & 2047] / 56; + pReturn->y -= sintable[(shootAng + 1024 + 512) & 2047] / 56; + pReturn->ang -= 8 + (krand2() & 255) - 128; + pReturn->xrepeat = 24; + pReturn->yrepeat = 24; + } + else if (projecTile != FREEZEBLAST) + { + pReturn->xrepeat = 30; + pReturn->yrepeat = 30; + pReturn->extra >>= 2; + } + } + else if ((WW2GI ? PWEAPON(playerNum, g_player[playerNum].ps->curr_weapon, WorksLike) : g_player[playerNum].ps->curr_weapon) == DEVISTATOR_WEAPON) + { + pReturn->extra >>= 2; + pReturn->ang += 16 - (krand2() & 31); + pReturn->zvel += 256 - (krand2() & 511); + + if (g_player[playerNum].ps->hbomb_hold_delay) + { + pReturn->x -= sintable[shootAng & 2047] / 644; + pReturn->y -= sintable[(shootAng + 1024 + 512) & 2047] / 644; + } + else + { + pReturn->x += sintable[shootAng & 2047] >> 8; + pReturn->y += sintable[(shootAng + 1024 + 512) & 2047] >> 8; + } + pReturn->xrepeat >>= 1; + pReturn->yrepeat >>= 1; + } + + pReturn->cstat = 128; + pReturn->clipdist = (projecTile == RPG) ? 4 : 40; + + if (RRRA && (projecTile == RPG2 || projecTile == RRTILE1790)) + pReturn->clipdist = 4; + + return returnSprite; + } + + case HANDHOLDINGLASER__STATIC: + { + if (RR) break; + int const zOffset = (playerNum >= 0) ? g_player[playerNum].ps->pyoff : 0; + Zvel = (playerNum >= 0) ? fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) * 32 : 0; + + startPos.z -= zOffset; + Proj_DoHitscan(spriteNum, 0, &startPos, Zvel, shootAng, &hitData); + startPos.z += zOffset; + + int placeMine = 0; + if (hitData.sprite >= 0) + break; + + if (hitData.wall >= 0 && hitData.sect >= 0) + if (((hitData.pos.x - startPos.x) * (hitData.pos.x - startPos.x) + + (hitData.pos.y - startPos.y) * (hitData.pos.y - startPos.y)) + < (290 * 290)) + { + // ST_2_UNDERWATER + if (wall[hitData.wall].nextsector >= 0) + { + if (sector[wall[hitData.wall].nextsector].lotag <= 2 && sector[hitData.sect].lotag <= 2) + placeMine = 1; + } + else if (sector[hitData.sect].lotag <= 2) + placeMine = 1; + } + + if (placeMine == 1) + { + int const tripBombMode = Gv_GetVarByLabel("TRIPBOMB_CONTROL", TRIPBOMB_TRIPWIRE, -1, -1); + int const spawnedSprite = A_InsertSprite(hitData.sect, hitData.pos.x, hitData.pos.y, hitData.pos.z, TRIPBOMB, -16, 4, 5, + shootAng, 0, 0, spriteNum, 6); + if (tripBombMode & TRIPBOMB_TIMER) + { + int32_t lLifetime = Gv_GetVarByLabel("STICKYBOMB_LIFETIME", NAM_GRENADE_LIFETIME, -1, playerNum); + int32_t lLifetimeVar + = Gv_GetVarByLabel("STICKYBOMB_LIFETIME_VAR", NAM_GRENADE_LIFETIME_VAR, -1, playerNum); + // set timer. blows up when at zero.... + sprite[spawnedSprite].extra = lLifetime + mulscale14(krand2(), lLifetimeVar) - lLifetimeVar; + } + sprite[spawnedSprite].hitag = spawnedSprite; + A_PlaySound(LASERTRIP_ONWALL, spawnedSprite); + sprite[spawnedSprite].xvel = -20; + A_SetSprite(spawnedSprite, CLIPMASK0); + sprite[spawnedSprite].cstat = 16; + + int const p2 = wall[hitData.wall].point2; + int const wallAng = getangle(wall[hitData.wall].x - wall[p2].x, wall[hitData.wall].y - wall[p2].y) - 512; + + actor[spawnedSprite].t_data[5] = sprite[spawnedSprite].ang = wallAng; + + if (!WW2GI && playerNum >= 0) + pPlayer->ammo_amount[TRIPBOMB_WEAPON]--; + + return spawnedSprite; + } + return -1; + } + + case BOUNCEMINE__STATIC: + if (RR) break; + fallthrough__; + case MORTER__STATIC: + case CHEERBOMB__STATICRR: + { + if (RR && !RRRA && projecTile == CHEERBOMB) break; + + if (pSprite->extra >= 0) + pSprite->shade = -96; + + int const playerSprite = g_player[A_FindPlayer(pSprite, NULL)].ps->i; + int const playerDist = ldist(&sprite[playerSprite], pSprite); + + Zvel = -playerDist >> 1; + + if (Zvel < -4096) + Zvel = -2048; + + vel = playerDist >> 4; + + int spriteSize = (RRRA && projecTile == CHEERBOMB) ? 16 : 32; + + A_InsertSprite(spriteSectnum, startPos.x + (sintable[(512 + shootAng + 512) & 2047] >> 8), + startPos.y + (sintable[(shootAng + 512) & 2047] >> 8), startPos.z + (6 << 8), projecTile, -64, + spriteSize, spriteSize, shootAng, vel, Zvel, spriteNum, 1); + break; + } + + case SHRINKER__STATIC: + { + if (RR) break; + if (pSprite->extra >= 0) + pSprite->shade = -96; + + if (playerNum >= 0) + { + if (NAM_WW2GI || GetAutoAimAng(spriteNum, playerNum, projecTile, ZOFFSET6, 0, &startPos, 768, &Zvel, &shootAng) < 0) + Zvel = fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) * 98; + } + else if (pSprite->statnum != STAT_EFFECTOR) + { + int const otherPlayer = A_FindPlayer(pSprite, NULL); + Zvel = tabledivide32_noinline((g_player[otherPlayer].ps->opos.z - startPos.z) * 512, + safeldist(g_player[otherPlayer].ps->i, pSprite)); + } + else + Zvel = 0; + + int const returnSprite = A_InsertSprite(spriteSectnum, startPos.x + (sintable[(512 + shootAng + 512) & 2047] >> 12), + startPos.y + (sintable[(shootAng + 512) & 2047] >> 12), startPos.z + (2 << 8), + SHRINKSPARK, -16, 28, 28, shootAng, 768, Zvel, spriteNum, 4); + sprite[returnSprite].cstat = 128; + sprite[returnSprite].clipdist = 32; + + return returnSprite; + } + } + + return -1; +} + +void A_DHShoot(int const playerNum) +{ + switch (g_player[playerNum].ps->dhat61f) + { + case 0: + ghpistol_fire(playerNum); + break; + case 1: + case 2: + ghrifle_fire(playerNum); + break; + case 3: + ghshtgn_fire(playerNum); + break; + case 4: + ghbow_fire(playerNum); + break; + } +} + + +//////////////////// HUD WEAPON / MISC. DISPLAY CODE //////////////////// + +static void P_DisplaySpit(void) +{ + DukePlayer_t *const pPlayer = g_player[screenpeek].ps; + int const loogCounter = pPlayer->loogcnt; + + if (loogCounter == 0) + return; + + int const rotY = loogCounter<<2; + + for (bssize_t i=0; i < pPlayer->numloogs; i++) + { + int const rotAng = klabs(sintable[((loogCounter + i) << 5) & 2047]) >> 5; + int const rotZoom = 4096 + ((loogCounter + i) << 9); + int const rotX = (-fix16_to_int(g_player[screenpeek].input->q16avel) >> 1) + (sintable[((loogCounter + i) << 6) & 2047] >> 10); + + rotatesprite_fs((pPlayer->loogiex[i] + rotX) << 16, (200 + pPlayer->loogiey[i] - rotY) << 16, rotZoom - (i << 8), + 256 - rotAng, LOOGIE, 0, 0, 2); + } +} + +int P_GetHudPal(const DukePlayer_t *p) +{ + if (sprite[p->i].pal == 1) + return 1; + + if (p->cursectnum >= 0) + { + int const hudPal = sector[p->cursectnum].floorpal; + if (!lookups.noFloorPal(hudPal)) + return hudPal; + } + + return 0; +} + +int P_GetKneePal(DukePlayer_t const * pPlayer) +{ + return P_GetKneePal(pPlayer, P_GetHudPal(pPlayer)); +} + +int P_GetKneePal(DukePlayer_t const * pPlayer, int const hudPal) +{ + return hudPal == 0 ? pPlayer->palookup : hudPal; +} + +int P_GetOverheadPal(DukePlayer_t const * pPlayer) +{ + return sprite[pPlayer->i].pal; +} + +static int P_DisplayFist(int const fistShade) +{ + DukePlayer_t const *const pPlayer = g_player[screenpeek].ps; + int fistInc = pPlayer->fist_incs; + + if (fistInc > 32) + fistInc = 32; + + if (fistInc <= 0) + return 0; + + int const fistY = klabs(fix16_to_int(pPlayer->q16look_ang)) / 9; + int const fistZoom = clamp(65536 - (sintable[(512 + (fistInc << 6)) & 2047] << 2), 40920, 90612); + int const fistYOffset = 194 + (sintable[((6 + fistInc) << 7) & 2047] >> 9); + int const fistPal = P_GetHudPal(pPlayer); + int wx[2] = { windowxy1.x, windowxy2.x }; + +#ifdef SPLITSCREEN_MOD_HACKS + // XXX: this is outdated, doesn't handle above/below split. + if (g_fakeMultiMode==2) + wx[(g_snum==0)] = (wx[0]+wx[1])/2+1; +#endif + + rotatesprite((-fistInc + 222 + (fix16_to_int(g_player[screenpeek].input->q16avel) >> 5)) << 16, (fistY + fistYOffset) << 16, + fistZoom, 0, FIST, fistShade, fistPal, 2, wx[0], windowxy1.y, wx[1], windowxy2.y); + + return 1; +} + +#define DRAWEAP_CENTER 262144 +#define weapsc(sc) scale(sc, hud_weaponscale, 100) + +static int32_t g_dts_yadd; + +static void G_DrawTileScaled(int drawX, int drawY, int tileNum, int drawShade, int drawBits, int drawPal, + int drawScale = 65536, int angleOffset = 0) +{ + int32_t wx[2] = { windowxy1.x, windowxy2.x }; + int32_t wy[2] = { windowxy1.y, windowxy2.y }; + + int drawYOffset = 0; + int drawXOffset = 192<<16; + + switch (DYNAMICWEAPONMAP(hudweap.cur)) + { + case DEVISTATOR_WEAPON__STATIC: + case TRIPBOMB_WEAPON__STATIC: + drawXOffset = 160<<16; + break; + default: + if (drawBits & DRAWEAP_CENTER) + { + drawXOffset = 160<<16; + drawBits &= ~DRAWEAP_CENTER; + } + break; + } + + // bit 4 means "flip x" for G_DrawTileScaled + int const drawAng = ((drawBits & 4) ? 1024 : 0) + angleOffset; + +#ifdef SPLITSCREEN_MOD_HACKS + if (g_fakeMultiMode==2) + { + int const sideBySide = (ud.screen_size!=0); + + // splitscreen HACK + drawBits &= ~(1024|512|256); + if (sideBySide) + { + drawBits &= ~8; + wx[(g_snum==0)] = (wx[0]+wx[1])/2 + 2; + } + else + { + drawBits |= 8; + if (g_snum==0) + drawYOffset = -(100<<16); + wy[(g_snum==0)] = (wy[0]+wy[1])/2 + 2; + } + } +#endif + +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST && hw_models && md_tilehasmodel(tileNum,drawPal) >= 0) + drawYOffset += (224<<16)-weapsc(224<<16); +#endif + rotatesprite(weapsc(drawX<<16) + (drawXOffset-weapsc(drawXOffset)), + weapsc((drawY<<16) + g_dts_yadd) + ((200<<16)-weapsc(200<<16)) + drawYOffset, + weapsc(drawScale),drawAng,tileNum,drawShade,drawPal,(2|drawBits), + wx[0],wy[0], wx[1],wy[1]); +} + +static void G_DrawWeaponTile(int weaponX, int weaponY, int weaponTile, int weaponShade, int weaponBits, int weaponPal, int weaponScale = 65536) +{ + static int shadef = 0; + static int palf = 0; + + // basic fading between player weapon shades + if (shadef != weaponShade && (!weaponPal || palf == weaponPal)) + { + shadef += (weaponShade - shadef) >> 2; + + if (!((weaponShade - shadef) >> 2)) + shadef = logapproach(shadef, weaponShade); + } + else + shadef = weaponShade; + + palf = weaponPal; + +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST) + { + if (!RR && weaponTile >= CHAINGUN + 1 && weaponTile <= CHAINGUN + 4) + { + if (!hw_models || md_tilehasmodel(weaponTile, weaponPal) < 0) + { + // HACK: Draw the upper part of the chaingun two screen + // pixels (not texels; multiplied by weapon scale) lower + // first, preventing ugly horizontal seam. + g_dts_yadd = tabledivide32_noinline(65536 * 2 * 200, ydim); + G_DrawTileScaled(weaponX, weaponY, weaponTile, shadef, weaponBits, weaponPal); + g_dts_yadd = 0; + } + } + } +#endif + + G_DrawTileScaled(weaponX, weaponY, weaponTile, shadef, weaponBits, weaponPal, weaponScale); +} + +static inline void G_DrawWeaponTileWithID(int uniqueID, int weaponX, int weaponY, int weaponTile, int weaponShade, + int weaponBits, int p, int weaponScale = 65536) +{ + int lastUniqueID = guniqhudid; + guniqhudid = uniqueID; + + G_DrawWeaponTile(weaponX, weaponY, weaponTile, weaponShade, weaponBits, p, weaponScale); + + guniqhudid = lastUniqueID; +} + +static inline void G_DrawWeaponTileUnfadedWithID(int uniqueID, int weaponX, int weaponY, int weaponTile, int weaponShade, + int weaponBits, int p) +{ + int lastUniqueID = guniqhudid; + guniqhudid = uniqueID; + + G_DrawTileScaled(weaponX, weaponY, weaponTile, weaponShade, weaponBits, p); // skip G_DrawWeaponTile + + guniqhudid = lastUniqueID; +} + +static int P_DisplayKnee(int kneeShade) +{ + static int8_t const knee_y[] = { 0, -8, -16, -32, -64, -84, -108, -108, -108, -72, -32, -8 }; + const DukePlayer_t *const ps = g_player[screenpeek].ps; + + if (ps->knee_incs == 0) + return 0; + + if (ps->knee_incs >= ARRAY_SIZE(knee_y) || sprite[ps->i].extra <= 0) + return 0; + + int const kneeY = knee_y[ps->knee_incs] + (klabs(fix16_to_int(ps->q16look_ang)) / 9) - (ps->hard_landing << 3); + int const kneePal = P_GetKneePal(ps); + + G_DrawTileScaled(105+(fix16_to_int(g_player[screenpeek].input->q16avel)>>5)-(fix16_to_int(ps->q16look_ang)>>1)+(knee_y[ps->knee_incs]>>2), + kneeY+280-(fix16_to_int(ps->q16horiz-ps->q16horizoff)>>4),KNEE,kneeShade,4+DRAWEAP_CENTER,kneePal); + + return 1; +} + +static int P_DisplayKnuckles(int knuckleShade) +{ + if (WW2GI) + return 0; + const DukePlayer_t *const pPlayer = g_player[screenpeek].ps; + + if (pPlayer->knuckle_incs == 0) + return 0; + + static int8_t const knuckleFrames[] = { 0, 1, 2, 2, 3, 3, 3, 2, 2, 1, 0 }; + + if ((unsigned) (pPlayer->knuckle_incs>>1) >= ARRAY_SIZE(knuckleFrames) || sprite[pPlayer->i].extra <= 0) + return 0; + + int const knuckleY = (klabs(fix16_to_int(pPlayer->q16look_ang)) / 9) - (pPlayer->hard_landing << 3); + int const knucklePal = P_GetHudPal(pPlayer); + + G_DrawTileScaled(160 + (fix16_to_int(g_player[screenpeek].input->q16avel) >> 5) - (fix16_to_int(pPlayer->q16look_ang) >> 1), + knuckleY + 180 - (fix16_to_int(pPlayer->q16horiz - pPlayer->q16horizoff) >> 4), + CRACKKNUCKLES + knuckleFrames[pPlayer->knuckle_incs >> 1], knuckleShade, 4 + DRAWEAP_CENTER, + knucklePal); + + return 1; +} + +// Set C-CON's WEAPON and WORKSLIKE gamevars. +void P_SetWeaponGamevars(int playerNum, const DukePlayer_t * const pPlayer) +{ + if (!WW2GI) + return; + Gv_SetVar(g_weaponVarID, pPlayer->curr_weapon, pPlayer->i, playerNum); + Gv_SetVar(g_worksLikeVarID, + ((unsigned)pPlayer->curr_weapon < MAX_WEAPONS) ? PWEAPON(playerNum, pPlayer->curr_weapon, WorksLike) : -1, + pPlayer->i, playerNum); +} + +static void P_FireWeapon(int playerNum) +{ + auto const pPlayer = g_player[playerNum].ps; + + if (PWEAPON(playerNum, pPlayer->curr_weapon, WorksLike) != KNEE_WEAPON) + pPlayer->ammo_amount[pPlayer->curr_weapon]--; + + if (PWEAPON(playerNum, pPlayer->curr_weapon, FireSound) > 0) + A_PlaySound(PWEAPON(playerNum, pPlayer->curr_weapon, FireSound), pPlayer->i); + + P_SetWeaponGamevars(playerNum, pPlayer); + // Printf("doing %d %d %d\n",PWEAPON(snum, p->curr_weapon, Shoots),p->curr_weapon,snum); + A_Shoot(pPlayer->i, PWEAPON(playerNum, pPlayer->curr_weapon, Shoots)); + + for (bssize_t burstFire = PWEAPON(playerNum, pPlayer->curr_weapon, ShotsPerBurst) - 1; burstFire > 0; --burstFire) + { + A_Shoot(pPlayer->i, PWEAPON(playerNum, pPlayer->curr_weapon, Shoots)); + + if (PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_AMMOPERSHOT) + { + pPlayer->ammo_amount[pPlayer->curr_weapon]--; + } + } + + if (!(PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_NOVISIBLE)) + { +#ifdef POLYMER + spritetype *s = &sprite[pPlayer->i]; + int32_t x = ((sintable[(s->ang + 512) & 2047]) >> 7), y = ((sintable[(s->ang) & 2047]) >> 7); + + s->x += x; + s->y += y; + G_AddGameLight(0, pPlayer->i, PHEIGHT, 8192, PWEAPON(playerNum, pPlayer->curr_weapon, FlashColor), + PR_LIGHT_PRIO_MAX_GAME); + actor[pPlayer->i].lightcount = 2; + s->x -= x; + s->y -= y; +#endif // POLYMER + pPlayer->visibility = 0; + } + + if (/*!(PWEAPON(playerNum, p->curr_weapon, Flags) & WEAPON_CHECKATRELOAD) && */ + PWEAPON(playerNum, pPlayer->curr_weapon, Reload) > PWEAPON(playerNum, pPlayer->curr_weapon, TotalTime) && pPlayer->ammo_amount[pPlayer->curr_weapon] > 0 + && (PWEAPON(playerNum, pPlayer->curr_weapon, Clip)) && (((pPlayer->ammo_amount[pPlayer->curr_weapon]%(PWEAPON(playerNum, pPlayer->curr_weapon, Clip)))==0))) + { + pPlayer->kickback_pic = PWEAPON(playerNum, pPlayer->curr_weapon, TotalTime); + } + + if (PWEAPON(playerNum, pPlayer->curr_weapon, WorksLike) != KNEE_WEAPON) + P_CheckWeapon(pPlayer); +} + +static void P_DoWeaponSpawn(int playerNum) +{ + auto const pPlayer = g_player[playerNum].ps; + + // NOTE: For the 'Spawn' member, 0 means 'none', too (originally so, + // i.e. legacy). The check for <0 was added to the check because mod + // authors (rightly) assumed that -1 is the no-op value. + if (PWEAPON(playerNum, pPlayer->curr_weapon, Spawn) <= 0) // <=0 : AMC TC beta/RC2 has WEAPONx_SPAWN -1 + return; + + int newSprite = A_Spawn(pPlayer->i, PWEAPON(playerNum, pPlayer->curr_weapon, Spawn)); + + if ((PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_SPAWNTYPE2)) + { + // like shotgun shells + sprite[newSprite].ang += 1024; + A_SetSprite(newSprite,CLIPMASK0); + sprite[newSprite].ang += 1024; + } + else if ((PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_SPAWNTYPE3)) + { + // like chaingun shells + sprite[newSprite].ang += 1024; + sprite[newSprite].ang &= 2047; + sprite[newSprite].xvel += 32; + sprite[newSprite].z += (3<<8); + A_SetSprite(newSprite,CLIPMASK0); + } +} + +void P_DisplayScuba(void) +{ + if (g_player[screenpeek].ps->scuba_on) + { + const DukePlayer_t *const pPlayer = g_player[screenpeek].ps; + + int const scubaPal = P_GetHudPal(pPlayer); + +#ifdef SPLITSCREEN_MOD_HACKS + g_snum = screenpeek; +#endif + + if (RR) + { + + if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) + { + G_DrawTileScaled(320 - (tilesiz[SCUBAMASK].x >> 1) - 15, 200 - (tilesiz[SCUBAMASK].y >> 1) + (sintable[(int32_t) totalclock & 2047] >> 10), + SCUBAMASK, 0, 2 + 16 + DRAWEAP_CENTER+512, scubaPal,49152); + G_DrawTileScaled(320 - tilesiz[SCUBAMASK+4].x, 200 - tilesiz[SCUBAMASK+4].y, SCUBAMASK+4, 0, 2 + 16 + DRAWEAP_CENTER + 1024, scubaPal); + G_DrawTileScaled(tilesiz[SCUBAMASK+4].x, 200 - tilesiz[SCUBAMASK+4].y, SCUBAMASK+4, 0, 2 + 4 + 16 + DRAWEAP_CENTER + 1024, scubaPal); + //G_DrawTileScaled(35, -1, SCUBAMASK+3, 0, 2 + 16 + DRAWEAP_CENTER+512, scubaPal); + //G_DrawTileScaled(35, -1, SCUBAMASK+3, 0, 2 + 16 + DRAWEAP_CENTER+256, scubaPal); + //G_DrawTileScaled(285, 200, SCUBAMASK+3, 0, 2 + 16 + DRAWEAP_CENTER+512, scubaPal,65536,1024); + //G_DrawTileScaled(285, 200, SCUBAMASK+3, 0, 2 + 16 + DRAWEAP_CENTER+256, scubaPal,65536,1024); + G_DrawTileScaled(35, -1, SCUBAMASK+3, 0, 2 + 16 + DRAWEAP_CENTER+1024, scubaPal); + G_DrawTileScaled(285, 200, SCUBAMASK+3, 0, 2 + 16 + DRAWEAP_CENTER+1024, scubaPal,65536,1024); + } + else + { + G_DrawTileScaled(320 - (tilesiz[SCUBAMASK].x >> 1) - 15, 200 - (tilesiz[SCUBAMASK].y >> 1) + (sintable[(int32_t) totalclock & 2047] >> 10), + SCUBAMASK, 0, 2 + 16 + DRAWEAP_CENTER, scubaPal,49152); + G_DrawTileScaled(320 - tilesiz[SCUBAMASK+4].x, 200 - tilesiz[SCUBAMASK+4].y, SCUBAMASK+4, 0, 2 + 16 + DRAWEAP_CENTER, scubaPal); + G_DrawTileScaled(tilesiz[SCUBAMASK+4].x, 200 - tilesiz[SCUBAMASK+4].y, SCUBAMASK+4, 0, 2 + 4 + 16 + DRAWEAP_CENTER, scubaPal); + G_DrawTileScaled(35, -1, SCUBAMASK+3, 0, 2 + 16 + DRAWEAP_CENTER, scubaPal); + G_DrawTileScaled(285, 200, SCUBAMASK+3, 0, 2 + 16 + DRAWEAP_CENTER, scubaPal,65536,1024); + } + } + else + { + // this is a hack to hide the seam that appears between the two halves of the mask in GL +#ifdef USE_OPENGL + if (videoGetRenderMode() >= REND_POLYMOST) + G_DrawTileScaled(44, (200 - tilesiz[SCUBAMASK].y), SCUBAMASK, 0, 2 + 16 + DRAWEAP_CENTER, scubaPal); +#endif + G_DrawTileScaled(43, (200 - tilesiz[SCUBAMASK].y), SCUBAMASK, 0, 2 + 16 + DRAWEAP_CENTER, scubaPal); + G_DrawTileScaled(320 - 43, (200 - tilesiz[SCUBAMASK].y), SCUBAMASK, 0, 2 + 4 + 16 + DRAWEAP_CENTER, scubaPal); + } + } +} + +static int8_t const access_tip_y [] = { + 0, -8, -16, -32, -64, -84, -108, -108, -108, -108, -108, -108, -108, -108, -108, -108, -96, -72, -64, -32, -16 +}; + +static int P_DisplayTip(int tipShade) +{ + const DukePlayer_t *const pPlayer = g_player[screenpeek].ps; + + if (pPlayer->tipincs == 0) + return 0; + + // Report that the tipping hand has been drawn so that the otherwise + // selected weapon is not drawn. + if ((unsigned)pPlayer->tipincs >= ARRAY_SIZE(access_tip_y)) + return 1; + + int const tipY = (klabs(fix16_to_int(pPlayer->q16look_ang)) / 9) - (pPlayer->hard_landing << 3); + int const tipPal = P_GetHudPal(pPlayer); + int const tipYOffset = access_tip_y[pPlayer->tipincs] >> 1; + + guniqhudid = 201; + + G_DrawTileScaled(170 + (fix16_to_int(g_player[screenpeek].input->q16avel) >> 5) - (fix16_to_int(pPlayer->q16look_ang) >> 1), + tipYOffset + tipY + 240 - (fix16_to_int(pPlayer->q16horiz - pPlayer->q16horizoff) >> 4), + TIP + ((26 - pPlayer->tipincs) >> 4), tipShade, DRAWEAP_CENTER, tipPal); + + guniqhudid = 0; + + return 1; +} + +static int P_DisplayAccess(int accessShade) +{ + const DukePlayer_t *const pSprite = g_player[screenpeek].ps; + + if (pSprite->access_incs == 0) + return 0; + + if ((unsigned)pSprite->access_incs >= ARRAY_SIZE(access_tip_y)-4 || sprite[pSprite->i].extra <= 0) + return 1; + + int const accessX = access_tip_y[pSprite->access_incs] >> 2; + int const accessY = access_tip_y[pSprite->access_incs] + (klabs(fix16_to_int(pSprite->q16look_ang)) / 9) - (pSprite->hard_landing << 3); + int const accessPal = (pSprite->access_spritenum >= 0) ? sprite[pSprite->access_spritenum].pal : 0; + + guniqhudid = 200; + + if ((pSprite->access_incs - 3) > 0 && (pSprite->access_incs - 3) >> 3) + { + G_DrawTileScaled(170 + (fix16_to_int(g_player[screenpeek].input->q16avel) >> 5) - (fix16_to_int(pSprite->q16look_ang) >> 1) + accessX, + accessY + 266 - (fix16_to_int(pSprite->q16horiz - pSprite->q16horizoff) >> 4), + HANDHOLDINGLASER + (pSprite->access_incs >> 3), accessShade, DRAWEAP_CENTER, accessPal); + } + else + { + G_DrawTileScaled(170 + (fix16_to_int(g_player[screenpeek].input->q16avel) >> 5) - (fix16_to_int(pSprite->q16look_ang) >> 1) + accessX, + accessY + 266 - (fix16_to_int(pSprite->q16horiz - pSprite->q16horizoff) >> 4), HANDHOLDINGACCESS, accessShade, + 4 + DRAWEAP_CENTER, accessPal); + } + + guniqhudid = 0; + + return 1; +} + +void P_DisplayWeapon(void) +{ + DukePlayer_t *const pPlayer = g_player[screenpeek].ps; + const uint8_t *const weaponFrame = &pPlayer->kickback_pic; + + int currentWeapon, quickKickFrame; + +#ifdef SPLITSCREEN_MOD_HACKS + g_snum = screenpeek; +#endif + + if (DEER) + { + switch (pPlayer->dhat61f) + { + case 0: + ghpistol_render(screenpeek); + break; + case 1: + ghrifle_render(screenpeek, 0); + break; + case 2: + ghrifle_render(screenpeek, 1); + break; + case 3: + ghshtgn_render(screenpeek); + break; + case 4: + ghbow_render(screenpeek); + break; + } + return; + } + + if (pPlayer->newowner >= 0 || ud.camerasprite >= 0 || (!RR && pPlayer->over_shoulder_on > 0) + || (sprite[pPlayer->i].pal != 1 && sprite[pPlayer->i].extra <= 0)) + return; + + int weaponX = (160) - 90; + int weaponY = klabs(fix16_to_int(pPlayer->q16look_ang)) / 9; + int weaponYOffset = 80 - (pPlayer->weapon_pos * pPlayer->weapon_pos); + int weaponShade = (RR && pPlayer->cursectnum >= 0 && g_shadedSector[pPlayer->cursectnum]) ? 16 : (sprite[pPlayer->i].shade <= 24 ? sprite[pPlayer->i].shade : 24); + + int32_t weaponBits = 0; + UNREFERENCED_PARAMETER(weaponBits); + + if (!RR && (P_DisplayFist(weaponShade) || P_DisplayKnuckles(weaponShade) || P_DisplayTip(weaponShade) || P_DisplayAccess(weaponShade))) + goto enddisplayweapon; + + if (!RR) + P_DisplayKnee(weaponShade); + + if (cl_weaponsway) + { + weaponX -= (sintable[((pPlayer->weapon_sway>>1)+512)&2047]/(1024+512)); + weaponYOffset -= (sprite[pPlayer->i].xrepeat < (RR ? 8 : 32)) ? klabs(sintable[(pPlayer->weapon_sway << 2) & 2047] >> 9) + : klabs(sintable[(pPlayer->weapon_sway >> 1) & 2047] >> 10); + } + else weaponYOffset -= 16; + + weaponX -= 58 + pPlayer->weapon_ang; + weaponYOffset -= (pPlayer->hard_landing << 3); + + if (WW2GI) + currentWeapon = PWEAPON(screenpeek, (pPlayer->last_weapon >= 0) ? pPlayer->last_weapon : pPlayer->curr_weapon, WorksLike); + else + currentWeapon = (pPlayer->last_weapon >= 0) ? pPlayer->last_weapon : pPlayer->curr_weapon; + hudweap.gunposy = weaponYOffset; + hudweap.lookhoriz = weaponY; + hudweap.cur = currentWeapon; + hudweap.gunposx = weaponX; + hudweap.shade = weaponShade; + hudweap.count = *weaponFrame; + hudweap.lookhalfang = fix16_to_int(pPlayer->q16look_ang) >> 1; + + quickKickFrame = 14 - pPlayer->quick_kick; + + if (!RR && (quickKickFrame != 14 || pPlayer->last_quick_kick) && r_drawweapon == 1) + { + int const weaponPal = P_GetKneePal(pPlayer); + + guniqhudid = 100; + + if (quickKickFrame < 6 || quickKickFrame > 12) + G_DrawTileScaled(weaponX + 80 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 250 - weaponYOffset, KNEE, weaponShade, + weaponBits | 4 | DRAWEAP_CENTER, weaponPal); + else + G_DrawTileScaled(weaponX + 160 - 16 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 214 - weaponYOffset, KNEE + 1, + weaponShade, weaponBits | 4 | DRAWEAP_CENTER, weaponPal); + guniqhudid = 0; + } + + if (RRRA) + { + if (pPlayer->on_motorcycle) + { + int motoTile = MOTOHIT; + if (!g_netServer && numplayers == 1) + { + if (*weaponFrame) + { + weaponShade = 0; + if (*weaponFrame == 1) + { + if ((krand2()&1) == 1) + motoTile = MOTOHIT+1; + else + motoTile = MOTOHIT+2; + } + else if (*weaponFrame == 4) + { + if ((krand2()&1) == 1) + motoTile = MOTOHIT+3; + else + motoTile = MOTOHIT+4; + } + } + } + else + { + if (*weaponFrame) + { + weaponShade = 0; + if (*weaponFrame >= 1 && *weaponFrame <= 4) + motoTile += *weaponFrame; + } + } + + int const weaponPal = P_GetHudPal(pPlayer); + + G_DrawTileScaled(160-(fix16_to_int(pPlayer->q16look_ang)>>1), 174, motoTile, weaponShade, 2 | DRAWEAP_CENTER, + weaponPal, 34816, pPlayer->tilt_status * 5 + (pPlayer->tilt_status < 0 ? 2047 : 0)); + return; + } + if (pPlayer->on_boat) + { + int boatTile; + if (pPlayer->tilt_status > 0) + { + if (*weaponFrame == 0) + boatTile = BOATHIT+1; + else if (*weaponFrame <= 3) + { + boatTile = BOATHIT+5; + weaponShade = -96; + } + else if (*weaponFrame <= 6) + { + boatTile = BOATHIT+6; + weaponShade = -96; + } + else + boatTile = BOATHIT+1; + } + else if (pPlayer->tilt_status < 0) + { + if (*weaponFrame == 0) + boatTile = BOATHIT+2; + else if (*weaponFrame <= 3) + { + boatTile = BOATHIT+7; + weaponShade = -96; + } + else if (*weaponFrame <= 6) + { + boatTile = BOATHIT+8; + weaponShade = -96; + } + else + boatTile = BOATHIT+2; + } + else + { + if (*weaponFrame == 0) + boatTile = BOATHIT; + else if (*weaponFrame <= 3) + { + boatTile = BOATHIT+3; + weaponShade = -96; + } + else if (*weaponFrame <= 6) + { + boatTile = BOATHIT+4; + weaponShade = -96; + } + else + boatTile = BOATHIT; + } + + int const weaponPal = P_GetHudPal(pPlayer); + int weaponY; + + if (pPlayer->not_on_water) + weaponY = 170; + else + weaponY = 170 + (*weaponFrame>>2); + + G_DrawTileScaled(160-(fix16_to_int(pPlayer->q16look_ang)>>1), weaponY, boatTile, weaponShade, 2 | DRAWEAP_CENTER, + weaponPal, 66048, pPlayer->tilt_status + (pPlayer->tilt_status < 0 ? 2047 : 0)); + return; + } + } + + if (sprite[pPlayer->i].xrepeat < (RR ? 8 : 40)) + { + static int32_t fistPos; + + int const weaponPal = P_GetHudPal(pPlayer); + + if (pPlayer->jetpack_on == 0) + { + int const playerXvel = sprite[pPlayer->i].xvel; + weaponY += 32 - (playerXvel >> 3); + fistPos += playerXvel >> 3; + } + + currentWeapon = weaponX; + weaponX += sintable[(fistPos)&2047] >> 10; + G_DrawTileScaled(weaponX + 250 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 258 - (klabs(sintable[(fistPos)&2047] >> 8)), + FIST, weaponShade, weaponBits, weaponPal); + weaponX = currentWeapon - (sintable[(fistPos)&2047] >> 10); + G_DrawTileScaled(weaponX + 40 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 200 + (klabs(sintable[(fistPos)&2047] >> 8)), FIST, + weaponShade, weaponBits | 4, weaponPal); + } + else + { + switch (r_drawweapon) + { + case 1: break; + case 2: + if ((unsigned)hudweap.cur < MAX_WEAPONS && hudweap.cur != KNEE_WEAPON) + rotatesprite_win(160 << 16, (180 + (pPlayer->weapon_pos * pPlayer->weapon_pos)) << 16, divscale16(ud.statusbarscale, 100), 0, + (!RR && hudweap.cur == GROW_WEAPON) ? GROWSPRITEICON : WeaponPickupSprites[hudweap.cur], 0, + 0, 2); + default: goto enddisplayweapon; + } + + if (!RR && currentWeapon == KNEE_WEAPON && *weaponFrame == 0) + goto enddisplayweapon; + + int const doAnim = !(sprite[pPlayer->i].pal == 1 || paused || g_player[myconnectindex].ps->gm & MODE_MENU); + int const halfLookAng = fix16_to_int(pPlayer->q16look_ang) >> 1; + + int const weaponPal = P_GetHudPal(pPlayer); + + if (RR) + { + switch (DYNAMICWEAPONMAP(currentWeapon)) + { + case KNEE_WEAPON__STATIC: + { + static int weaponFrames[] = { 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7 }; + static int offsetX[] = { 310,342,364,418,350,316,282,288,0,0 }; + static int offsetY[] = { 300,362,320,268,248,248,277,420,0,0 }; + weaponX = weaponX + ((offsetX[weaponFrames[*weaponFrame]]>>1) - 12); + weaponY = weaponY + 200 - (244-offsetY[weaponFrames[*weaponFrame]]); + guniqhudid = currentWeapon; + G_DrawTileScaled(weaponX - halfLookAng, weaponY - weaponYOffset, KNEE + weaponFrames[*weaponFrame], + weaponShade, weaponBits, weaponPal, 32768); + guniqhudid = 0; + break; + } + case SLINGBLADE_WEAPON__STATIC: + if (RRRA) + { + if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) + weaponBits |= 512; + static int weaponFrames[] = { 0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7 }; + static int offsetX[] = { 580,676,310,491,356,210,310,614 }; + static int offsetY[] = { 369,363,300,323,371,400,300,440 }; + weaponX = weaponX + ((offsetX[weaponFrames[*weaponFrame]]>>1) - 12); + weaponY = weaponY + 210 - (244-offsetY[weaponFrames[*weaponFrame]]); + guniqhudid = currentWeapon; + G_DrawTileScaled(weaponX - halfLookAng + 20, weaponY - weaponYOffset - 80, SLINGBLADE + weaponFrames[*weaponFrame], + weaponShade, weaponBits, weaponPal, 32768); + guniqhudid = 0; + break; + } + break; + + case TRIPBOMB_WEAPON__STATIC: + case BOWLINGBALL_WEAPON__STATIC: + weaponX += 8; + weaponYOffset -= 10; + + if (currentWeapon == BOWLINGBALL_WEAPON) + { + if (pPlayer->ammo_amount[BOWLINGBALL_WEAPON]) + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 162 - halfLookAng, weaponY + 214 - weaponYOffset + (*weaponFrame) * 8, BOWLINGBALLH, + weaponShade, weaponBits, weaponPal, 32768); + } + else + { + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 162 - halfLookAng, weaponY + 214 - weaponYOffset, HANDTHROW+5, + weaponShade, weaponBits, weaponPal, 36700); + } + } + else + { + if (pPlayer->ammo_amount[TRIPBOMB_WEAPON]) + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 180 - halfLookAng, weaponY + 214 - weaponYOffset + (*weaponFrame) * 8, POWDERH, + weaponShade, weaponBits, weaponPal, 36700); + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 90 - halfLookAng, weaponY + 214 - weaponYOffset + (*weaponFrame) * 8, POWDERH, + weaponShade, weaponBits | 4, weaponPal, 36700); + } + else + { + G_DrawWeaponTileWithID(currentWeapon << 2, weaponX + 162 - halfLookAng, weaponY + 214 - weaponYOffset, HANDTHROW+5, + weaponShade, weaponBits, weaponPal, 36700); + } + } + break; + + case RPG_WEAPON__STATIC: + { + if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) + weaponBits |= 512; + static int frames[] = { 0,1,1,2,2,3,2,3,2,3,2,2,2,2,2,2,2,2,2,4,4,4,4,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7 }; + int frame = frames[*weaponFrame]; + if (frame == 2 || frame == 3) + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 200 - halfLookAng, weaponY + 250 - weaponYOffset, + RPGGUN + frame, weaponShade, weaponBits, weaponPal, 36700); + } + else if (frame == 1) + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 200 - halfLookAng, weaponY + 250 - weaponYOffset, + RPGGUN + frame, 0, weaponBits, weaponPal, 36700); + } + else + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 210 - halfLookAng, weaponY + 255 - weaponYOffset, + RPGGUN + frame, weaponShade, weaponBits, weaponPal, 36700); + } + break; + } + + case CHICKEN_WEAPON__STATIC: + { + if (!RRRA) break; + if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) + weaponBits |= 512; + if (*weaponFrame) + { + static int frames[] = { 0,1,1,2,2,3,2,3,2,3,2,2,2,2,2,2,2,2,2,4,4,4,4,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7 }; + int frame = frames[*weaponFrame]; + if (frame == 2 || frame == 3) + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 200 - halfLookAng, weaponY + 250 - weaponYOffset, + RPGGUN2 + frame, weaponShade, weaponBits, weaponPal, 36700); + } + else if (frame == 1) + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 200 - halfLookAng, weaponY + 250 - weaponYOffset, + RPGGUN2 + frame, 0, weaponBits, weaponPal, 36700); + } + else + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 210 - halfLookAng, weaponY + 255 - weaponYOffset, + RPGGUN2 + frame, weaponShade, weaponBits, weaponPal, 36700); + } + } + else + { + if (!g_netServer && ud.multimode < 2) + { + if (g_chickenWeaponTimer) + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 210 - halfLookAng, weaponY + 222 - weaponYOffset, + RPGGUN2+7, weaponShade, weaponBits, weaponPal, 36700); + } + else if ((krand2() & 15) == 5) + { + A_PlaySound(327, pPlayer->i); + G_DrawWeaponTileWithID(currentWeapon, weaponX + 210 - halfLookAng, weaponY + 222 - weaponYOffset, + RPGGUN2+7, weaponShade, weaponBits, weaponPal, 36700); + g_chickenWeaponTimer = 6; + } + else + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 210 - halfLookAng, weaponY + 225 - weaponYOffset, + RPGGUN2, weaponShade, weaponBits, weaponPal, 36700); + } + + } + else + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 210 - halfLookAng, weaponY + 225 - weaponYOffset, + RPGGUN2, weaponShade, weaponBits, weaponPal, 36700); + } + } + break; + } + + case SHOTGUN_WEAPON__STATIC: + weaponX -= 8; + { + static int kb_frames3[] = { 0,0,1,1,2,2,5,5,6,6,7,7,8,8,0,0,0,0,0,0,0 }; + static int kb_frames2[] = { 0,0,3,3,4,4,5,5,6,6,7,7,8,8,0,0,20,20,21,21,21,21,20,20,20,20,0,0 }; + static int kb_frames[] = { 0,0,1,1,2,2,3,3,4,4,5,5,5,5,6,6,6,6,7,7,7,7,8,8,0,0,20,20,21,21,21,21,20,20,20,20,0,0 }; + static int kb_ox[] = { 300,300,300,300,300,330,320,310,305,306,302 }; + static int kb_oy[] = { 315,300,302,305,302,302,303,306,302,404,384 }; + if (pPlayer->shotgun_state[1]) + { + if (*weaponFrame < 26) + { + int frm = kb_frames[*weaponFrame]; + if (frm == 3 || frm == 4) + weaponShade = 0; + G_DrawWeaponTileWithID(currentWeapon, weaponX + 52 - halfLookAng + (kb_ox[frm] >> 1), + weaponY + kb_oy[frm] - 64 - weaponYOffset, SHOTGUN + frm, weaponShade, weaponBits, weaponPal, 32768); + } + else + { + int frm; + if (kb_frames[*weaponFrame] > 0) + frm = kb_frames[(*weaponFrame) - 11]; + else + frm = kb_frames[*weaponFrame]; + weaponX += (kb_ox[frm] >> 1) - 12; + weaponY += kb_oy[frm] - 64; + switch (*weaponFrame) + { + case 23: + weaponY += 60; + break; + case 24: + weaponY += 30; + break; + } + G_DrawWeaponTileWithID(currentWeapon, weaponX + 64 - halfLookAng, weaponY - weaponYOffset, + SHOTGUN + kb_frames[*weaponFrame], weaponShade, weaponBits, weaponPal, 32768); + if (kb_frames[*weaponFrame] == 21) + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 96 - halfLookAng, weaponY - weaponYOffset, + SHOTGUNSHELLS, weaponShade, weaponBits, weaponPal, 32768); + } + } + else + { + if ((*weaponFrame) < 16) + { + if (pPlayer->shotgun_state[0]) + { + int frm = kb_frames2[*weaponFrame]; + if (frm == 3 || frm == 4) + weaponShade = 0; + G_DrawWeaponTileWithID(currentWeapon, weaponX + 52 - halfLookAng + (kb_ox[frm] >> 1), + weaponY + kb_oy[frm] - 64 - weaponYOffset, SHOTGUN + frm, weaponShade, weaponBits, weaponPal, 32768); + } + else + { + int frm = kb_frames3[*weaponFrame]; + if (frm == 1 || frm == 2) + weaponShade = 0; + G_DrawWeaponTileWithID(currentWeapon, weaponX + 52 - halfLookAng + (kb_ox[frm] >> 1), + weaponY + kb_oy[frm] - 64 - weaponYOffset, SHOTGUN + frm, weaponShade, weaponBits, weaponPal, 32768); + } + } + else if (pPlayer->shotgun_state[0]) + { + int frm; + if (kb_frames2[*weaponFrame] > 0) + frm = kb_frames2[(*weaponFrame) - 11]; + else + frm = kb_frames2[*weaponFrame]; + weaponX += (kb_ox[frm] >> 1) - 12; + weaponY += kb_oy[frm] - 64; + switch (*weaponFrame) + { + case 23: + weaponY += 60; + break; + case 24: + weaponY += 30; + break; + } + G_DrawWeaponTileWithID(currentWeapon, weaponX + 64 - halfLookAng, weaponY - weaponYOffset, + SHOTGUN + kb_frames2[*weaponFrame], weaponShade, weaponBits, weaponPal, 32768); + if (kb_frames2[*weaponFrame] == 21) + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 96 - halfLookAng, weaponY - weaponYOffset, + SHOTGUNSHELLS, weaponShade, weaponBits, weaponPal, 32768); + } + } + } + break; + + case CHAINGUN_WEAPON__STATIC: + if (*weaponFrame > 0) + { + weaponYOffset -= sintable[(*weaponFrame)<<7]>>12; + + if (doAnim) + weaponX += 1-(rand()&3); + } + + switch (*weaponFrame) + { + case 0: + G_DrawWeaponTileWithID(currentWeapon, weaponX + 178 - (fix16_to_int(pPlayer->q16look_ang) >> 1) + 30, weaponY + 233 - weaponYOffset + 5, + CHAINGUN, weaponShade, weaponBits, weaponPal, 32768); + break; + + default: + if (*weaponFrame < 8) + G_DrawWeaponTileWithID(currentWeapon, weaponX + 178 - (fix16_to_int(pPlayer->q16look_ang) >> 1) + 30, weaponY + 233 - weaponYOffset + 5, + CHAINGUN + 1, 0, weaponBits, weaponPal, 32768); + else + G_DrawWeaponTileWithID(currentWeapon, weaponX + 178 - (fix16_to_int(pPlayer->q16look_ang) >> 1) + 30, weaponY + 233 - weaponYOffset + 5, + CHAINGUN + 2, weaponShade, weaponBits, weaponPal, 32768); + + break; + } + break; + + case PISTOL_WEAPON__STATIC: + if ((*weaponFrame) < 22) + { + static int frames[] = { 0,0,1,1,2,2,3,3,4,4,6,6,6,6,5,5,4,4,3,3,0,0 }; + static int offsetX[] = { 194,190,185,208,215,215,216,216,201,170 }; + static int offsetY[] = { 256,249,248,238,228,218,208,256,245,258 }; + int frame = frames[*weaponFrame]; + + if (frame) + weaponShade = 0; + + G_DrawWeaponTileWithID(currentWeapon, offsetX[frame] - 12 + weaponX - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + offsetY[frame] - weaponYOffset, + FIRSTGUN + frame, weaponShade, weaponBits, weaponPal, 36700); + + break; + } + else + { + static int frames[] = { 0,0,1,1,2,2,2,2,2,2,2,2,2,2,2,1,1,0,0 }; + static int offsetX[] = { 244,244,244 }; + static int offsetY[] = { 256,249,248 }; + int dx, dy; + int frame = frames[(*weaponFrame) - 22]; + switch (*weaponFrame) + { + case 28: + dy = 10; + dx = 5; + break; + case 29: + dy = 20; + dx = 10; + break; + case 30: + dy = 30; + dx = 15; + break; + case 31: + dy = 40; + dx = 20; + break; + case 32: + dy = 50; + dx = 25; + break; + case 33: + dy = 40; + dx = 20; + break; + case 34: + dy = 30; + dx = 15; + break; + case 35: + dy = 20; + dx = 10; + break; + case 36: + dy = 10; + dx = 5; + break; + default: + dy = 0; + dx = 0; + break; + } + + G_DrawWeaponTileWithID(currentWeapon, weaponX + offsetX[frame] - 12 - dx - halfLookAng, weaponY + offsetY[frame] - weaponYOffset + dy, + FIRSTGUNRELOAD + frame, weaponShade, weaponBits, weaponPal, 36700); + } + break; + + case HANDBOMB_WEAPON__STATIC: + weaponYOffset -= 9 * (*weaponFrame); + G_DrawWeaponTileWithID(currentWeapon, weaponX + 190 - halfLookAng, weaponY + 260 - weaponYOffset, + HANDTHROW, weaponShade, weaponBits, weaponPal, 36700); + break; + + case HANDREMOTE_WEAPON__STATIC: + if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) + weaponBits |= 512; + + if(*weaponFrame < 20) + { + static uint8_t remoteFrames[] = { 1,1,1,1,1,2,2,2,2,3,3,3,4,4,4,5,5,5,5,5,6,6,6 }; + + if (*weaponFrame >= ARRAY_SIZE(remoteFrames)) + break; + + if (*weaponFrame < 5) + { + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 265 - halfLookAng, weaponY + 174 - weaponYOffset + pPlayer->hbomb_offset, + RRTILE1752, 0, weaponBits, weaponPal, 36700); + } + G_DrawWeaponTileWithID(currentWeapon, weaponX + 290 - halfLookAng, weaponY + 238 - weaponYOffset, + HANDTHROW + remoteFrames[(*weaponFrame)], 0, weaponBits, weaponPal, 36700); + } + break; + + case DEVISTATOR_WEAPON__STATIC: + if (*weaponFrame) + G_DrawWeaponTileWithID(currentWeapon, 150 + (weaponX >> 1) - halfLookAng, 266 + (weaponY >> 1) - weaponYOffset, + DEVISTATOR, 0, weaponBits, weaponPal, 47040); + else + G_DrawWeaponTileWithID(currentWeapon, 150 + (weaponX >> 1) - halfLookAng, 266 + (weaponY >> 1) - weaponYOffset, + DEVISTATOR + 1, weaponShade, weaponBits, weaponPal, 47040); + break; + + case FREEZE_WEAPON__STATIC: + if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) + weaponBits |= 512; + + if ((*weaponFrame) > 0) + { + static uint8_t freezerFrames[] = { 0,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }; + + G_DrawWeaponTileWithID(currentWeapon, weaponX + 260 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 215 - weaponYOffset, + FREEZE + freezerFrames[*weaponFrame], -32, weaponBits, weaponPal, 32768); + } + else + G_DrawWeaponTileWithID(currentWeapon, weaponX + 260 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 215 - weaponYOffset, + FREEZE, weaponShade, weaponBits, weaponPal, 32768); + break; + + case GROW_WEAPON__STATIC: + case SHRINKER_WEAPON__STATIC: + weaponX += 28; + weaponY += 18; + + if ((*weaponFrame) > 0) + { + if (doAnim) + { + weaponX += rand() & 3; + weaponYOffset += (rand() & 3); + } + + if (currentWeapon == GROW_WEAPON) + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 184 - halfLookAng, weaponY + 240 - weaponYOffset, + GROWSPARK + ((*weaponFrame)&2), weaponShade, weaponBits, 0, 44040); + } + else + { + static int frames[] = { 1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,0,0,0,0,0,0,0,0,0,0 }; + G_DrawWeaponTileWithID(currentWeapon, weaponX + 184 - halfLookAng, weaponY + 240 - weaponYOffset, + SHRINKER + frames[*weaponFrame], weaponShade, weaponBits, 0, 44040); + } + } + else + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 188 - halfLookAng, weaponY + 240 - weaponYOffset, + SHRINKER, weaponShade, weaponBits, weaponPal, 44040); + } + break; + } + } + else + { + switch (DYNAMICWEAPONMAP(currentWeapon)) + { + case KNEE_WEAPON__STATIC: + { + int const kneePal = P_GetKneePal(pPlayer, weaponPal); + + guniqhudid = currentWeapon; + if (*weaponFrame < 5 || *weaponFrame > 9) + G_DrawTileScaled(weaponX + 220 - halfLookAng, weaponY + 250 - weaponYOffset, KNEE, + weaponShade, weaponBits, kneePal); + else + G_DrawTileScaled(weaponX + 160 - halfLookAng, weaponY + 214 - weaponYOffset, KNEE + 1, + weaponShade, weaponBits, kneePal); + guniqhudid = 0; + break; + } + + case TRIPBOMB_WEAPON__STATIC: + weaponX += 8; + weaponYOffset -= 10; + + if ((*weaponFrame) > 6) + weaponY += ((*weaponFrame) << 3); + else if ((*weaponFrame) < 4) + G_DrawWeaponTileWithID(currentWeapon << 2, weaponX + 142 - halfLookAng, + weaponY + 234 - weaponYOffset, HANDHOLDINGLASER + 3, weaponShade, weaponBits, weaponPal); + + G_DrawWeaponTileWithID(currentWeapon, weaponX + 130 - halfLookAng, weaponY + 249 - weaponYOffset, + HANDHOLDINGLASER + ((*weaponFrame) >> 2), weaponShade, weaponBits, weaponPal); + + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 152 - halfLookAng, + weaponY + 249 - weaponYOffset, HANDHOLDINGLASER + ((*weaponFrame) >> 2), weaponShade, weaponBits | 4, + weaponPal); + break; + + case RPG_WEAPON__STATIC: + weaponX -= sintable[(768 + ((*weaponFrame) << 7)) & 2047] >> 11; + weaponYOffset += sintable[(768 + ((*weaponFrame) << 7)) & 2047] >> 11; + + if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING)) + weaponBits |= 512; + + if (*weaponFrame > 0) + { + int totalTime; + if (*weaponFrame < (WW2GI ? (totalTime = PWEAPON(screenpeek, pPlayer->curr_weapon, TotalTime)) : 8)) + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 164, (weaponY << 1) + 176 - weaponYOffset, + RPGGUN + ((*weaponFrame) >> 1), weaponShade, weaponBits, weaponPal); + else if (WW2GI) + { + totalTime = PWEAPON(screenpeek, pPlayer->curr_weapon, TotalTime); + int const reloadTime = PWEAPON(screenpeek, pPlayer->curr_weapon, Reload); + + weaponYOffset -= (*weaponFrame < ((reloadTime - totalTime) / 2 + totalTime)) + ? 10 * ((*weaponFrame) - totalTime) // down + : 10 * (reloadTime - (*weaponFrame)); // up + } + } + + G_DrawWeaponTileWithID(currentWeapon, weaponX + 164, (weaponY << 1) + 176 - weaponYOffset, RPGGUN, weaponShade, + weaponBits, weaponPal); + break; + + case SHOTGUN_WEAPON__STATIC: + weaponX -= 8; + + if (WW2GI) + { + int const totalTime = PWEAPON(screenpeek, pPlayer->curr_weapon, TotalTime); + int const reloadTime = PWEAPON(screenpeek, pPlayer->curr_weapon, Reload); + + if (*weaponFrame > 0) + weaponYOffset -= sintable[(*weaponFrame)<<7]>>12; + + if (*weaponFrame > 0 && doAnim) + weaponX += 1-(rand()&3); + + if (*weaponFrame == 0) + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 146 - halfLookAng, weaponY + 202 - weaponYOffset, + SHOTGUN, weaponShade, weaponBits, weaponPal); + } + else if (*weaponFrame <= totalTime) + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 146 - halfLookAng, weaponY + 202 - weaponYOffset, + SHOTGUN + 1, weaponShade, weaponBits, weaponPal); + } + // else we are in 'reload time' + else + { + weaponYOffset -= (*weaponFrame < ((reloadTime - totalTime) / 2 + totalTime)) + ? 10 * ((*weaponFrame) - totalTime) // D + : 10 * (reloadTime - (*weaponFrame)); // U + + G_DrawWeaponTileWithID(currentWeapon, weaponX + 146 - halfLookAng, weaponY + 202 - weaponYOffset, + SHOTGUN, weaponShade, weaponBits, weaponPal); + } + + break; + } + + switch (*weaponFrame) + { + case 1: + case 2: + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 168 - halfLookAng, weaponY + 201 - weaponYOffset, + SHOTGUN + 2, -128, weaponBits, weaponPal); + fallthrough__; + case 0: + case 6: + case 7: + case 8: + G_DrawWeaponTileWithID(currentWeapon, weaponX + 146 - halfLookAng, weaponY + 202 - weaponYOffset, + SHOTGUN, weaponShade, weaponBits, weaponPal); + break; + + case 3: + case 4: + weaponYOffset -= 40; + weaponX += 20; + + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 178 - halfLookAng, weaponY + 194 - weaponYOffset, + SHOTGUN + 1 + ((*(weaponFrame)-1) >> 1), -128, weaponBits, weaponPal); + fallthrough__; + case 5: + case 9: + case 10: + case 11: + case 12: + G_DrawWeaponTileWithID(currentWeapon, weaponX + 158 - halfLookAng, weaponY + 220 - weaponYOffset, + SHOTGUN + 3, weaponShade, weaponBits, weaponPal); + break; + + case 13: + case 14: + case 15: + G_DrawWeaponTileWithID(currentWeapon, 32 + weaponX + 166 - halfLookAng, weaponY + 210 - weaponYOffset, + SHOTGUN + 4, weaponShade, weaponBits, weaponPal); + break; + + case 16: + case 17: + case 18: + case 19: + case 24: + case 25: + case 26: + case 27: + G_DrawWeaponTileWithID(currentWeapon, 64 + weaponX + 170 - halfLookAng, weaponY + 196 - weaponYOffset, + SHOTGUN + 5, weaponShade, weaponBits, weaponPal); + break; + + case 20: + case 21: + case 22: + case 23: + G_DrawWeaponTileWithID(currentWeapon, 64 + weaponX + 176 - halfLookAng, weaponY + 196 - weaponYOffset, + SHOTGUN + 6, weaponShade, weaponBits, weaponPal); + break; + + + case 28: + case 29: + case 30: + G_DrawWeaponTileWithID(currentWeapon, 32 + weaponX + 156 - halfLookAng, weaponY + 206 - weaponYOffset, + SHOTGUN + 4, weaponShade, weaponBits, weaponPal); + break; + } + break; + + case CHAINGUN_WEAPON__STATIC: + if (*weaponFrame > 0) + { + weaponYOffset -= sintable[(*weaponFrame)<<7]>>12; + + if (doAnim) + weaponX += 1-(rand()&3); + } + + if (WW2GI) + { + int const totalTime = PWEAPON(screenpeek, pPlayer->curr_weapon, TotalTime); + int const reloadTime = PWEAPON(screenpeek, pPlayer->curr_weapon, Reload); + + if (*weaponFrame == 0) + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 178 - halfLookAng,weaponY+233-weaponYOffset, + CHAINGUN+1,weaponShade,weaponBits,weaponPal); + } + else if (*weaponFrame <= totalTime) + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 188 - halfLookAng,weaponY+243-weaponYOffset, + CHAINGUN+2,weaponShade,weaponBits,weaponPal); + } + // else we are in 'reload time' + // divide reload time into fifths.. + // 1) move weapon up/right, hand on clip (CHAINGUN - 17) + // 2) move weapon up/right, hand removing clip (CHAINGUN - 18) + // 3) hold weapon up/right, hand removed clip (CHAINGUN - 19) + // 4) hold weapon up/right, hand inserting clip (CHAINGUN - 18) + // 5) move weapon down/left, clip inserted (CHAINGUN - 17) + else + { + int iFifths = (reloadTime - totalTime) / 5; + if (iFifths < 1) + iFifths = 1; + + if (*weaponFrame < iFifths + totalTime) + { + // first segment + int const weaponOffset = 80 - 10 * (totalTime + iFifths - (*weaponFrame)); + weaponYOffset += weaponOffset; + weaponX += weaponOffset; + G_DrawWeaponTileWithID(currentWeapon, weaponX + 168 - halfLookAng, weaponY + 260 - weaponYOffset, CHAINGUN - 17, + weaponShade, weaponBits, weaponPal); + } + else if (*weaponFrame < (iFifths * 2 + totalTime)) + { + // second segment + weaponYOffset += 80; // D + weaponX += 80; + G_DrawWeaponTileWithID(currentWeapon, weaponX + 168 - halfLookAng, weaponY + 260 - weaponYOffset, CHAINGUN - 18, + weaponShade, weaponBits, weaponPal); + } + else if (*weaponFrame < (iFifths * 3 + totalTime)) + { + // third segment + // up + weaponYOffset += 80; + weaponX += 80; + G_DrawWeaponTileWithID(currentWeapon, weaponX + 168 - halfLookAng, weaponY + 260 - weaponYOffset, CHAINGUN - 19, + weaponShade, weaponBits, weaponPal); + } + else if (*weaponFrame < (iFifths * 4 + totalTime)) + { + // fourth segment + // down + weaponYOffset += 80; // D + weaponX += 80; + G_DrawWeaponTileWithID(currentWeapon, weaponX + 168 - halfLookAng, weaponY + 260 - weaponYOffset, CHAINGUN - 18, + weaponShade, weaponBits, weaponPal); + } + else + { + // up and left + int const weaponOffset = 10 * (reloadTime - (*weaponFrame)); + weaponYOffset += weaponOffset; // U + weaponX += weaponOffset; + G_DrawWeaponTileWithID(currentWeapon, weaponX + 168 - halfLookAng, weaponY + 260 - weaponYOffset, CHAINGUN - 17, + weaponShade, weaponBits, weaponPal); + } + } + + break; + } + + switch (*weaponFrame) + { + case 0: + G_DrawWeaponTileWithID(currentWeapon, weaponX + 178 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 233 - weaponYOffset, + CHAINGUN + 1, weaponShade, weaponBits, weaponPal); + break; + + default: + if (*weaponFrame > 4 && *weaponFrame < 12) + { + int randomOffset = doAnim ? rand()&7 : 0; + G_DrawWeaponTileWithID(currentWeapon << 2, randomOffset + weaponX - 4 + 140 - (fix16_to_int(pPlayer->q16look_ang) >> 1), + randomOffset + weaponY - ((*weaponFrame) >> 1) + 208 - weaponYOffset, + CHAINGUN + 5 + ((*weaponFrame - 4) / 5), weaponShade, weaponBits, weaponPal); + if (doAnim) randomOffset = rand()&7; + G_DrawWeaponTileWithID(currentWeapon << 2, randomOffset + weaponX - 4 + 184 - (fix16_to_int(pPlayer->q16look_ang) >> 1), + randomOffset + weaponY - ((*weaponFrame) >> 1) + 208 - weaponYOffset, + CHAINGUN + 5 + ((*weaponFrame - 4) / 5), weaponShade, weaponBits, weaponPal); + } + + if (*weaponFrame < 8) + { + int const randomOffset = doAnim ? rand()&7 : 0; + G_DrawWeaponTileWithID(currentWeapon << 2, randomOffset + weaponX - 4 + 162 - (fix16_to_int(pPlayer->q16look_ang) >> 1), + randomOffset + weaponY - ((*weaponFrame) >> 1) + 208 - weaponYOffset, + CHAINGUN + 5 + ((*weaponFrame - 2) / 5), weaponShade, weaponBits, weaponPal); + G_DrawWeaponTileWithID(currentWeapon, weaponX + 178 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 233 - weaponYOffset, + CHAINGUN + 1 + ((*weaponFrame) >> 1), weaponShade, weaponBits, weaponPal); + } + else + G_DrawWeaponTileWithID(currentWeapon, weaponX + 178 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 233 - weaponYOffset, + CHAINGUN + 1, weaponShade, weaponBits, weaponPal); + + break; + } + + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 168 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 260 - weaponYOffset, + CHAINGUN, weaponShade, weaponBits, weaponPal); + break; + + case PISTOL_WEAPON__STATIC: + if ((*weaponFrame) < 5) + { + static uint8_t pistolFrames[] = { 0, 1, 2 }; + int pistolOffset = 195-12+weaponX; + + if ((*weaponFrame) == 2) + pistolOffset -= 3; + + G_DrawWeaponTileWithID(currentWeapon, (pistolOffset - (fix16_to_int(pPlayer->q16look_ang) >> 1)), (weaponY + 244 - weaponYOffset), + FIRSTGUN + pistolFrames[*weaponFrame > 2 ? 0 : *weaponFrame], weaponShade, 2, + weaponPal); + + break; + } + + if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING) && DUKE) + weaponBits |= 512; + + if ((*weaponFrame) < 10) + G_DrawWeaponTileWithID(currentWeapon, 194 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 230 - weaponYOffset, FIRSTGUN + 4, + weaponShade, weaponBits, weaponPal); + else if ((*weaponFrame) < 15) + { + G_DrawWeaponTileWithID(currentWeapon << 1, 244 - ((*weaponFrame) << 3) - (fix16_to_int(pPlayer->q16look_ang) >> 1), + weaponY + 130 - weaponYOffset + ((*weaponFrame) << 4), FIRSTGUN + 6, weaponShade, + weaponBits, weaponPal); + G_DrawWeaponTileWithID(currentWeapon, 224 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 220 - weaponYOffset, FIRSTGUN + 5, + weaponShade, weaponBits, weaponPal); + } + else if ((*weaponFrame) < 20) + { + G_DrawWeaponTileWithID(currentWeapon << 1, 124 + ((*weaponFrame) << 1) - (fix16_to_int(pPlayer->q16look_ang) >> 1), + weaponY + 430 - weaponYOffset - ((*weaponFrame) << 3), FIRSTGUN + 6, weaponShade, + weaponBits, weaponPal); + G_DrawWeaponTileWithID(currentWeapon, 224 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 220 - weaponYOffset, FIRSTGUN + 5, + weaponShade, weaponBits, weaponPal); + } + + else if ((*weaponFrame) < (WW2GI ? PWEAPON(screenpeek, PISTOL_WEAPON, Reload) - 12 : (NAM ? 38 : 23))) + { + G_DrawWeaponTileWithID(currentWeapon << 2, 184 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 235 - weaponYOffset, + FIRSTGUN + 8, weaponShade, weaponBits, weaponPal); + G_DrawWeaponTileWithID(currentWeapon, 224 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 210 - weaponYOffset, FIRSTGUN + 5, + weaponShade, weaponBits, weaponPal); + } + else if ((*weaponFrame) < (WW2GI ? PWEAPON(screenpeek, PISTOL_WEAPON, Reload) - 6 : (NAM ? 44 : 25))) + { + G_DrawWeaponTileWithID(currentWeapon << 2, 164 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 245 - weaponYOffset, + FIRSTGUN + 8, weaponShade, weaponBits, weaponPal); + G_DrawWeaponTileWithID(currentWeapon, 224 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 220 - weaponYOffset, FIRSTGUN + 5, + weaponShade, weaponBits, weaponPal); + } + else if ((*weaponFrame) < (WW2GI ? PWEAPON(screenpeek, PISTOL_WEAPON, Reload) : (NAM ? 50 : 27))) + G_DrawWeaponTileWithID(currentWeapon, 194 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 235 - weaponYOffset, FIRSTGUN + 5, + weaponShade, weaponBits, weaponPal); + + break; + + case HANDBOMB_WEAPON__STATIC: + { + static uint8_t pipebombFrames [] = { 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2 }; + + if (*weaponFrame >= ARRAY_SIZE(pipebombFrames)) + break; + + if (WW2GI && *weaponFrame >= PWEAPON(screenpeek, pPlayer->curr_weapon, TotalTime)) + break; + + if (*weaponFrame) + { + if (WW2GI) + { + int const fireDelay = PWEAPON(screenpeek, pPlayer->curr_weapon, FireDelay); + int const totalTime = PWEAPON(screenpeek, pPlayer->curr_weapon, TotalTime); + + if (*weaponFrame <= fireDelay) + { + // it holds here + weaponYOffset -= 5 * (*weaponFrame); // D + } + else if (*weaponFrame < ((totalTime - fireDelay) / 2 + fireDelay)) + { + // up and left + int const weaponOffset = (*weaponFrame) - fireDelay; + weaponYOffset += 10 * weaponOffset; // U + weaponX += 80 * weaponOffset; + } + else if (*weaponFrame < totalTime) + { + // start high + weaponYOffset += 240; + weaponYOffset -= 12 * ((*weaponFrame) - fireDelay); // D + // move left + weaponX += 90 - 5 * (totalTime - (*weaponFrame)); + } + } + else + { + if (*weaponFrame < 7) weaponYOffset -= 10 * (*weaponFrame); // D + else if (*weaponFrame < 12) weaponYOffset += 20 * ((*weaponFrame) - 10); // U + else if (*weaponFrame < 20) weaponYOffset -= 9 * ((*weaponFrame) - 14); // D + + weaponYOffset += 10; + } + } + + G_DrawWeaponTileWithID(currentWeapon, weaponX + 190 - halfLookAng, weaponY + 260 - weaponYOffset, + HANDTHROW + pipebombFrames[(*weaponFrame)], weaponShade, weaponBits, weaponPal); + } + break; + + case HANDREMOTE_WEAPON__STATIC: + { + static uint8_t remoteFrames[] = { 0, 1, 1, 2, 1, 1, 0, 0, 0, 0, 0 }; + + if (*weaponFrame >= ARRAY_SIZE(remoteFrames)) + break; + + weaponX = -48; + G_DrawWeaponTileWithID(currentWeapon, weaponX + 150 - halfLookAng, weaponY + 258 - weaponYOffset, + HANDREMOTE + remoteFrames[(*weaponFrame)], weaponShade, weaponBits, weaponPal); + } + break; + + case DEVISTATOR_WEAPON__STATIC: + if (WW2GI) + { + if (*weaponFrame) + { + int32_t const totalTime = PWEAPON(screenpeek, pPlayer->curr_weapon, TotalTime); + int32_t const reloadTime = PWEAPON(screenpeek, pPlayer->curr_weapon, Reload); + + if (*weaponFrame < totalTime) + { + int const tileOffset = ksgn((*weaponFrame) >> 2); + + if (pPlayer->ammo_amount[pPlayer->curr_weapon] & 1) + { + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 30 - halfLookAng, weaponY + 240 - weaponYOffset, + DEVISTATOR, weaponShade, weaponBits | 4, weaponPal); + G_DrawWeaponTileWithID(currentWeapon, weaponX + 268 - halfLookAng, weaponY + 238 - weaponYOffset, + DEVISTATOR + tileOffset, -32, weaponBits, weaponPal); + } + else + { + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 30 - halfLookAng, weaponY + 240 - weaponYOffset, + DEVISTATOR + tileOffset, -32, weaponBits | 4, weaponPal); + G_DrawWeaponTileWithID(currentWeapon, weaponX + 268 - halfLookAng, weaponY + 238 - weaponYOffset, DEVISTATOR, + weaponShade, weaponBits, weaponPal); + } + } + // else we are in 'reload time' + else + { + weaponYOffset -= (*weaponFrame < ((reloadTime - totalTime) / 2 + totalTime)) + ? 10 * ((*weaponFrame) - totalTime) + : 10 * (reloadTime - (*weaponFrame)); + + G_DrawWeaponTileWithID(currentWeapon, weaponX + 268 - halfLookAng, weaponY + 238 - weaponYOffset, DEVISTATOR, + weaponShade, weaponBits, weaponPal); + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 30 - halfLookAng, weaponY + 240 - weaponYOffset, DEVISTATOR, + weaponShade, weaponBits | 4, weaponPal); + } + } + else + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 268 - halfLookAng, weaponY + 238 - weaponYOffset, DEVISTATOR, + weaponShade, weaponBits, weaponPal); + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 30 - halfLookAng, weaponY + 240 - weaponYOffset, DEVISTATOR, + weaponShade, weaponBits | 4, weaponPal); + } + break; + } + + if (*weaponFrame > 0) + { + static uint8_t const devastatorFrames[] = { 0, 4, 12, 24, 12, 4, 0 }; + + if (*weaponFrame >= ARRAY_SIZE(devastatorFrames)) + break; + + int const tileOffset = ksgn((*weaponFrame) >> 2); + + if (pPlayer->hbomb_hold_delay) + { + G_DrawWeaponTileWithID(currentWeapon, (devastatorFrames[*weaponFrame] >> 1) + weaponX + 268 - halfLookAng, + devastatorFrames[*weaponFrame] + weaponY + 238 - weaponYOffset, + DEVISTATOR + tileOffset, -32, weaponBits, weaponPal); + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 30 - halfLookAng, weaponY + 240 - weaponYOffset, DEVISTATOR, + weaponShade, weaponBits | 4, weaponPal); + } + else + { + G_DrawWeaponTileWithID(currentWeapon << 1, -(devastatorFrames[*weaponFrame] >> 1) + weaponX + 30 - halfLookAng, + devastatorFrames[*weaponFrame] + weaponY + 240 - weaponYOffset, + DEVISTATOR + tileOffset, -32, weaponBits | 4, weaponPal); + G_DrawWeaponTileWithID(currentWeapon, weaponX + 268 - halfLookAng, weaponY + 238 - weaponYOffset, DEVISTATOR, + weaponShade, weaponBits, weaponPal); + } + } + else + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 268 - halfLookAng, weaponY + 238 - weaponYOffset, DEVISTATOR, weaponShade, + weaponBits, weaponPal); + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 30 - halfLookAng, weaponY + 240 - weaponYOffset, DEVISTATOR, + weaponShade, weaponBits | 4, weaponPal); + } + break; + + case FREEZE_WEAPON__STATIC: + if (!(duke3d_globalflags & DUKE3D_NO_WIDESCREEN_PINNING) && DUKE) + weaponBits |= 512; + + if ((*weaponFrame) > 0) + { + static uint8_t freezerFrames[] = { 0, 0, 1, 1, 2, 2 }; + + if (*weaponFrame % 6 >= ARRAY_SIZE(freezerFrames)) + break; + + if (doAnim) + { + weaponX += rand() & 3; + weaponY += rand() & 3; + } + weaponYOffset -= 16; + G_DrawWeaponTileWithID(currentWeapon << 1, weaponX + 210 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 261 - weaponYOffset, + FREEZE + 2, -32, weaponBits, weaponPal); + G_DrawWeaponTileWithID(currentWeapon, weaponX + 210 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 235 - weaponYOffset, + FREEZE + 3 + freezerFrames[*weaponFrame % 6], -32, weaponBits, weaponPal); + } + else + G_DrawWeaponTileWithID(currentWeapon, weaponX + 210 - (fix16_to_int(pPlayer->q16look_ang) >> 1), weaponY + 261 - weaponYOffset, + FREEZE, weaponShade, weaponBits, weaponPal); + break; + + case GROW_WEAPON__STATIC: + case SHRINKER_WEAPON__STATIC: + weaponX += 28; + weaponY += 18; + + if (WW2GI) + { + if (*weaponFrame == 0) + { + // the 'at rest' display + if (currentWeapon == GROW_WEAPON) + { + G_DrawWeaponTileWithID(currentWeapon, weaponX + 188 - halfLookAng, weaponY + 240 - weaponYOffset, SHRINKER - 2, + weaponShade, weaponBits, weaponPal); + break; + } + else if (pPlayer->ammo_amount[currentWeapon] > 0) + { + G_DrawWeaponTileUnfadedWithID(currentWeapon << 1, weaponX + 184 - halfLookAng, weaponY + 240 - weaponYOffset, SHRINKER + 2, + 16 - (sintable[pPlayer->random_club_frame & 2047] >> 10), weaponBits, 0); + G_DrawWeaponTileWithID(currentWeapon, weaponX + 188 - halfLookAng, weaponY + 240 - weaponYOffset, SHRINKER, + weaponShade, weaponBits, weaponPal); + break; + } + } + else + { + // the 'active' display. + if (doAnim) + { + weaponX += rand() & 3; + weaponYOffset += rand() & 3; + } + + int const totalTime = PWEAPON(screenpeek, pPlayer->curr_weapon, TotalTime); + int const reloadTime = PWEAPON(screenpeek, pPlayer->curr_weapon, Reload); + + if (*weaponFrame < totalTime) + { + if (*weaponFrame >= PWEAPON(screenpeek, pPlayer->curr_weapon, FireDelay)) + { + // after fire time. + // lower weapon to reload cartridge (not clip) + weaponYOffset -= (currentWeapon == GROW_WEAPON ? 15 : 10) * (totalTime - (*weaponFrame)); + } + } + // else we are in 'reload time' + else + { + weaponYOffset -= (*weaponFrame < ((reloadTime - totalTime) / 2 + totalTime)) + ? (currentWeapon == GROW_WEAPON ? 5 : 10) * ((*weaponFrame) - totalTime) // D + : 10 * (reloadTime - (*weaponFrame)); // U + } + } + + G_DrawWeaponTileUnfadedWithID(currentWeapon << 1, weaponX + 184 - halfLookAng, weaponY + 240 - weaponYOffset, + SHRINKER + 3 + ((*weaponFrame) & 3), -32, weaponBits, currentWeapon == GROW_WEAPON ? 2 : 0); + + G_DrawWeaponTileWithID(currentWeapon, weaponX + 188 - halfLookAng, weaponY + 240 - weaponYOffset, + SHRINKER + (currentWeapon == GROW_WEAPON ? -1 : 1), weaponShade, weaponBits, weaponPal); + + break; + } + + if ((*weaponFrame) > 0) + { + if (doAnim) + { + weaponX += rand() & 3; + weaponYOffset += (rand() & 3); + } + + G_DrawWeaponTileUnfadedWithID(currentWeapon << 1, weaponX + 184 - halfLookAng, weaponY + 240 - weaponYOffset, + SHRINKER + 3 + ((*weaponFrame) & 3), -32, weaponBits, currentWeapon == GROW_WEAPON ? 2 : 0); + G_DrawWeaponTileWithID(currentWeapon, weaponX + 188 - halfLookAng, weaponY + 240 - weaponYOffset, + currentWeapon == GROW_WEAPON ? SHRINKER - 1 : SHRINKER + 1, weaponShade, weaponBits, weaponPal); + } + else + { + G_DrawWeaponTileUnfadedWithID(currentWeapon << 1, weaponX + 184 - halfLookAng, weaponY + 240 - weaponYOffset, + SHRINKER + 2, 16 - (sintable[pPlayer->random_club_frame & 2047] >> 10), weaponBits, + currentWeapon == GROW_WEAPON ? 2 : 0); + G_DrawWeaponTileWithID(currentWeapon, weaponX + 188 - halfLookAng, weaponY + 240 - weaponYOffset, + currentWeapon == GROW_WEAPON ? SHRINKER - 2 : SHRINKER, weaponShade, weaponBits, weaponPal); + } + break; + } + } + } + +enddisplayweapon: + if (!RR) + P_DisplaySpit(); +} + +#define TURBOTURNTIME (TICRATE/8) // 7 +#define NORMALTURN 15 +#define PREAMBLETURN 5 +#define NORMALKEYMOVE 40 +#define MAXVEL ((NORMALKEYMOVE*2)+10) +#define MAXSVEL ((NORMALKEYMOVE*2)+10) +#define MAXANGVEL 1024 +#define MAXHORIZVEL 256 +#define ONEEIGHTYSCALE 4 +#define MAXVELMOTO 120 + +int32_t g_myAimStat = 0, g_oldAimStat = 0; +int32_t mouseyaxismode = -1; + +enum inputlock_t +{ + IL_NOANGLE = 0x1, + IL_NOHORIZ = 0x2, + IL_NOMOVE = 0x4, + + IL_NOTHING = IL_NOANGLE|IL_NOHORIZ|IL_NOMOVE, +}; + +static int P_CheckLockedMovement(int const playerNum) +{ + auto &thisPlayer = g_player[playerNum]; + auto const pPlayer = thisPlayer.ps; + + if (pPlayer->on_crane >= 0) + return IL_NOMOVE|IL_NOANGLE; + + if (pPlayer->newowner != -1) + return IL_NOANGLE|IL_NOHORIZ; + + if (pPlayer->return_to_center > 0 || thisPlayer.horizRecenter) + return IL_NOHORIZ; + + if (pPlayer->dead_flag || pPlayer->fist_incs || pPlayer->transporter_hold > 2 || pPlayer->hard_landing || pPlayer->access_incs > 0 + || pPlayer->knee_incs > 0 + || (PWEAPON(playerNum, pPlayer->curr_weapon, WorksLike) == TRIPBOMB_WEAPON && pPlayer->kickback_pic > 1 + && pPlayer->kickback_pic < PWEAPON(playerNum, pPlayer->curr_weapon, FireDelay))) + return IL_NOTHING; + + return 0; +} + +void P_GetInput(int const playerNum) +{ + auto &thisPlayer = g_player[playerNum]; + auto const pPlayer = thisPlayer.ps; + auto const pSprite = &sprite[pPlayer->i]; + ControlInfo info; + + auto const currentHiTicks = timerGetHiTicks(); + double const elapsedInputTicks = currentHiTicks - thisPlayer.lastInputTicks; + + thisPlayer.lastInputTicks = currentHiTicks; + + if (elapsedInputTicks == currentHiTicks) + return; + + if ((pPlayer->gm & (MODE_MENU|MODE_TYPE)) || paused) + { + if (!(pPlayer->gm&MODE_MENU)) + CONTROL_GetInput(&info); + + localInput = {}; + localInput.bits = (((int32_t)g_gameQuit) << SK_GAMEQUIT); + localInput.extbits |= (1 << 7); + + return; + } + + D_ProcessEvents(); + + bool mouseaim = in_mousemode || buttonMap.ButtonDown(gamefunc_Mouse_Aiming); + + if (numplayers == 1) + { + pPlayer->aim_mode = in_mousemode; + pPlayer->auto_aim = cl_autoaim; + pPlayer->weaponswitch = cl_weaponswitch; + } + + + CONTROL_GetInput(&info); + + + // JBF: Run key behaviour is selectable + + int const playerRunning = G_CheckAutorun(buttonMap.ButtonDown(gamefunc_Run)); + int const turnAmount = playerRunning ? (NORMALTURN << 1) : NORMALTURN; + constexpr int analogTurnAmount = (NORMALTURN << 1); + int const keyMove = playerRunning ? (NORMALKEYMOVE << 1) : NORMALKEYMOVE; + constexpr int analogExtent = 32767; // KEEPINSYNC sdlayer.cpp + + input_t input {}; + + if (buttonMap.ButtonDown(gamefunc_Strafe)) + { + static int strafeyaw; + + input.svel = -(info.mousex + strafeyaw) >> 3; + strafeyaw = (info.mousex + strafeyaw) % 8; + + input.svel -= info.dyaw * keyMove / analogExtent; + } + else + { + input.q16avel = fix16_sadd(input.q16avel, fix16_sdiv(fix16_from_int(info.mousex), F16(32))); + input.q16avel = fix16_sadd(input.q16avel, fix16_from_int(info.dyaw * analogTurnAmount / (analogExtent >> 1))); + } + + if (mouseaim) + input.q16horz = fix16_sadd(input.q16horz, fix16_sdiv(fix16_from_int(info.mousey), F16(64))); + else + input.fvel = -(info.mousey >> 3); + + if (!in_mouseflip) input.q16horz = -input.q16horz; + + input.q16horz = fix16_ssub(input.q16horz, fix16_from_int(info.dpitch * analogTurnAmount / analogExtent)); + input.svel -= info.dx * keyMove / analogExtent; + input.fvel -= info.dz * keyMove / analogExtent; + + auto scaleAdjustmentToInterval = [=](double x) { return x * REALGAMETICSPERSEC / (1000.0 / elapsedInputTicks); }; + + if (buttonMap.ButtonDown(gamefunc_Strafe)) + { + if (!localInput.svel) + { + if (buttonMap.ButtonDown(gamefunc_Turn_Left) && !(pPlayer->movement_lock & 4) && !localInput.svel) + input.svel = keyMove; + + if (buttonMap.ButtonDown(gamefunc_Turn_Right) && !(pPlayer->movement_lock & 8) && !localInput.svel) + input.svel = -keyMove; + } + } + else + { + static int32_t turnHeldTime; + static int32_t lastInputClock; // MED + int32_t const elapsedTics = (int32_t)totalclock - lastInputClock; + + lastInputClock = (int32_t) totalclock; + + if (buttonMap.ButtonDown(gamefunc_Turn_Left)) + { + turnHeldTime += elapsedTics; + input.q16avel = fix16_ssub(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval((turnHeldTime >= TURBOTURNTIME) ? (turnAmount << 1) : (PREAMBLETURN << 1)))); + } + else if (buttonMap.ButtonDown(gamefunc_Turn_Right)) + { + turnHeldTime += elapsedTics; + input.q16avel = fix16_sadd(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval((turnHeldTime >= TURBOTURNTIME) ? (turnAmount << 1) : (PREAMBLETURN << 1)))); + } + else + turnHeldTime = 0; + } + + if (localInput.svel < keyMove && localInput.svel > -keyMove) + { + if (buttonMap.ButtonDown(gamefunc_Strafe_Left) && !(pPlayer->movement_lock & 4)) + input.svel += keyMove; + + if (buttonMap.ButtonDown(gamefunc_Strafe_Right) && !(pPlayer->movement_lock & 8)) + input.svel += -keyMove; + } + + if (localInput.fvel < keyMove && localInput.fvel > -keyMove) + { + if (RR) + { + /*if (buttonMap.ButtonDown(gamefunc_Quick_Kick)) + { + localInput.bits |= buttonMap.ButtonDown(gamefunc_Move_Forward)<drink_amt >= 66 && pPlayer->drink_amt <= 87) + { + if (buttonMap.ButtonDown(gamefunc_Move_Forward)) + { + input.fvel += keyMove; + if (pPlayer->drink_amt & 1) + input.svel += keyMove; + else + input.svel -= keyMove; + } + + if (buttonMap.ButtonDown(gamefunc_Move_Backward)) + { + input.fvel += -keyMove; + if (pPlayer->drink_amt & 1) + input.svel -= keyMove; + else + input.svel += keyMove; + } + } + else + { + if (buttonMap.ButtonDown(gamefunc_Move_Forward)) + input.fvel += keyMove; + + if (buttonMap.ButtonDown(gamefunc_Move_Backward)) + input.fvel += -keyMove; + } + } + } + else + { + if (buttonMap.ButtonDown(gamefunc_Move_Forward) && !(pPlayer->movement_lock & 1)) + input.fvel += keyMove; + + if (buttonMap.ButtonDown(gamefunc_Move_Backward) && !(pPlayer->movement_lock & 2)) + input.fvel += -keyMove; + } + } + + int weaponSelection; + + for (weaponSelection = gamefunc_Weapon_10; weaponSelection >= gamefunc_Weapon_1; --weaponSelection) + { + if (buttonMap.ButtonDown(weaponSelection)) + { + weaponSelection -= (gamefunc_Weapon_1 - 1); + break; + } + } + + if (buttonMap.ButtonDown(gamefunc_Last_Weapon)) + weaponSelection = 14; + else if (buttonMap.ButtonDown(gamefunc_Alt_Weapon)) + weaponSelection = 13; + else if (buttonMap.ButtonPressed(gamefunc_Next_Weapon) || (buttonMap.ButtonDown(gamefunc_Dpad_Select) && input.fvel > 0)) + { + weaponSelection = 12; + buttonMap.ClearButton(gamefunc_Next_Weapon); + } + else if (buttonMap.ButtonPressed(gamefunc_Previous_Weapon) || (buttonMap.ButtonDown(gamefunc_Dpad_Select) && input.fvel < 0)) + { + weaponSelection = 11; + buttonMap.ClearButton(gamefunc_Previous_Weapon); + } + else if (weaponSelection == gamefunc_Weapon_1-1) + weaponSelection = 0; + + if ((localInput.bits & 0xf00) == 0) + localInput.bits |= (weaponSelection << SK_WEAPON_BITS); + + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Fire) << SK_FIRE); + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Open) << SK_OPEN); + + int const sectorLotag = pPlayer->cursectnum != -1 ? sector[pPlayer->cursectnum].lotag : 0; + int const crouchable = sectorLotag != 2 && (sectorLotag != 1 || pPlayer->spritebridge); + + if (buttonMap.ButtonDown(gamefunc_Toggle_Crouch)) + { + pPlayer->crouch_toggle = !pPlayer->crouch_toggle && crouchable; + + if (crouchable) + buttonMap.ClearButton(gamefunc_Toggle_Crouch); + } + + if (buttonMap.ButtonDown(gamefunc_Crouch) || buttonMap.ButtonDown(gamefunc_Jump) || pPlayer->jetpack_on || (!crouchable && pPlayer->on_ground)) + pPlayer->crouch_toggle = 0; + + int const crouching = buttonMap.ButtonDown(gamefunc_Crouch) || buttonMap.ButtonDown(gamefunc_Toggle_Crouch) || pPlayer->crouch_toggle; + + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Jump) << SK_JUMP) | (crouching << SK_CROUCH); + + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Aim_Up) || (buttonMap.ButtonDown(gamefunc_Dpad_Aiming) && input.fvel > 0)) << SK_AIM_UP; + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Aim_Down) || (buttonMap.ButtonDown(gamefunc_Dpad_Aiming) && input.fvel < 0)) << SK_AIM_DOWN; + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Center_View) << SK_CENTER_VIEW); + + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Look_Left) << SK_LOOK_LEFT) | (buttonMap.ButtonDown(gamefunc_Look_Right) << SK_LOOK_RIGHT); + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Look_Up) << SK_LOOK_UP) | (buttonMap.ButtonDown(gamefunc_Look_Down) << SK_LOOK_DOWN); + + localInput.bits |= (playerRunning << SK_RUN); + + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Inventory_Left) || (buttonMap.ButtonDown(gamefunc_Dpad_Select) && (input.svel > 0 || input.q16avel < 0))) << SK_INV_LEFT; + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Inventory_Right) || (buttonMap.ButtonDown(gamefunc_Dpad_Select) && (input.svel < 0 || input.q16avel > 0))) << SK_INV_RIGHT; + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Inventory) << SK_INVENTORY); + + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Steroids) << SK_STEROIDS) | (buttonMap.ButtonDown(gamefunc_NightVision) << SK_NIGHTVISION); + localInput.bits |= (buttonMap.ButtonDown(gamefunc_MedKit) << SK_MEDKIT) | (buttonMap.ButtonDown(gamefunc_Holo_Duke) << SK_HOLODUKE); + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Jetpack) << SK_JETPACK); + + localInput.bits |= buttonMap.ButtonDown(gamefunc_Holster_Weapon) << SK_HOLSTER; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Quick_Kick) << SK_QUICK_KICK; + localInput.bits |= buttonMap.ButtonDown(gamefunc_TurnAround) << SK_TURNAROUND; + + localInput.bits |= (mouseaim << SK_AIMMODE); + localInput.bits |= (g_gameQuit << SK_GAMEQUIT); + localInput.bits |= inputState.GetKeyStatus(sc_Pause) << SK_PAUSE; + //localInput.bits |= ((uint32_t)inputState.GetKeyStatus(sc_Escape)) << SK_ESCAPE; fixme.This needs to be done differently + + if (RR) + { + if (TEST_SYNC_KEY(localInput.bits, SK_CROUCH)) + localInput.bits &= ~(1 << SK_JUMP); + if (pPlayer->drink_amt > 88) + localInput.bits |= 1 << SK_LOOK_LEFT; + if (pPlayer->drink_amt > 99) + localInput.bits |= 1 << SK_LOOK_DOWN; + } + + if (buttonMap.ButtonDown(gamefunc_Dpad_Select)) + { + input.fvel = 0; + input.svel = 0; + input.q16avel = 0; + } + else if (buttonMap.ButtonDown(gamefunc_Dpad_Aiming)) + input.fvel = 0; + + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Move_Forward) || (input.fvel > 0)); + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Move_Backward) || (input.fvel < 0)) << 1; + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Strafe_Left) || (input.svel > 0)) << 2; + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Strafe_Right) || (input.svel < 0)) << 3; + localInput.extbits |= buttonMap.ButtonDown(gamefunc_Turn_Left)<<4; + localInput.extbits |= buttonMap.ButtonDown(gamefunc_Turn_Right)<<5; + + int const movementLocked = P_CheckLockedMovement(playerNum); + + if ((ud.scrollmode && ud.overhead_on) || (movementLocked & IL_NOTHING) == IL_NOTHING) + { + if (ud.scrollmode && ud.overhead_on) + { + ud.folfvel = input.fvel; + ud.folavel = fix16_to_int(input.q16avel); + } + + localInput.fvel = localInput.svel = 0; + localInput.q16avel = localInput.q16horz = 0; + } + else + { + if (!(movementLocked & IL_NOMOVE)) + { + localInput.fvel = clamp(localInput.fvel + input.fvel, -MAXVEL, MAXVEL); + localInput.svel = clamp(localInput.svel + input.svel, -MAXSVEL, MAXSVEL); + } + + if (!(movementLocked & IL_NOANGLE)) + { + localInput.q16avel = fix16_sadd(localInput.q16avel, input.q16avel); + pPlayer->q16ang = fix16_sadd(pPlayer->q16ang, input.q16avel) & 0x7FFFFFF; + + if (input.q16avel) + { + pPlayer->one_eighty_count = 0; + } + } + + if (!(movementLocked & IL_NOHORIZ)) + { + localInput.q16horz = fix16_clamp(fix16_sadd(localInput.q16horz, input.q16horz), F16(-MAXHORIZVEL), F16(MAXHORIZVEL)); + pPlayer->q16horiz = fix16_clamp(fix16_sadd(pPlayer->q16horiz, input.q16horz), F16(HORIZ_MIN), F16(HORIZ_MAX)); + } + } + + // don't adjust rotscrnang and look_ang if dead. + if (pSprite->extra > 0) + { + pPlayer->q16rotscrnang = fix16_ssub(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(fix16_to_dbl(fix16_sdiv(pPlayer->q16rotscrnang, fix16_from_int(2)))))); + + if (pPlayer->q16rotscrnang && !fix16_sdiv(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(2)))) + pPlayer->q16rotscrnang = fix16_ssub(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(ksgn(fix16_to_int(pPlayer->q16rotscrnang))))); + + pPlayer->q16look_ang = fix16_ssub(pPlayer->q16look_ang, fix16_from_dbl(scaleAdjustmentToInterval(fix16_to_dbl(fix16_sdiv(pPlayer->q16look_ang, fix16_from_int(4)))))); + + if (pPlayer->q16look_ang && !fix16_sdiv(pPlayer->q16look_ang, fix16_from_dbl(scaleAdjustmentToInterval(4)))) + pPlayer->q16look_ang = fix16_ssub(pPlayer->q16look_ang, fix16_from_dbl(scaleAdjustmentToInterval(ksgn(fix16_to_int(pPlayer->q16look_ang))))); + + if (thisPlayer.lookLeft) + { + pPlayer->q16look_ang = fix16_ssub(pPlayer->q16look_ang, fix16_from_dbl(scaleAdjustmentToInterval(152))); + pPlayer->q16rotscrnang = fix16_sadd(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + } + if (thisPlayer.lookRight) + { + pPlayer->q16look_ang = fix16_sadd(pPlayer->q16look_ang, fix16_from_dbl(scaleAdjustmentToInterval(152))); + pPlayer->q16rotscrnang = fix16_ssub(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + } + + if (pPlayer->one_eighty_count < 0) + { + pPlayer->one_eighty_count = -fix16_to_int(fix16_abs(G_GetQ16AngleDelta(pPlayer->one_eighty_target, pPlayer->q16ang))); + pPlayer->q16ang = fix16_sadd(pPlayer->q16ang, fix16_max(fix16_one, fix16_from_dbl(scaleAdjustmentToInterval(-pPlayer->one_eighty_count / ONEEIGHTYSCALE)))) & 0x7FFFFFF; + } + + if (RRRA && pPlayer->sea_sick) + { + if (pPlayer->sea_sick < 250) + { + if (pPlayer->sea_sick >= 180) + pPlayer->q16rotscrnang = fix16_sadd(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + else if (pPlayer->sea_sick >= 130) + pPlayer->q16rotscrnang = fix16_ssub(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + else if (pPlayer->sea_sick >= 70) + pPlayer->q16rotscrnang = fix16_sadd(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + else if (pPlayer->sea_sick >= 20) + pPlayer->q16rotscrnang = fix16_sadd(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + } + if (pPlayer->sea_sick < 250) + pPlayer->q16look_ang = fix16_sadd(pPlayer->q16look_ang, fix16_from_dbl(scaleAdjustmentToInterval((krand2()&255)-128))); + } + } + + // A horiz diff of 128 equal 45 degrees, so we convert horiz to 1024 angle units + + if (thisPlayer.horizAngleAdjust) + { + float const horizAngle + = atan2f(pPlayer->q16horiz - F16(100), F16(128)) * (512.f / fPI) + scaleAdjustmentToInterval(thisPlayer.horizAngleAdjust); + pPlayer->q16horiz = F16(100) + Blrintf(F16(128) * tanf(horizAngle * (fPI / 512.f))); + } + else if (pPlayer->return_to_center > 0 || thisPlayer.horizRecenter) + { + pPlayer->q16horiz = fix16_sadd(pPlayer->q16horiz, fix16_from_dbl(scaleAdjustmentToInterval(fix16_to_dbl(fix16_from_dbl(66.535) - fix16_sdiv(pPlayer->q16horiz, fix16_from_dbl(1.505)))))); + + if (pPlayer->q16horiz >= F16(99) && pPlayer->q16horiz <= F16(101)) + { + pPlayer->q16horiz = F16(100); + pPlayer->return_to_center = 0; + thisPlayer.horizRecenter = false; + } + + if (pPlayer->q16horizoff >= F16(-1) && pPlayer->q16horizoff <= F16(1)) + pPlayer->q16horizoff = 0; + } + + // calculates automatic view angle for playing without a mouse + if (!pPlayer->aim_mode && pPlayer->on_ground && sectorLotag != ST_2_UNDERWATER && (sector[pPlayer->cursectnum].floorstat & 2)) + { + // this is some kind of horse shit approximation of where the player is looking, I guess? + vec2_t const adjustedPosition = { pPlayer->pos.x + (sintable[(fix16_to_int(pPlayer->q16ang) + 512) & 2047] >> 5), + pPlayer->pos.y + (sintable[fix16_to_int(pPlayer->q16ang) & 2047] >> 5) }; + int16_t currentSector = pPlayer->cursectnum; + + updatesector(adjustedPosition.x, adjustedPosition.y, ¤tSector); + + if (currentSector >= 0) + { + int const slopeZ = getflorzofslope(pPlayer->cursectnum, adjustedPosition.x, adjustedPosition.y); + if ((pPlayer->cursectnum == currentSector) || (klabs(getflorzofslope(currentSector, adjustedPosition.x, adjustedPosition.y) - slopeZ) <= ZOFFSET6)) + pPlayer->q16horizoff = fix16_sadd(pPlayer->q16horizoff, fix16_from_dbl(scaleAdjustmentToInterval(mulscale16(pPlayer->truefz - slopeZ, 160)))); + } + } + + if (pPlayer->q16horizoff > 0) + { + pPlayer->q16horizoff = fix16_ssub(pPlayer->q16horizoff, fix16_from_dbl(scaleAdjustmentToInterval(fix16_to_dbl((pPlayer->q16horizoff >> 3) + fix16_one)))); + pPlayer->q16horizoff = fix16_max(pPlayer->q16horizoff, 0); + } + else if (pPlayer->q16horizoff < 0) + { + pPlayer->q16horizoff = fix16_sadd(pPlayer->q16horizoff, fix16_from_dbl(scaleAdjustmentToInterval(fix16_to_dbl((-pPlayer->q16horizoff >> 3) + fix16_one)))); + pPlayer->q16horizoff = fix16_min(pPlayer->q16horizoff, 0); + } + + if (thisPlayer.horizSkew) + pPlayer->q16horiz = fix16_sadd(pPlayer->q16horiz, fix16_from_dbl(scaleAdjustmentToInterval(thisPlayer.horizSkew))); + + pPlayer->q16horiz = fix16_clamp(pPlayer->q16horiz, F16(HORIZ_MIN), F16(HORIZ_MAX)); +} + +void P_GetInputMotorcycle(int playerNum) +{ + auto &thisPlayer = g_player[playerNum]; + auto const pPlayer = thisPlayer.ps; + auto const pSprite = &sprite[pPlayer->i]; + ControlInfo info; + + auto const currentHiTicks = timerGetHiTicks(); + double const elapsedInputTicks = currentHiTicks - thisPlayer.lastInputTicks; + + thisPlayer.lastInputTicks = currentHiTicks; + + if (elapsedInputTicks == currentHiTicks) + return; + + if ((pPlayer->gm & (MODE_MENU|MODE_TYPE)) || paused) + { + if (!(pPlayer->gm&MODE_MENU)) + CONTROL_GetInput(&info); + + localInput = {}; + localInput.bits = (((int32_t)g_gameQuit) << SK_GAMEQUIT); + localInput.extbits |= (1 << 7); + + return; + } + + D_ProcessEvents(); + + bool mouseaim = in_mousemode || buttonMap.ButtonDown(gamefunc_Mouse_Aiming); + + if (numplayers == 1) + { + pPlayer->aim_mode = in_mousemode; + pPlayer->auto_aim = cl_autoaim; + pPlayer->weaponswitch = cl_weaponswitch; + } + + CONTROL_GetInput(&info); + + // JBF: Run key behaviour is selectable + int const playerRunning = G_CheckAutorun(buttonMap.ButtonDown(gamefunc_Run)); + constexpr int analogTurnAmount = (NORMALTURN << 1); + int const keyMove = playerRunning ? (NORMALKEYMOVE << 1) : NORMALKEYMOVE; + constexpr int analogExtent = 32767; // KEEPINSYNC sdlayer.cpp + + input_t input {}; + + input.q16avel = fix16_sadd(input.q16avel, fix16_sdiv(fix16_from_int(info.mousex), F16(32))); + input.q16avel = fix16_sadd(input.q16avel, fix16_from_int(info.dyaw * analogTurnAmount / (analogExtent >> 1))); + + input.svel -= info.dx * keyMove / analogExtent; + input.fvel -= info.dz * keyMove / analogExtent; + + auto scaleAdjustmentToInterval = [=](double x) { return x * REALGAMETICSPERSEC / (1000.0 / elapsedInputTicks); }; + + pPlayer->crouch_toggle = 0; + + localInput.bits |= buttonMap.ButtonDown(gamefunc_Fire) << SK_FIRE; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Steroids) << SK_STEROIDS; + localInput.bits |= buttonMap.ButtonDown(gamefunc_NightVision) << SK_NIGHTVISION; + localInput.bits |= buttonMap.ButtonDown(gamefunc_MedKit) << SK_MEDKIT; + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Inventory_Left) || + (buttonMap.ButtonDown(gamefunc_Dpad_Select) && (input.svel > 0 || input.q16avel < 0))) << SK_INV_LEFT; + localInput.bits |= inputState.GetKeyStatus(sc_Pause) << SK_PAUSE; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Holo_Duke) << SK_HOLODUKE; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Jetpack) << SK_JETPACK; + localInput.bits |= (g_gameQuit << SK_GAMEQUIT); + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Inventory_Right) || + (buttonMap.ButtonDown(gamefunc_Dpad_Select) && (input.svel < 0 || input.q16avel > 0))) << SK_INV_RIGHT; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Open) << SK_OPEN; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Inventory) << SK_INVENTORY; + //localInput.bits |= ((uint32_t)inputState.GetKeyStatus(sc_Escape)) << SK_ESCAPE; fixme.This needs to be done differently + + if (buttonMap.ButtonDown(gamefunc_Dpad_Select)) + { + input.fvel = 0; + input.svel = 0; + input.q16avel = 0; + } + + if (buttonMap.ButtonDown(gamefunc_Dpad_Aiming)) + input.fvel = 0; + + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Move_Forward) || (input.fvel > 0)); + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Move_Backward) || (input.fvel < 0)) << 1; + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Strafe_Left) || (input.svel > 0)) << 2; + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Strafe_Right) || (input.svel < 0)) << 3; + + int const turn = input.q16avel / 32; + int turnLeft = buttonMap.ButtonDown(gamefunc_Turn_Left) || buttonMap.ButtonDown(gamefunc_Strafe_Left); + int turnRight = buttonMap.ButtonDown(gamefunc_Turn_Right) || buttonMap.ButtonDown(gamefunc_Strafe_Right); + int avelScale = F16((turnLeft || turnRight) ? 1 : 0); + if (turn) + { + avelScale = fix16_max(avelScale, fix16_clamp(fix16_mul(turn, turn),0,F16(1))); + if (turn < 0) + turnLeft = 1; + else if (turn > 0) + turnRight = 1; + } + + input.svel = input.fvel = input.q16avel = 0; + + localInput.bits |= turnLeft << SK_AIM_DOWN; + localInput.bits |= turnRight << SK_LOOK_LEFT; + + static int32_t turnHeldTime; + static int32_t lastInputClock; // MED + int32_t const elapsedTics = (int32_t)totalclock - lastInputClock; + + int const moveBack = buttonMap.ButtonDown(gamefunc_Move_Backward) && pPlayer->moto_speed <= 0; + + if (pPlayer->moto_speed == 0 || !pPlayer->on_ground) + { + if (turnLeft) + { + pPlayer->tilt_status -= scaleAdjustmentToInterval(1); + if (pPlayer->tilt_status < -10) + pPlayer->tilt_status = -10; + } + else if (turnRight) + { + pPlayer->tilt_status += scaleAdjustmentToInterval(1); + if (pPlayer->tilt_status > 10) + pPlayer->tilt_status = 10; + } + } + else + { + if (turnLeft || pPlayer->moto_drink < 0) + { + turnHeldTime += elapsedTics; + pPlayer->tilt_status -= scaleAdjustmentToInterval(1); + if (pPlayer->tilt_status < -10) + pPlayer->tilt_status = -10; + if (turnHeldTime >= TURBOTURNTIME && pPlayer->moto_speed > 0) + { + if (moveBack) + input.q16avel = fix16_sadd(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 40 : 20))); + else + input.q16avel = fix16_ssub(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 40 : 20))); + } + else + { + if (moveBack) + input.q16avel = fix16_sadd(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 20 : 6))); + else + input.q16avel = fix16_ssub(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 20 : 6))); + } + } + else if (turnRight || pPlayer->moto_drink > 0) + { + turnHeldTime += elapsedTics; + pPlayer->tilt_status += scaleAdjustmentToInterval(1); + if (pPlayer->tilt_status > 10) + pPlayer->tilt_status = 10; + if (turnHeldTime >= TURBOTURNTIME && pPlayer->moto_speed > 0) + { + if (moveBack) + input.q16avel = fix16_ssub(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 40 : 20))); + else + input.q16avel = fix16_sadd(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 40 : 20))); + } + else + { + if (moveBack) + input.q16avel = fix16_ssub(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 20 : 6))); + else + input.q16avel = fix16_sadd(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 20 : 6))); + } + } + else + { + turnHeldTime = 0; + + if (pPlayer->tilt_status > 0) + pPlayer->tilt_status -= scaleAdjustmentToInterval(1); + else if (pPlayer->tilt_status < 0) + pPlayer->tilt_status += scaleAdjustmentToInterval(1); + } + } + + if (pPlayer->tilt_status > -0.025 && pPlayer->tilt_status < 0.025) + pPlayer->tilt_status = 0; + + if (pPlayer->moto_underwater) + { + pPlayer->moto_speed = 0; + } + else + { + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Move_Forward) || buttonMap.ButtonDown(gamefunc_Strafe)) << SK_JUMP; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Move_Backward) << SK_AIM_UP; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Run) << SK_CROUCH; + } + + input.fvel += pPlayer->moto_speed; + input.q16avel = fix16_mul(input.q16avel, avelScale); + + int const movementLocked = P_CheckLockedMovement(playerNum); + + if ((ud.scrollmode && ud.overhead_on) || (movementLocked & IL_NOTHING) == IL_NOTHING) + { + if (ud.scrollmode && ud.overhead_on) + { + ud.folfvel = input.fvel; + ud.folavel = fix16_to_int(input.q16avel); + } + + localInput.fvel = localInput.svel = 0; + localInput.q16avel = localInput.q16horz = 0; + } + else + { + if (!(movementLocked & IL_NOMOVE)) + { + localInput.fvel = clamp(input.fvel, -(MAXVELMOTO / 8), MAXVELMOTO); + } + + if (!(movementLocked & IL_NOANGLE)) + { + localInput.q16avel = fix16_sadd(localInput.q16avel, input.q16avel); + pPlayer->q16ang = fix16_sadd(pPlayer->q16ang, input.q16avel) & 0x7FFFFFF; + } + } + + // don't adjust rotscrnang and look_ang if dead. + if (pSprite->extra > 0) + { + if (RRRA && pPlayer->sea_sick) + { + if (pPlayer->sea_sick < 250) + { + if (pPlayer->sea_sick >= 180) + pPlayer->q16rotscrnang = fix16_sadd(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + else if (pPlayer->sea_sick >= 130) + pPlayer->q16rotscrnang = fix16_ssub(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + else if (pPlayer->sea_sick >= 70) + pPlayer->q16rotscrnang = fix16_sadd(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + else if (pPlayer->sea_sick >= 20) + pPlayer->q16rotscrnang = fix16_sadd(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + } + if (pPlayer->sea_sick < 250) + pPlayer->q16look_ang = fix16_sadd(pPlayer->q16look_ang, fix16_from_dbl(scaleAdjustmentToInterval((krand2()&255)-128))); + } + } + + if (TEST_SYNC_KEY(localInput.bits, SK_JUMP)) + { + localInput.bits |= 1; + } +} + +void P_GetInputBoat(int playerNum) +{ + auto &thisPlayer = g_player[playerNum]; + auto const pPlayer = thisPlayer.ps; + auto const pSprite = &sprite[pPlayer->i]; + ControlInfo info; + + auto const currentHiTicks = timerGetHiTicks(); + double const elapsedInputTicks = currentHiTicks - thisPlayer.lastInputTicks; + + thisPlayer.lastInputTicks = currentHiTicks; + + if (elapsedInputTicks == currentHiTicks) + return; + + if ((pPlayer->gm & (MODE_MENU|MODE_TYPE)) || paused) + { + if (!(pPlayer->gm&MODE_MENU)) + CONTROL_GetInput(&info); + + localInput = {}; + localInput.bits = (((int32_t)g_gameQuit) << SK_GAMEQUIT); + localInput.extbits |= (1 << 7); + + return; + } + + D_ProcessEvents(); + + bool mouseaim = in_mousemode || buttonMap.ButtonDown(gamefunc_Mouse_Aiming); + + if (numplayers == 1) + { + pPlayer->aim_mode = in_mousemode; + pPlayer->auto_aim = cl_autoaim; + pPlayer->weaponswitch = cl_weaponswitch; + } + + CONTROL_GetInput(&info); + + // JBF: Run key behaviour is selectable + int const playerRunning = G_CheckAutorun(buttonMap.ButtonDown(gamefunc_Run)); + constexpr int analogTurnAmount = (NORMALTURN << 1); + int const keyMove = playerRunning ? (NORMALKEYMOVE << 1) : NORMALKEYMOVE; + constexpr int analogExtent = 32767; // KEEPINSYNC sdlayer.cpp + + input_t input {}; + + input.q16avel = fix16_sadd(input.q16avel, fix16_sdiv(fix16_from_int(info.mousex), F16(32))); + input.q16avel = fix16_sadd(input.q16avel, fix16_from_int(info.dyaw * analogTurnAmount / (analogExtent >> 1))); + + input.svel -= info.dx * keyMove / analogExtent; + input.fvel -= info.dz * keyMove / analogExtent; + + auto scaleAdjustmentToInterval = [=](double x) { return x * REALGAMETICSPERSEC / (1000.0 / elapsedInputTicks); }; + + pPlayer->crouch_toggle = 0; + + localInput.bits |= buttonMap.ButtonDown(gamefunc_Fire) << SK_FIRE; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Steroids) << SK_STEROIDS; + localInput.bits |= buttonMap.ButtonDown(gamefunc_NightVision) << SK_NIGHTVISION; + localInput.bits |= buttonMap.ButtonDown(gamefunc_MedKit) << SK_MEDKIT; + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Inventory_Left) || + (buttonMap.ButtonDown(gamefunc_Dpad_Select) && (input.svel > 0 || input.q16avel < 0))) << SK_INV_LEFT; + localInput.bits |= inputState.GetKeyStatus(sc_Pause) << SK_PAUSE; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Holo_Duke) << SK_HOLODUKE; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Jetpack) << SK_JETPACK; + localInput.bits |= (g_gameQuit << SK_GAMEQUIT); + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Inventory_Right) || + (buttonMap.ButtonDown(gamefunc_Dpad_Select) && (input.svel < 0 || input.q16avel > 0))) << SK_INV_RIGHT; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Open) << SK_OPEN; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Inventory) << SK_INVENTORY; + //localInput.bits |= ((uint32_t)inputState.GetKeyStatus(sc_Escape)) << SK_ESCAPE; fixme.This needs to be done differently + + if (buttonMap.ButtonDown(gamefunc_Dpad_Select)) + { + input.fvel = 0; + input.svel = 0; + input.q16avel = 0; + } + + if (buttonMap.ButtonDown(gamefunc_Dpad_Aiming)) + input.fvel = 0; + + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Move_Forward) || (input.fvel > 0)); + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Move_Backward) || (input.fvel < 0)) << 1; + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Strafe_Left) || (input.svel > 0)) << 2; + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Strafe_Right) || (input.svel < 0)) << 3; + + int const turn = input.q16avel / 32; + int turnLeft = buttonMap.ButtonDown(gamefunc_Turn_Left) || buttonMap.ButtonDown(gamefunc_Strafe_Left); + int turnRight = buttonMap.ButtonDown(gamefunc_Turn_Right) || buttonMap.ButtonDown(gamefunc_Strafe_Right); + int avelScale = F16((turnLeft || turnRight) ? 1 : 0); + if (turn) + { + avelScale = fix16_max(avelScale, fix16_clamp(fix16_mul(turn, turn),0,F16(1))); + if (turn < 0) + turnLeft = 1; + else if (turn > 0) + turnRight = 1; + } + + input.svel = input.fvel = input.q16avel = 0; + + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Move_Forward) || buttonMap.ButtonDown(gamefunc_Strafe)) << SK_JUMP; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Move_Backward) << SK_AIM_UP; + localInput.bits |= buttonMap.ButtonDown(gamefunc_Run) << SK_CROUCH; + + localInput.bits |= turnLeft << SK_AIM_DOWN; + localInput.bits |= turnRight << SK_LOOK_LEFT; + + static int32_t turnHeldTime; + static int32_t lastInputClock; // MED + int32_t const elapsedTics = (int32_t)totalclock - lastInputClock; + + if (pPlayer->moto_speed != 0) + { + if (turnLeft || pPlayer->moto_drink < 0) + { + turnHeldTime += elapsedTics; + if (!pPlayer->not_on_water) + { + pPlayer->tilt_status -= scaleAdjustmentToInterval(1); + if (pPlayer->tilt_status < -10) + pPlayer->tilt_status = -10; + if (turnHeldTime >= TURBOTURNTIME) + input.q16avel = fix16_ssub(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 40 : 20))); + else + input.q16avel = fix16_ssub(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 12 : 6))); + } + else + if (turnHeldTime >= TURBOTURNTIME) + input.q16avel = fix16_ssub(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 12 : 6))); + else + input.q16avel = fix16_ssub(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 4 : 2))); + } + else if (turnRight || pPlayer->moto_drink > 0) + { + turnHeldTime += elapsedTics; + if (!pPlayer->not_on_water) + { + pPlayer->tilt_status += scaleAdjustmentToInterval(1); + if (pPlayer->tilt_status > 10) + pPlayer->tilt_status = 10; + if (turnHeldTime >= TURBOTURNTIME) + input.q16avel = fix16_sadd(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 40 : 20))); + else + input.q16avel = fix16_sadd(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 12 : 6))); + } + else + if (turnHeldTime >= TURBOTURNTIME) + input.q16avel = fix16_sadd(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 12 : 6))); + else + input.q16avel = fix16_sadd(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval(turn ? 4 : 2))); + } + else if (!pPlayer->not_on_water) + { + turnHeldTime = 0; + + if (pPlayer->tilt_status > 0) + pPlayer->tilt_status -= scaleAdjustmentToInterval(1); + else if (pPlayer->tilt_status < 0) + pPlayer->tilt_status += scaleAdjustmentToInterval(1); + } + } + else if (!pPlayer->not_on_water) + { + turnHeldTime = 0; + + if (pPlayer->tilt_status > 0) + pPlayer->tilt_status -= scaleAdjustmentToInterval(1); + else if (pPlayer->tilt_status < 0) + pPlayer->tilt_status += scaleAdjustmentToInterval(1); + } + + if (pPlayer->tilt_status > -0.025 && pPlayer->tilt_status < 0.025) + pPlayer->tilt_status = 0; + + input.fvel += pPlayer->moto_speed; + input.q16avel = fix16_mul(input.q16avel, avelScale); + + int const movementLocked = P_CheckLockedMovement(playerNum); + + if ((ud.scrollmode && ud.overhead_on) || (movementLocked & IL_NOTHING) == IL_NOTHING) + { + if (ud.scrollmode && ud.overhead_on) + { + ud.folfvel = input.fvel; + ud.folavel = fix16_to_int(input.q16avel); + } + + localInput.fvel = localInput.svel = 0; + localInput.q16avel = localInput.q16horz = 0; + } + else + { + if (!(movementLocked & IL_NOMOVE)) + { + localInput.fvel = clamp(input.fvel, -(MAXVELMOTO / 8), MAXVELMOTO); + } + + if (!(movementLocked & IL_NOANGLE)) + { + localInput.q16avel = fix16_sadd(localInput.q16avel, input.q16avel); + pPlayer->q16ang = fix16_sadd(pPlayer->q16ang, input.q16avel) & 0x7FFFFFF; + } + } + + // don't adjust rotscrnang and look_ang if dead. + if (pSprite->extra > 0) + { + if (RRRA && pPlayer->sea_sick) + { + if (pPlayer->sea_sick < 250) + { + if (pPlayer->sea_sick >= 180) + pPlayer->q16rotscrnang = fix16_sadd(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + else if (pPlayer->sea_sick >= 130) + pPlayer->q16rotscrnang = fix16_ssub(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + else if (pPlayer->sea_sick >= 70) + pPlayer->q16rotscrnang = fix16_sadd(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + else if (pPlayer->sea_sick >= 20) + pPlayer->q16rotscrnang = fix16_sadd(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + } + if (pPlayer->sea_sick < 250) + pPlayer->q16look_ang = fix16_sadd(pPlayer->q16look_ang, fix16_from_dbl(scaleAdjustmentToInterval((krand2()&255)-128))); + } + } +} + +int dword_A99D4, dword_A99D8, dword_A99DC, dword_A99E0; +int dword_164620, dword_164624; + +void sub_299C0(void) +{ + dword_A99D8 = 0; + dword_A99DC = 0; +} + +int sub_299D8(void) +{ + if ((int)totalclock - dword_A99D8 >= 30 && buttonMap.ButtonDown(gamefunc_Crouch)) + { + dword_A99D8 = (int)totalclock; + dword_A99DC ^= 1; + } + return dword_A99DC; +} + +void P_DHGetInput(int const playerNum) +{ + auto &thisPlayer = g_player[playerNum]; + auto const pPlayer = thisPlayer.ps; + auto const pSprite = &sprite[pPlayer->i]; + ControlInfo info; + + auto const currentHiTicks = timerGetHiTicks(); + double const elapsedInputTicks = currentHiTicks - thisPlayer.lastInputTicks; + + thisPlayer.lastInputTicks = currentHiTicks; + + if (elapsedInputTicks == currentHiTicks) + return; + + if ((pPlayer->gm & (MODE_MENU|MODE_TYPE)) || paused) + { + if (!(pPlayer->gm&MODE_MENU)) + CONTROL_GetInput(&info); + + localInput = {}; + localInput.bits = (((int32_t)g_gameQuit) << SK_GAMEQUIT); + localInput.extbits |= (1 << 7); + + return; + } + + D_ProcessEvents(); + + bool mouseaim = in_mousemode || buttonMap.ButtonDown(gamefunc_Mouse_Aiming); + + CONTROL_GetInput(&info); + + // JBF: Run key behaviour is selectable + int const playerRunning = G_CheckAutorun(buttonMap.ButtonDown(gamefunc_Run)); + int const playerCrouch = sub_299D8(); + int const playerJump = buttonMap.ButtonDown(gamefunc_Jump) && !(pPlayer->cursectnum >= 0 && sector[pPlayer->cursectnum].hitag == 2003); + int const turnAmount = playerCrouch ? 2 : (playerRunning ? 16 : 8); + constexpr int analogTurnAmount = 16; + int const keyMove = playerCrouch ? 3 : (playerRunning ? 24 : 12); + constexpr int analogExtent = 32767; // KEEPINSYNC sdlayer.cpp + + input_t input {}; + + if (buttonMap.ButtonDown(gamefunc_Strafe)) + { + static int strafeyaw; + + input.svel = -(info.mousex + strafeyaw) >> 3; + strafeyaw = (info.mousex + strafeyaw) % 8; + + input.svel -= info.dyaw * keyMove / analogExtent; + } + else + { + input.q16avel = fix16_sadd(input.q16avel, fix16_sdiv(fix16_from_int(info.mousex), F16(32))); + input.q16avel = fix16_sadd(input.q16avel, fix16_from_int(info.dyaw / analogExtent * (analogTurnAmount << 1))); + } + + if (mouseaim) + input.q16horz = fix16_sadd(input.q16horz, fix16_sdiv(fix16_from_int(info.mousey), F16(64))); + else + input.fvel = -(info.mousey >> 3); + + if (!in_mouseflip) input.q16horz = -input.q16horz; + + input.q16horz = fix16_ssub(input.q16horz, fix16_from_int(info.dpitch * analogTurnAmount / analogExtent)); + input.svel -= info.dx * keyMove / analogExtent; + input.fvel -= info.dz * keyMove / analogExtent; + + auto scaleAdjustmentToInterval = [=](double x) { return x * REALGAMETICSPERSEC / (1000.0 / elapsedInputTicks); }; + + if (buttonMap.ButtonDown(gamefunc_Strafe)) + { + if (!localInput.svel) + { + if (buttonMap.ButtonDown(gamefunc_Turn_Left) && !(pPlayer->movement_lock & 4) && !localInput.svel) + input.svel = keyMove; + + if (buttonMap.ButtonDown(gamefunc_Turn_Right) && !(pPlayer->movement_lock & 8) && !localInput.svel) + input.svel = -keyMove; + } + } + else + { + static int32_t turnHeldTime; + static int32_t lastInputClock; // MED + int32_t const elapsedTics = (int32_t)totalclock - lastInputClock; + + lastInputClock = (int32_t) totalclock; + + if (buttonMap.ButtonDown(gamefunc_Turn_Left)) + { + turnHeldTime += elapsedTics; + input.q16avel = fix16_ssub(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval((turnHeldTime >= TURBOTURNTIME) ? (turnAmount << 1) : (PREAMBLETURN << 1)))); + } + else if (buttonMap.ButtonDown(gamefunc_Turn_Right)) + { + turnHeldTime += elapsedTics; + input.q16avel = fix16_sadd(input.q16avel, fix16_from_dbl(scaleAdjustmentToInterval((turnHeldTime >= TURBOTURNTIME) ? (turnAmount << 1) : (PREAMBLETURN << 1)))); + } + else + turnHeldTime = 0; + } + + if (localInput.svel < keyMove && localInput.svel > -keyMove) + { + if (buttonMap.ButtonDown(gamefunc_Strafe_Left) && !(pPlayer->movement_lock & 4)) + input.svel += keyMove; + + if (buttonMap.ButtonDown(gamefunc_Strafe_Right) && !(pPlayer->movement_lock & 8)) + input.svel += -keyMove; + } + + if (localInput.fvel < keyMove && localInput.fvel > -keyMove) + { + if (buttonMap.ButtonDown(gamefunc_Move_Forward) && !(pPlayer->movement_lock & 1)) + input.fvel += keyMove; + + if (buttonMap.ButtonDown(gamefunc_Move_Backward) && !(pPlayer->movement_lock & 2)) + input.fvel += -keyMove; + } + + if (playerRunning && sub_535EC()) + input.fvel <<= 3; + + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Fire) << SK_FIRE); + + localInput.bits |= (playerJump << SK_JUMP) | (playerCrouch << SK_CROUCH); + + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Aim_Up) || (buttonMap.ButtonDown(gamefunc_Dpad_Aiming) && input.fvel > 0)) << SK_AIM_UP; + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Aim_Down) || (buttonMap.ButtonDown(gamefunc_Dpad_Aiming) && input.fvel < 0)) << SK_AIM_DOWN; + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Center_View) << SK_CENTER_VIEW); + + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Look_Left) << SK_LOOK_LEFT) | (buttonMap.ButtonDown(gamefunc_Look_Right) << SK_LOOK_RIGHT); + localInput.bits |= (buttonMap.ButtonDown(gamefunc_Look_Up) << SK_LOOK_UP) | (buttonMap.ButtonDown(gamefunc_Look_Down) << SK_LOOK_DOWN); + + localInput.bits |= (playerRunning << SK_RUN); + + localInput.bits |= buttonMap.ButtonDown(gamefunc_TurnAround) << SK_TURNAROUND; + + localInput.bits |= (mouseaim << SK_AIMMODE); + localInput.bits |= (g_gameQuit << SK_GAMEQUIT); + localInput.bits |= inputState.GetKeyStatus(sc_Pause) << SK_PAUSE; + localInput.bits |= ((uint32_t)inputState.GetKeyStatus(sc_Escape)) << SK_ESCAPE; + + if (buttonMap.ButtonDown(gamefunc_Dpad_Aiming)) + input.fvel = 0; + + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Move_Forward) || (input.fvel > 0)); + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Move_Backward) || (input.fvel < 0)) << 1; + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Strafe_Left) || (input.svel > 0)) << 2; + localInput.extbits |= (buttonMap.ButtonDown(gamefunc_Strafe_Right) || (input.svel < 0)) << 3; + localInput.extbits |= buttonMap.ButtonDown(gamefunc_Turn_Left)<<4; + localInput.extbits |= buttonMap.ButtonDown(gamefunc_Turn_Right)<<5; + + if (pPlayer->cursectnum >= 0 && sector[pPlayer->cursectnum].hitag == 2003) + input.fvel >>= 1; + + // don't adjust rotscrnang and look_ang if dead. + if (pSprite->extra > 0) + { + pPlayer->q16rotscrnang = fix16_ssub(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(fix16_to_dbl(fix16_sdiv(pPlayer->q16rotscrnang, fix16_from_int(2)))))); + + if (pPlayer->q16rotscrnang && !fix16_sdiv(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(2)))) + pPlayer->q16rotscrnang = fix16_ssub(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(ksgn(fix16_to_int(pPlayer->q16rotscrnang))))); + + pPlayer->q16look_ang = fix16_ssub(pPlayer->q16look_ang, fix16_from_dbl(scaleAdjustmentToInterval(fix16_to_dbl(fix16_sdiv(pPlayer->q16look_ang, fix16_from_int(4)))))); + + if (pPlayer->q16look_ang && !fix16_sdiv(pPlayer->q16look_ang, fix16_from_dbl(scaleAdjustmentToInterval(4)))) + pPlayer->q16look_ang = fix16_ssub(pPlayer->q16look_ang, fix16_from_dbl(scaleAdjustmentToInterval(ksgn(fix16_to_int(pPlayer->q16look_ang))))); + + if (thisPlayer.lookLeft) + { + pPlayer->q16look_ang = fix16_ssub(pPlayer->q16look_ang, fix16_from_dbl(scaleAdjustmentToInterval(152))); + pPlayer->q16rotscrnang = fix16_sadd(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + } + if (thisPlayer.lookRight) + { + pPlayer->q16look_ang = fix16_sadd(pPlayer->q16look_ang, fix16_from_dbl(scaleAdjustmentToInterval(152))); + pPlayer->q16rotscrnang = fix16_ssub(pPlayer->q16rotscrnang, fix16_from_dbl(scaleAdjustmentToInterval(24))); + } + + if (pPlayer->one_eighty_count < 0) + { + pPlayer->one_eighty_count = -fix16_to_int(fix16_abs(G_GetQ16AngleDelta(pPlayer->one_eighty_target, pPlayer->q16ang))); + pPlayer->q16ang = fix16_sadd(pPlayer->q16ang, fix16_max(fix16_one, fix16_from_dbl(scaleAdjustmentToInterval(-pPlayer->one_eighty_count / ONEEIGHTYSCALE)))) & 0x7FFFFFF; + } + } + + // A horiz diff of 128 equal 45 degrees, so we convert horiz to 1024 angle units + + if (thisPlayer.horizAngleAdjust) + { + float const horizAngle + = atan2f(pPlayer->q16horiz - F16(100), F16(128)) * (512.f / fPI) + scaleAdjustmentToInterval(thisPlayer.horizAngleAdjust); + pPlayer->q16horiz = F16(100) + Blrintf(F16(128) * tanf(horizAngle * (fPI / 512.f))); + } + else if (pPlayer->return_to_center > 0 || thisPlayer.horizRecenter) + { + pPlayer->q16horiz = fix16_sadd(pPlayer->q16horiz, fix16_from_dbl(scaleAdjustmentToInterval(fix16_to_dbl(fix16_from_dbl(200 / 3) - fix16_sdiv(pPlayer->q16horiz, F16(1.5)))))); + + if ((!pPlayer->return_to_center && thisPlayer.horizRecenter) || (pPlayer->q16horiz >= F16(99.9) && pPlayer->q16horiz <= F16(100.1))) + { + pPlayer->q16horiz = F16(100); + thisPlayer.horizRecenter = false; + } + + if (pPlayer->q16horizoff >= F16(-0.1) && pPlayer->q16horizoff <= F16(0.1)) + pPlayer->q16horizoff = 0; + } + + if (pPlayer->q16horizoff > 0) + { + pPlayer->q16horizoff = fix16_ssub(pPlayer->q16horizoff, fix16_from_dbl(scaleAdjustmentToInterval(fix16_to_dbl((pPlayer->q16horizoff >> 3) + fix16_one)))); + pPlayer->q16horizoff = fix16_max(pPlayer->q16horizoff, 0); + } + else if (pPlayer->q16horizoff < 0) + { + pPlayer->q16horizoff = fix16_sadd(pPlayer->q16horizoff, fix16_from_dbl(scaleAdjustmentToInterval(fix16_to_dbl((-pPlayer->q16horizoff >> 3) + fix16_one)))); + pPlayer->q16horizoff = fix16_min(pPlayer->q16horizoff, 0); + } + + if (thisPlayer.horizSkew) + pPlayer->q16horiz = fix16_sadd(pPlayer->q16horiz, fix16_from_dbl(scaleAdjustmentToInterval(thisPlayer.horizSkew))); + + pPlayer->q16horiz = fix16_clamp(pPlayer->q16horiz, F16(HORIZ_MIN), F16(HORIZ_MAX)); + + if (input.fvel || input.svel || input.q16avel || TEST_SYNC_KEY(input.bits, SK_FIRE) || dword_A99E0 != pPlayer->pos.z) + pPlayer->dhat60f = 1; + dword_A99E0 = pPlayer->pos.z; + pPlayer->dhat617 = playerRunning; + if (!input.fvel) + pPlayer->dhat617 = 0; + pPlayer->dhat613 = buttonMap.ButtonDown(gamefunc_Move_Forward) | buttonMap.ButtonDown(gamefunc_Move_Backward); + if (pPlayer->dhat60f) + sub_5A250(256); + //dword_A99D4++; + //if (dword_A99D4 == 2) + //{ + // sub_53304(); + // dword_A99D4 = 0; + //} +} + +void P_MadeNoise(int playerNum) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + pPlayer->make_noise = 1; + pPlayer->noise_x = pPlayer->pos.x; + pPlayer->noise_y = pPlayer->pos.y; +} + +static void P_Thrust(DukePlayer_t *const pPlayer, int shift) +{ + pPlayer->vel.x += sintable[(fix16_to_int(pPlayer->q16ang)+512)&2047] << shift; + pPlayer->vel.y += sintable[fix16_to_int(pPlayer->q16ang)&2047] << shift; +} + +static int32_t P_DoCounters(int playerNum) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + if (RRRA) + { + if (g_windTime > 0) + g_windTime--; + else if ((krand2() & 127) == 8) + { + g_windTime = 120+((krand2()&63)<<2); + g_windDir = krand2()&2047; + } + + if (g_bellTime > 0) + { + g_bellTime--; + if (g_bellTime == 0) + sprite[g_bellSprite].picnum++; + } + + if (playerNum == 0 && g_chickenWeaponTimer > 0) + g_chickenWeaponTimer--; + + if (pPlayer->sea_sick) + { + pPlayer->sea_sick--; + if (pPlayer->sea_sick) + pPlayer->sea_sick_stat = 0; + } + + } + + if (RR) + { + if (pPlayer->yehaa_timer) + pPlayer->yehaa_timer--; + + if (pPlayer->hbomb_offset > 0) + { + pPlayer->hbomb_offset++; + pPlayer->hbomb_time--; + } + + if (--pPlayer->drink_timer <= 0) + { + pPlayer->drink_timer = 1024; + if (pPlayer->drink_amt) + pPlayer->drink_amt--; + } + + if (--pPlayer->eat_timer <= 0) + { + pPlayer->eat_timer = 1024; + if (pPlayer->eat_amt) + pPlayer->eat_amt--; + } + + if (pPlayer->drink_amt == 100) + { + if (!A_CheckSoundPlaying(pPlayer->i, 420)) + A_PlaySound(420, pPlayer->i); + pPlayer->drink_amt -= 9; + pPlayer->eat_amt >>= 1; + } + pPlayer->eat_ang = (1647 + pPlayer->eat_amt * 8) & 2047; + + if (pPlayer->eat_amt >= 100) + pPlayer->eat_amt = 100; + + if (pPlayer->eat_amt >= 31 && krand2() < pPlayer->eat_amt) + { + switch (krand2()&3) + { + case 0: + A_PlaySound(404, pPlayer->i); + break; + case 1: + A_PlaySound(422, pPlayer->i); + break; + case 2: + A_PlaySound(423, pPlayer->i); + break; + case 3: + A_PlaySound(424, pPlayer->i); + break; + } + if (!g_netServer && numplayers < 2) + { + pPlayer->noise_radius = 16384; + P_MadeNoise(playerNum); + P_Thrust(pPlayer, 4); + } + pPlayer->eat_amt -= 4; + if (pPlayer->eat_amt < 0) + pPlayer->eat_amt = 0; + } + } + + if (pPlayer->invdisptime > 0) + pPlayer->invdisptime--; + + if (pPlayer->tipincs > 0) + pPlayer->tipincs--; + + if (pPlayer->last_pissed_time > 0) + { + if (RR) + { + --pPlayer->last_pissed_time; + + if (pPlayer->drink_amt > 66 && (pPlayer->last_pissed_time % GAMETICSPERSEC) == 0) + pPlayer->drink_amt--; + + if (!adult_lockout) + { + switch (pPlayer->last_pissed_time) + { + case 5662: + A_PlaySound(434, pPlayer->i); + break; + case 5567: + A_PlaySound(434, pPlayer->i); + break; + case 5472: + A_PlaySound(433, pPlayer->i); + break; + case 5072: + A_PlaySound(435, pPlayer->i); + break; + case 5014: + A_PlaySound(434, pPlayer->i); + break; + case 4919: + A_PlaySound(433, pPlayer->i); + break; + } + } + if (pPlayer->last_pissed_time == 5668) + { + pPlayer->holster_weapon = 0; + pPlayer->weapon_pos = WEAPON_POS_RAISE; + } + } + else + switch (--pPlayer->last_pissed_time) + { + case GAMETICSPERSEC * 219: + { + A_PlaySound(FLUSH_TOILET, pPlayer->i); + if (playerNum == screenpeek || GTFLAGS(GAMETYPE_COOPSOUND)) + A_PlaySound(DUKE_PISSRELIEF, pPlayer->i); + } + break; + case GAMETICSPERSEC * 218: + { + pPlayer->holster_weapon = 0; + pPlayer->weapon_pos = WEAPON_POS_RAISE; + } + break; + } + } + + if (pPlayer->crack_time > 0) + { + if (--pPlayer->crack_time == 0) + { + pPlayer->knuckle_incs = 1; + pPlayer->crack_time = 777; + } + } + + if (pPlayer->inv_amount[GET_STEROIDS] > 0 && pPlayer->inv_amount[GET_STEROIDS] < 400) + { + if (--pPlayer->inv_amount[GET_STEROIDS] == 0) + { + P_SelectNextInvItem(pPlayer); + if (RR) + { + pPlayer->eat_amt = pPlayer->drink_amt = 0; + pPlayer->eat_ang = pPlayer->drink_ang = 1647; + } + } + + if (!(pPlayer->inv_amount[GET_STEROIDS] & (RR ? 14 : 7))) + if (playerNum == screenpeek || GTFLAGS(GAMETYPE_COOPSOUND)) + A_PlaySound(RR ? DUKE_TAKEPILLS : DUKE_HARTBEAT, pPlayer->i); + } + + if (!RR) + { + if (pPlayer->heat_on && pPlayer->inv_amount[GET_HEATS] > 0) + { + if (--pPlayer->inv_amount[GET_HEATS] == 0) + { + pPlayer->heat_on = 0; + P_SelectNextInvItem(pPlayer); + A_PlaySound(NITEVISION_ONOFF, pPlayer->i); + P_UpdateScreenPal(pPlayer); + } + } + + if (pPlayer->holoduke_on >= 0) + { + if (--pPlayer->inv_amount[GET_HOLODUKE] <= 0) + { + A_PlaySound(TELEPORTER, pPlayer->i); + pPlayer->holoduke_on = -1; + P_SelectNextInvItem(pPlayer); + } + } + + if (pPlayer->jetpack_on && pPlayer->inv_amount[GET_JETPACK] > 0) + { + if (--pPlayer->inv_amount[GET_JETPACK] <= 0) + { + pPlayer->jetpack_on = 0; + P_SelectNextInvItem(pPlayer); + A_PlaySound(DUKE_JETPACK_OFF, pPlayer->i); + S_StopEnvSound(DUKE_JETPACK_IDLE, pPlayer->i); + S_StopEnvSound(DUKE_JETPACK_ON, pPlayer->i); + } + } + + if (pPlayer->quick_kick > 0 && sprite[pPlayer->i].pal != 1) + { + pPlayer->last_quick_kick = pPlayer->quick_kick + 1; + + if (--pPlayer->quick_kick == 8) + A_Shoot(pPlayer->i, KNEE); + } + else if (pPlayer->last_quick_kick > 0) + --pPlayer->last_quick_kick; + } + + if (pPlayer->access_incs && sprite[pPlayer->i].pal != 1) + { + ++pPlayer->access_incs; + + if (sprite[pPlayer->i].extra <= 0) + pPlayer->access_incs = 12; + + if (pPlayer->access_incs == 12) + { + if (pPlayer->access_spritenum >= 0) + { + P_ActivateSwitch(playerNum, pPlayer->access_spritenum, 1); + switch (sprite[pPlayer->access_spritenum].pal) + { + case 0: RR ? pPlayer->keys[1] = 1 : pPlayer->got_access &= (0xffff - 0x1); break; + case 21: RR ? pPlayer->keys[2] = 1 : pPlayer->got_access &= (0xffff - 0x2); break; + case 23: RR ? pPlayer->keys[3] = 1 : pPlayer->got_access &= (0xffff - 0x4); break; + } + pPlayer->access_spritenum = -1; + } + else + { + P_ActivateSwitch(playerNum,pPlayer->access_wallnum,0); + switch (wall[pPlayer->access_wallnum].pal) + { + case 0: RR ? pPlayer->keys[1] = 1 : pPlayer->got_access &= (0xffff - 0x1); break; + case 21: RR ? pPlayer->keys[2] = 1 : pPlayer->got_access &= (0xffff - 0x2); break; + case 23: RR ? pPlayer->keys[3] = 1 : pPlayer->got_access &= (0xffff - 0x4); break; + } + } + } + + if (pPlayer->access_incs > 20) + { + pPlayer->access_incs = 0; + pPlayer->weapon_pos = WEAPON_POS_RAISE; + pPlayer->kickback_pic = 0; + } + } + + if (pPlayer->cursectnum >= 0 && pPlayer->scuba_on == 0 && sector[pPlayer->cursectnum].lotag == ST_2_UNDERWATER) + { + if (pPlayer->inv_amount[GET_SCUBA] > 0) + { + pPlayer->scuba_on = 1; + pPlayer->inven_icon = ICON_SCUBA; + P_DoQuote(QUOTE_SCUBA_ON, pPlayer); + } + else + { + if (pPlayer->airleft > 0) + --pPlayer->airleft; + else + { + pPlayer->extra_extra8 += 32; + if (pPlayer->last_extra < (pPlayer->max_player_health >> 1) && (pPlayer->last_extra & 3) == 0) + A_PlaySound(DUKE_LONGTERM_PAIN, pPlayer->i); + } + } + } + else if (pPlayer->inv_amount[GET_SCUBA] > 0 && pPlayer->scuba_on) + { + pPlayer->inv_amount[GET_SCUBA]--; + if (pPlayer->inv_amount[GET_SCUBA] == 0) + { + pPlayer->scuba_on = 0; + P_SelectNextInvItem(pPlayer); + } + } + + if (pPlayer->knuckle_incs) + { + if (++pPlayer->knuckle_incs == 10) + { + if (RR && !g_wupass) + { + int soundId = 391; + g_wupass = 1; + if (!g_lastLevel) switch (ud.volume_number) + { + case 0: + switch (ud.level_number) + { + case 0: + soundId = RRRA ? 63 : 391; + break; + case 1: + soundId = 64; + break; + case 2: + soundId = 77; + break; + case 3: + soundId = 80; + break; + case 4: + soundId = 102; + break; + case 5: + soundId = 103; + break; + case 6: + soundId = 104; + break; + } + break; + case 1: + switch (ud.level_number) + { + case 0: + soundId = 105; + break; + case 1: + soundId = 176; + break; + case 2: + soundId = 177; + break; + case 3: + soundId = 198; + break; + case 4: + soundId = 230; + break; + case 5: + soundId = 255; + break; + case 6: + soundId = 283; + break; + } + break; + } + A_PlaySound(soundId, pPlayer->i); + } + else if (!WW2GI) + { + if (totalclock > 1024) + if (playerNum == screenpeek || GTFLAGS(GAMETYPE_COOPSOUND)) + { + if (rand()&1) + A_PlaySound(DUKE_CRACK,pPlayer->i); + else A_PlaySound(DUKE_CRACK2,pPlayer->i); + } + + A_PlaySound(DUKE_CRACK_FIRST, pPlayer->i); + } + } + else if (pPlayer->knuckle_incs == 22 || TEST_SYNC_KEY(g_player[playerNum].input->bits, SK_FIRE)) + pPlayer->knuckle_incs=0; + + return 1; + } + + return 0; +} + +int16_t WeaponPickupSprites[MAX_WEAPONS] = { KNEE__STATIC, FIRSTGUNSPRITE__STATIC, SHOTGUNSPRITE__STATIC, + CHAINGUNSPRITE__STATIC, RPGSPRITE__STATIC, HEAVYHBOMB__STATIC, SHRINKERSPRITE__STATIC, DEVISTATORSPRITE__STATIC, + TRIPBOMBSPRITE__STATIC, FREEZESPRITE__STATIC, HEAVYHBOMB__STATIC, SHRINKERSPRITE__STATIC + }; +// this is used for player deaths +void P_DropWeapon(int const playerNum) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + int const currentWeapon = WW2GI ? PWEAPON(playerNum, pPlayer->curr_weapon, WorksLike) : pPlayer->curr_weapon; + + if (RRRA && (g_netServer || numplayers > 1)) + { + if (pPlayer->on_motorcycle) + { + int const newSprite = A_Spawn(pPlayer->i, EMPTYBIKE); + sprite[newSprite].ang = fix16_to_int(pPlayer->q16ang); + sprite[newSprite].owner = pPlayer->ammo_amount[MOTORCYCLE_WEAPON]; + pPlayer->on_motorcycle = 0; + pPlayer->gotweapon &= ~(1<q16horiz = F16(100); + pPlayer->moto_do_bump = 0; + pPlayer->moto_speed = 0; + pPlayer->tilt_status = 0; + pPlayer->moto_drink = 0; + pPlayer->moto_bump_target = 0; + pPlayer->moto_bump = 0; + pPlayer->moto_turb = 0; + } + else if (pPlayer->on_boat) + { + int const newSprite = A_Spawn(pPlayer->i, EMPTYBOAT); + sprite[newSprite].ang = fix16_to_int(pPlayer->q16ang); + sprite[newSprite].owner = pPlayer->ammo_amount[BOAT_WEAPON]; + pPlayer->on_boat = 0; + pPlayer->gotweapon &= ~(1<q16horiz = F16(100); + pPlayer->moto_do_bump = 0; + pPlayer->moto_speed = 0; + pPlayer->tilt_status = 0; + pPlayer->moto_drink = 0; + pPlayer->moto_bump_target = 0; + pPlayer->moto_bump = 0; + pPlayer->moto_turb = 0; + } + } + + if (currentWeapon == KNEE_WEAPON || (unsigned)currentWeapon >= MAX_WEAPONS) + return; + + if (krand2() & 1) + A_Spawn(pPlayer->i, WeaponPickupSprites[currentWeapon]); + else + switch (DYNAMICWEAPONMAP(currentWeapon)) + { + case CHICKEN_WEAPON__STATIC: + if (!RRRA) break; + fallthrough__; + case RPG_WEAPON__STATIC: + case HANDBOMB_WEAPON__STATIC: A_Spawn(pPlayer->i, EXPLOSION2); break; + } + + if (RR) + { + for (bssize_t key = 0; key < 5; key++) + { + if (pPlayer->keys[key] == 1) + { + int const newSprite = A_Spawn(pPlayer->i, ACCESSCARD); + switch (key) + { + case 1: + sprite[newSprite].lotag = 100; + break; + case 2: + sprite[newSprite].lotag = 101; + break; + case 3: + sprite[newSprite].lotag = 102; + break; + case 4: + sprite[newSprite].lotag = 103; + break; + } + } + } + } +} + +void P_AddAmmo(DukePlayer_t * const pPlayer, int const weaponNum, int const addAmount) +{ + pPlayer->ammo_amount[weaponNum] += addAmount; + + if (pPlayer->ammo_amount[weaponNum] > pPlayer->max_ammo_amount[weaponNum]) + pPlayer->ammo_amount[weaponNum] = pPlayer->max_ammo_amount[weaponNum]; +} + +void P_AddWeapon(DukePlayer_t *pPlayer, int weaponNum) +{ + int8_t curr_weapon = pPlayer->curr_weapon; + + if (pPlayer->on_motorcycle || pPlayer->on_boat) + { + pPlayer->gotweapon |= (1<gotweapon |= (1<ammo_amount[GROW_WEAPON] = 1; + } + else if (weaponNum == RPG_WEAPON) + pPlayer->gotweapon |= (1<ammo_amount[SLINGBLADE_WEAPON] = 1; + return; + } + + if ((pPlayer->gotweapon & (1<gotweapon |= (1<gotweapon |= (1<ammo_amount[GROW_WEAPON] = 1; + } + if (RRRA) + { + if (weaponNum == RPG_WEAPON) + pPlayer->gotweapon |= (1<ammo_amount[SLINGBLADE_WEAPON] = 50; + } + + if (!RR || weaponNum != HANDBOMB_WEAPON) + curr_weapon = weaponNum; + } + else + curr_weapon = weaponNum; + + if (RR && weaponNum == HANDBOMB_WEAPON) + pPlayer->last_weapon = -1; + + pPlayer->random_club_frame = 0; + + if (pPlayer->holster_weapon == 0) + { + pPlayer->weapon_pos = -1; + pPlayer->last_weapon = pPlayer->curr_weapon; + } + else + { + pPlayer->weapon_pos = WEAPON_POS_RAISE; + pPlayer->holster_weapon = 0; + pPlayer->last_weapon = -1; + } + + pPlayer->kickback_pic = 0; + pPlayer->curr_weapon = curr_weapon; + + switch (DYNAMICWEAPONMAP(weaponNum)) + { + case SLINGBLADE_WEAPON__STATIC: + case KNEE_WEAPON__STATIC: + case TRIPBOMB_WEAPON__STATIC: + case HANDREMOTE_WEAPON__STATIC: + case HANDBOMB_WEAPON__STATIC: break; + case SHOTGUN_WEAPON__STATIC: A_PlaySound(SHOTGUN_COCK, pPlayer->i); break; + case PISTOL_WEAPON__STATIC: A_PlaySound(INSERT_CLIP, pPlayer->i); break; + default: A_PlaySound(RR ? EJECT_CLIP : SELECT_WEAPON, pPlayer->i); break; + } +} + +void P_SelectNextInvItem(DukePlayer_t *pPlayer) +{ + if (pPlayer->inv_amount[GET_FIRSTAID] > 0) + pPlayer->inven_icon = ICON_FIRSTAID; + else if (pPlayer->inv_amount[GET_STEROIDS] > 0) + pPlayer->inven_icon = ICON_STEROIDS; + else if (pPlayer->inv_amount[GET_JETPACK] > 0) + pPlayer->inven_icon = ICON_JETPACK; + else if (pPlayer->inv_amount[GET_HOLODUKE] > 0) + pPlayer->inven_icon = ICON_HOLODUKE; + else if (pPlayer->inv_amount[GET_HEATS] > 0) + pPlayer->inven_icon = ICON_HEATS; + else if (pPlayer->inv_amount[GET_SCUBA] > 0) + pPlayer->inven_icon = ICON_SCUBA; + else if (pPlayer->inv_amount[GET_BOOTS] > 0) + pPlayer->inven_icon = ICON_BOOTS; + else + pPlayer->inven_icon = ICON_NONE; +} + +void P_CheckWeapon(DukePlayer_t *pPlayer) +{ + int playerNum; + int weaponNum; + + // if (pPlayer->reloading) + // return; + + if (pPlayer->wantweaponfire >= 0) + { + weaponNum = pPlayer->wantweaponfire; + pPlayer->wantweaponfire = -1; + + if (weaponNum == pPlayer->curr_weapon) + return; + + if ((pPlayer->gotweapon & (1<ammo_amount[weaponNum] > 0) + { + P_AddWeapon(pPlayer, weaponNum); + return; + } + } + + weaponNum = pPlayer->curr_weapon; + + if ((pPlayer->gotweapon & (1<ammo_amount[weaponNum] > 0) + return; + + playerNum = P_Get(pPlayer->i); + + int wpnInc = 0; + + for (wpnInc = 0; wpnInc <= (RR ? DEVISTATOR_WEAPON: FREEZE_WEAPON); ++wpnInc) + { + weaponNum = g_player[playerNum].wchoice[wpnInc]; + if (VOLUMEONE && weaponNum > SHRINKER_WEAPON) + continue; + + if (weaponNum == KNEE_WEAPON) + weaponNum = RR ? DEVISTATOR_WEAPON : FREEZE_WEAPON; + else weaponNum--; + + if (weaponNum == KNEE_WEAPON || ((pPlayer->gotweapon & (1<ammo_amount[weaponNum] > 0)) + break; + } + + if (wpnInc == HANDREMOTE_WEAPON) + weaponNum = KNEE_WEAPON; + + // Found the weapon + + pPlayer->last_weapon = pPlayer->curr_weapon; + pPlayer->random_club_frame = 0; + pPlayer->curr_weapon = weaponNum; + P_SetWeaponGamevars(playerNum, pPlayer); + VM_OnEvent(EVENT_CHANGEWEAPON, pPlayer->i, playerNum); + pPlayer->kickback_pic = 0; + if (pPlayer->holster_weapon == 1) + { + pPlayer->holster_weapon = 0; + pPlayer->weapon_pos = 10; + } + else pPlayer->weapon_pos = -1; +} + +static void DoWallTouchDamage(const DukePlayer_t *pPlayer, int32_t wallNum) +{ + vec3_t const davect = { pPlayer->pos.x + (sintable[(fix16_to_int(pPlayer->q16ang) + 512) & 2047] >> 9), + pPlayer->pos.y + (sintable[fix16_to_int(pPlayer->q16ang) & 2047] >> 9), pPlayer->pos.z }; + + A_DamageWall(pPlayer->i, wallNum, &davect, -1); +} + +static void P_CheckTouchDamage(DukePlayer_t *pPlayer, int touchObject) +{ + if (touchObject == -1) + return; + + if ((touchObject & 49152) == 49152) + { + int const touchSprite = touchObject & (MAXSPRITES - 1); + + if (RRRA) + { + switch (DYNAMICTILEMAP(sprite[touchSprite].picnum)) + { + case RRTILE2430__STATICRR: + case RRTILE2431__STATICRR: + case RRTILE2432__STATICRR: + case RRTILE2443__STATICRR: + case RRTILE2446__STATICRR: + case RRTILE2451__STATICRR: + case RRTILE2455__STATICRR: + if (pPlayer->hurt_delay2 < 8) + { + sprite[pPlayer->i].extra -= 5; + + pPlayer->hurt_delay2 = 16; + P_PalFrom(pPlayer, 32, 32, 0, 0); + A_PlaySound(DUKE_LONGTERM_PAIN, pPlayer->i); + } + break; + } + return; + } + if (sprite[touchSprite].picnum == CACTUS) + { + if (pPlayer->hurt_delay < 8) + { + sprite[pPlayer->i].extra -= 5; + + pPlayer->hurt_delay = 16; + P_PalFrom(pPlayer, 32, 32, 0, 0); + A_PlaySound(DUKE_LONGTERM_PAIN, pPlayer->i); + } + } + return; + } + + if ((touchObject & 49152) != 32768) + return; + + int const touchWall = touchObject & (MAXWALLS-1); + + if (pPlayer->hurt_delay > 0) + pPlayer->hurt_delay--; + else if (wall[touchWall].cstat & FORCEFIELD_CSTAT) + { + int const forcePic = G_GetForcefieldPicnum(touchWall); + + switch (DYNAMICTILEMAP(forcePic)) + { + case W_FORCEFIELD__STATIC: + if (RR) break; + sprite[pPlayer->i].extra -= 5; + + pPlayer->hurt_delay = 16; + P_PalFrom(pPlayer, 32, 32,0,0); + + pPlayer->vel.x = -(sintable[(fix16_to_int(pPlayer->q16ang)+512)&2047]<<8); + pPlayer->vel.y = -(sintable[(fix16_to_int(pPlayer->q16ang))&2047]<<8); + A_PlaySound(DUKE_LONGTERM_PAIN,pPlayer->i); + + DoWallTouchDamage(pPlayer, touchWall); + break; + + case BIGFORCE__STATIC: + pPlayer->hurt_delay = GAMETICSPERSEC; + DoWallTouchDamage(pPlayer, touchWall); + break; + } + } +} + +static int P_CheckFloorDamage(DukePlayer_t *pPlayer, int floorTexture) +{ + spritetype * const pSprite = &sprite[pPlayer->i]; + + if ((unsigned)(floorTexture) >= MAXTILES) + return 0; + + switch (DYNAMICTILEMAP(floorTexture)) + { + case HURTRAIL__STATIC: + if (rnd(32)) + { + if (pPlayer->inv_amount[GET_BOOTS] > 0) + return 1; + else + { + if (!A_CheckSoundPlaying(pPlayer->i, DUKE_LONGTERM_PAIN)) + A_PlaySound(DUKE_LONGTERM_PAIN, pPlayer->i); + + P_PalFrom(pPlayer, 32, 64, 64, 64); + + pSprite->extra -= 1 + (krand2() & 3); + if (!A_CheckSoundPlaying(pPlayer->i, SHORT_CIRCUIT)) + A_PlaySound(SHORT_CIRCUIT, pPlayer->i); + + return 0; + } + } + break; + + case FLOORSLIME__STATIC: + if (rnd(16)) + { + if (pPlayer->inv_amount[GET_BOOTS] > 0) + return 1; + else + { + if (!A_CheckSoundPlaying(pPlayer->i, DUKE_LONGTERM_PAIN)) + A_PlaySound(DUKE_LONGTERM_PAIN, pPlayer->i); + + P_PalFrom(pPlayer, 32, 0, 8, 0); + pSprite->extra -= 1 + (krand2() & 3); + + return 0; + } + } + break; + + case FLOORPLASMA__STATIC: + if (rnd(32)) + { + if (pPlayer->inv_amount[GET_BOOTS] > 0) + return 1; + else + { + if (!A_CheckSoundPlaying(pPlayer->i, DUKE_LONGTERM_PAIN)) + A_PlaySound(DUKE_LONGTERM_PAIN, pPlayer->i); + + P_PalFrom(pPlayer, 32, 8, 0, 0); + pSprite->extra -= 1 + (krand2() & 3); + + return 0; + } + } + break; + } + + return 0; +} + + +int P_FindOtherPlayer(int playerNum, int32_t *pDist) +{ + int closestPlayer = playerNum; + int closestPlayerDist = INT32_MAX; + + for (bssize_t TRAVERSE_CONNECT(otherPlayer)) + { + if (playerNum != otherPlayer && sprite[g_player[otherPlayer].ps->i].extra > 0) + { + int otherPlayerDist = klabs(g_player[otherPlayer].ps->opos.x - g_player[playerNum].ps->pos.x) + + klabs(g_player[otherPlayer].ps->opos.y - g_player[playerNum].ps->pos.y) + + (klabs(g_player[otherPlayer].ps->opos.z - g_player[playerNum].ps->pos.z) >> 4); + + if (otherPlayerDist < closestPlayerDist) + { + closestPlayer = otherPlayer; + closestPlayerDist = otherPlayerDist; + } + } + } + + *pDist = closestPlayerDist; + + return closestPlayer; +} + +void P_FragPlayer(int playerNum) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + spritetype *const pSprite = &sprite[pPlayer->i]; + + //if (g_netClient) // [75] The server should not overwrite its own randomseed + // randomseed = ticrandomseed; + + if (pSprite->pal != 1) + { + P_PalFrom(pPlayer, 63, 63, 0, 0); + + pPlayer->pos.z -= ZOFFSET2; + pSprite->z -= ZOFFSET2; + + int32_t const r1 = krand2(), r2 = krand2(); + pPlayer->dead_flag = (512 - ((r2 & 1) << 10) + (r1 & 255) - 512) & 2047; + + if (pPlayer->dead_flag == 0) + pPlayer->dead_flag++; + +#ifndef NETCODE_DISABLE + //if (g_netServer) + //{ + // packbuf[0] = PACKET_FRAG; + // packbuf[1] = playerNum; + // packbuf[2] = pPlayer->frag_ps; + // packbuf[3] = actor[pPlayer->i].picnum; + // B_BUF32(&packbuf[4], ticrandomseed); + // packbuf[8] = myconnectindex; + // + // enet_host_broadcast(g_netServer, CHAN_GAMESTATE, enet_packet_create(packbuf, 9, ENET_PACKET_FLAG_RELIABLE)); + //} +#endif + } + + pPlayer->jetpack_on = 0; + pPlayer->holoduke_on = -1; + + if (!RR) + S_StopEnvSound(DUKE_JETPACK_IDLE, pPlayer->i); + + S_StopEnvSound(-1, pPlayer->i, CHAN_VOICE); + + if (pSprite->pal != 1 && (pSprite->cstat & 32768) == 0) + pSprite->cstat = 0; + + if ((g_netServer || ud.multimode > 1) && (pSprite->pal != 1 || (pSprite->cstat & 32768))) + { + if (pPlayer->frag_ps != playerNum) + { + if (GTFLAGS(GAMETYPE_TDM) && g_player[pPlayer->frag_ps].ps->team == g_player[playerNum].ps->team) + g_player[pPlayer->frag_ps].ps->fraggedself++; + else + { + g_player[pPlayer->frag_ps].ps->frag++; + g_player[pPlayer->frag_ps].frags[playerNum]++; + g_player[playerNum].frags[playerNum]++; // deaths + } + + if (playerNum == screenpeek) + { + quoteMgr.InitializeQuote(QUOTE_RESERVED, "Killed by %s", &g_player[pPlayer->frag_ps].user_name[0]); + P_DoQuote(QUOTE_RESERVED, pPlayer); + } + else + { + quoteMgr.InitializeQuote(QUOTE_RESERVED2, "Killed %s", &g_player[playerNum].user_name[0]); + P_DoQuote(QUOTE_RESERVED2, g_player[pPlayer->frag_ps].ps); + } + + if (cl_obituaries) + { + Bsprintf(tempbuf, quoteMgr.GetQuote(OBITQUOTEINDEX + (krand2() % g_numObituaries)), + &g_player[pPlayer->frag_ps].user_name[0], &g_player[playerNum].user_name[0]); + G_AddUserQuote(tempbuf); + } + else + krand2(); + } + else + { + if (actor[pPlayer->i].picnum != APLAYERTOP) + { + pPlayer->fraggedself++; + if ((unsigned)pPlayer->wackedbyactor < MAXTILES && A_CheckEnemyTile(sprite[pPlayer->wackedbyactor].picnum)) + Bsprintf(tempbuf, quoteMgr.GetQuote(OBITQUOTEINDEX + (krand2() % g_numObituaries)), "A monster", + &g_player[playerNum].user_name[0]); + else if (actor[pPlayer->i].picnum == NUKEBUTTON) + Bsprintf(tempbuf, "^02%s^02 tried to leave", &g_player[playerNum].user_name[0]); + else + { + // random suicide death string + Bsprintf(tempbuf, quoteMgr.GetQuote(SUICIDEQUOTEINDEX + (krand2() % g_numSelfObituaries)), + &g_player[playerNum].user_name[0]); + } + } + else + Bsprintf(tempbuf, "^02%s^02 switched to team %d", &g_player[playerNum].user_name[0], pPlayer->team + 1); + + if (cl_obituaries) + G_AddUserQuote(tempbuf); + } + pPlayer->frag_ps = playerNum; + pus = NUMPAGES; + } +} + +# define PIPEBOMB_CONTROL(playerNum) (Gv_GetVarByLabel("PIPEBOMB_CONTROL", PIPEBOMB_REMOTE, -1, playerNum)) + +static void P_ProcessWeapon(int playerNum) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + uint8_t *const weaponFrame = &pPlayer->kickback_pic; + int const playerShrunk = (sprite[pPlayer->i].yrepeat < (RR ? 8 : 32)); + uint32_t playerBits = g_player[playerNum].input->bits; + int const sectorLotag = sector[pPlayer->cursectnum].lotag; + + if (RR) + { + if (pPlayer->hbomb_offset > 0) + { + if (ud.god) + { + pPlayer->hbomb_time = 45; + pPlayer->hbomb_offset = 0; + } + else if (pPlayer->hbomb_time <= 0 && (*weaponFrame) < 5) + { + S_PlaySound(PIPEBOMB_EXPLODE); + P_QuickKill(pPlayer); + } + } + } +#define WEAPON2_CLIP 20 + if (NAM_WW2GI && TEST_SYNC_KEY(playerBits, SK_HOLSTER)) // 'Holster Weapon + { + if (NAM) + { + if (pPlayer->curr_weapon == PISTOL_WEAPON) + { + if (pPlayer->ammo_amount[PISTOL_WEAPON] > WEAPON2_CLIP) + { + // throw away the remaining clip + pPlayer->ammo_amount[PISTOL_WEAPON] -= pPlayer->ammo_amount[PISTOL_WEAPON] % WEAPON2_CLIP; + (*weaponFrame) = 3; + playerBits &= ~BIT(SK_FIRE); + } + return; + } + } + else + { + P_SetWeaponGamevars(playerNum, pPlayer); + + if (VM_OnEvent(EVENT_HOLSTER, pPlayer->i, playerNum) == 0) + { + if (PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_HOLSTER_CLEARS_CLIP) + { + int const weap = pPlayer->curr_weapon, clipcnt = PWEAPON(playerNum, weap, Clip); + + if (pPlayer->ammo_amount[weap] > clipcnt && (pPlayer->ammo_amount[weap] % clipcnt) != 0) + { + pPlayer->ammo_amount[weap] -= pPlayer->ammo_amount[weap] % clipcnt; + *weaponFrame = PWEAPON(playerNum, weap, TotalTime)+1; + playerBits &= ~BIT(SK_FIRE); // not firing... + } + + return; + } + } + } + } +#undef WEAPON2_CLIP + if (WW2GI ? PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_GLOWS : + (pPlayer->curr_weapon == SHRINKER_WEAPON || pPlayer->curr_weapon == GROW_WEAPON + || (RR && (pPlayer->curr_weapon == TRIPBOMB_WEAPON || pPlayer->curr_weapon == BOWLINGBALL_WEAPON)) + || (RRRA && (pPlayer->curr_weapon == KNEE_WEAPON || pPlayer->curr_weapon == SLINGBLADE_WEAPON)))) + { + pPlayer->random_club_frame += 64; // Glowing + +#ifdef POLYMER + if (pPlayer->kickback_pic == 0 && !RR) + { + spritetype *const pSprite = &sprite[pPlayer->i]; + int const glowXOffset = ((sintable[(pSprite->ang + 512) & 2047]) >> 7); + int const glowYOffset = ((sintable[(pSprite->ang) & 2047]) >> 7); + int const glowRange = 1024 + (sintable[pPlayer->random_club_frame & 2047] >> 3); + int const flashColor = (pPlayer->curr_weapon == GROW_WEAPON) ? 216+(52<<8)+(20<<16) : 176+(252<<8)+(120<<16); + + pSprite->x += glowXOffset; + pSprite->y += glowYOffset; + + G_AddGameLight(0, pPlayer->i, PHEIGHT, max(glowRange, 0), flashColor, PR_LIGHT_PRIO_HIGH_GAME); + + actor[pPlayer->i].lightcount = 2; + + pSprite->x -= glowXOffset; + pSprite->y -= glowYOffset; + } +#endif + } + + if (pPlayer->rapid_fire_hold == 1) + { + if (TEST_SYNC_KEY(playerBits, SK_FIRE)) + return; + pPlayer->rapid_fire_hold = 0; + } + + if (playerShrunk || pPlayer->tipincs || pPlayer->access_incs) + playerBits &= ~BIT(SK_FIRE); + else if (playerShrunk == 0 && (playerBits & (1 << 2)) && (*weaponFrame) == 0 && pPlayer->fist_incs == 0 && + pPlayer->last_weapon == -1 && (pPlayer->weapon_pos == 0 || pPlayer->holster_weapon == 1)) + { + pPlayer->crack_time = 777; + + if (pPlayer->holster_weapon == 1) + { + if (pPlayer->last_pissed_time <= (GAMETICSPERSEC * 218) && pPlayer->weapon_pos == WEAPON_POS_LOWER) + { + pPlayer->holster_weapon = 0; + pPlayer->weapon_pos = WEAPON_POS_RAISE; + P_DoQuote(QUOTE_WEAPON_RAISED, pPlayer); + } + } + else + { + P_SetWeaponGamevars(playerNum, pPlayer); + if (VM_OnEvent(EVENT_FIRE, pPlayer->i, playerNum) == 0) + { + switch (DYNAMICWEAPONMAP(WW2GI ? PWEAPON(playerNum, pPlayer->curr_weapon, WorksLike) : pPlayer->curr_weapon)) + { + case HANDBOMB_WEAPON__STATIC: + pPlayer->hbomb_hold_delay = 0; + if (pPlayer->ammo_amount[pPlayer->curr_weapon] > 0) + { + (*weaponFrame) = 1; + if (WW2GI && PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound) > 0) + A_PlaySound(PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound), pPlayer->i); + } + break; + + case HANDREMOTE_WEAPON__STATIC: + pPlayer->hbomb_hold_delay = 0; + (*weaponFrame) = 1; + if (WW2GI && PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound) > 0) + A_PlaySound(PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound), pPlayer->i); + break; + + case PISTOL_WEAPON__STATIC: + if (pPlayer->ammo_amount[PISTOL_WEAPON] > 0) + { + if (!WW2GI) + pPlayer->ammo_amount[PISTOL_WEAPON]--; + (*weaponFrame) = 1; + if (WW2GI && PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound) > 0) + A_PlaySound(PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound), pPlayer->i); + } + break; + + case SHOTGUN_WEAPON__STATIC: + if (pPlayer->ammo_amount[SHOTGUN_WEAPON] > 0 && pPlayer->random_club_frame == 0) + { + (*weaponFrame) = 1; + if (WW2GI && PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound) > 0) + A_PlaySound(PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound), pPlayer->i); + } + break; + + case TRIPBOMB_WEAPON__STATIC: + case BOWLINGBALL_WEAPON__STATIC: + if (RR) + { + if (pPlayer->ammo_amount[pPlayer->curr_weapon] > 0) + { + //pPlayer->ammo_amount[pPlayer->curr_weapon]--; + (*weaponFrame) = 1; + } + break; + } + if (pPlayer->curr_weapon == BOWLINGBALL) + break; + if (pPlayer->ammo_amount[pPlayer->curr_weapon] > 0) + { + hitdata_t hitData; + + hitscan((const vec3_t *)pPlayer, pPlayer->cursectnum, sintable[(fix16_to_int(pPlayer->q16ang) + 512) & 2047], + sintable[fix16_to_int(pPlayer->q16ang) & 2047], fix16_to_int(F16(100) - pPlayer->q16horiz - pPlayer->q16horizoff) * 32, &hitData, + CLIPMASK1); + + if ((hitData.sect < 0 || hitData.sprite >= 0) || + (hitData.wall >= 0 && sector[hitData.sect].lotag > 2)) + break; + + if (hitData.wall >= 0 && wall[hitData.wall].overpicnum >= 0) + if (wall[hitData.wall].overpicnum == BIGFORCE) + break; + + int spriteNum = headspritesect[hitData.sect]; + while (spriteNum >= 0) + { + if (sprite[spriteNum].picnum == TRIPBOMB && klabs(sprite[spriteNum].z - hitData.pos.z) < ZOFFSET4 && + ((sprite[spriteNum].x - hitData.pos.x) * (sprite[spriteNum].x - hitData.pos.x) + + (sprite[spriteNum].y - hitData.pos.y) * (sprite[spriteNum].y - hitData.pos.y)) < (290 * 290)) + break; + spriteNum = nextspritesect[spriteNum]; + } + + // ST_2_UNDERWATER + if (spriteNum == -1 && hitData.wall >= 0 && (wall[hitData.wall].cstat & 16) == 0) + if ((wall[hitData.wall].nextsector >= 0 && sector[wall[hitData.wall].nextsector].lotag <= 2) || + (wall[hitData.wall].nextsector == -1 && sector[hitData.sect].lotag <= 2)) + if (((hitData.pos.x - pPlayer->pos.x) * (hitData.pos.x - pPlayer->pos.x) + + (hitData.pos.y - pPlayer->pos.y) * (hitData.pos.y - pPlayer->pos.y)) < (290 * 290)) + { + pPlayer->pos.z = pPlayer->opos.z; + pPlayer->vel.z = 0; + (*weaponFrame) = 1; + if (WW2GI && PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound) > 0) + { + A_PlaySound(PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound), pPlayer->i); + } + } + } + break; + + case SHRINKER_WEAPON__STATIC: + if (pPlayer->ammo_amount[SHRINKER_WEAPON] > 0) + { + (*weaponFrame) = 1; + if (!WW2GI) + A_PlaySound(SHRINKER_FIRE, pPlayer->i); + else if (PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound) > 0) + A_PlaySound(PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound), pPlayer->i); + } + break; + + case GROW_WEAPON__STATIC: + if (pPlayer->ammo_amount[GROW_WEAPON] > 0) + { + (*weaponFrame) = 1; + if (!WW2GI) + A_PlaySound(RR ? 431 : EXPANDERSHOOT, pPlayer->i); + else if (PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound) > 0) + A_PlaySound(PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound), pPlayer->i); + } + break; + + case FREEZE_WEAPON__STATIC: + if (pPlayer->ammo_amount[pPlayer->curr_weapon] > 0) + { + (*weaponFrame) = 1; + if (!RR) + { + if (!WW2GI) + A_PlaySound(CAT_FIRE, pPlayer->i); + else if (PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound) > 0) + A_PlaySound(PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound), pPlayer->i); + } + } + break; + + case RPG_WEAPON__STATIC: + case CHAINGUN_WEAPON__STATIC: + if (pPlayer->ammo_amount[pPlayer->curr_weapon] > 0) + { + (*weaponFrame) = 1; + if (WW2GI && PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound) > 0) + A_PlaySound(PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound), pPlayer->i); + } + break; + + case DEVISTATOR_WEAPON__STATIC: + if (pPlayer->ammo_amount[pPlayer->curr_weapon] > 0) + { + (*weaponFrame) = 1; + pPlayer->hbomb_hold_delay = !pPlayer->hbomb_hold_delay; + if (!RR) + { + if (!WW2GI) + A_PlaySound(CAT_FIRE, pPlayer->i); + else if (PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound) > 0) + A_PlaySound(PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound), pPlayer->i); + } + } + break; + + case KNEE_WEAPON__STATIC: + case SLINGBLADE_WEAPON__STATIC: + if (RRRA) + { + if (pPlayer->ammo_amount[pPlayer->curr_weapon] > 0 && !pPlayer->quick_kick) + (*weaponFrame) = 1; + break; + } + if (RRRA && pPlayer->curr_weapon == SLINGBLADE) break; + if (pPlayer->quick_kick == 0) + { + (*weaponFrame) = 1; + if (WW2GI && PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound) > 0) + A_PlaySound(PWEAPON(playerNum, pPlayer->curr_weapon, InitialSound), pPlayer->i); + } + break; + + case CHICKEN_WEAPON__STATIC: + case MOTORCYCLE_WEAPON__STATIC: + case BOAT_WEAPON__STATIC: + if (!RRRA) break; + if (pPlayer->ammo_amount[pPlayer->curr_weapon] > 0) + { + (*weaponFrame) = 1; + } + break; + } + } + } + } + else if (*weaponFrame) + { + int spriteNum; + int flashColor = 0; + + if (RR) + { + switch (DYNAMICWEAPONMAP(pPlayer->curr_weapon)) + { + case HANDBOMB_WEAPON__STATIC: + if (*weaponFrame == 1) + S_PlaySound(401); + + if ((*weaponFrame) == 6 && TEST_SYNC_KEY(playerBits, SK_FIRE)) + pPlayer->rapid_fire_hold = 1; + + if (++(*weaponFrame) > 19) + { + *weaponFrame = 0; + pPlayer->curr_weapon = HANDREMOTE_WEAPON; + pPlayer->last_weapon = -1; + pPlayer->weapon_pos = WEAPON_POS_RAISE; + pPlayer->hbomb_time = 45; + pPlayer->hbomb_offset = 1; + S_PlaySound(402); + } + break; + + case HANDREMOTE_WEAPON__STATIC: + (*weaponFrame)++; + + if (pPlayer->hbomb_time < 0) + pPlayer->hbomb_on = 0; + + if ((*weaponFrame) == 39) + { + pPlayer->hbomb_on = 0; + pPlayer->noise_radius = 8192; + P_MadeNoise(playerNum); + } + if ((*weaponFrame) == 12) + { + pPlayer->ammo_amount[HANDBOMB_WEAPON]--; + if (pPlayer->ammo_amount[RPG_WEAPON]) + pPlayer->ammo_amount[RPG_WEAPON]--; + + //if (numplayers < 2 || g_netServer) + { + int pipeBombZvel; + int pipeBombFwdVel; + + if (pPlayer->on_ground && TEST_SYNC_KEY(playerBits, SK_CROUCH)) + { + pipeBombFwdVel = 15; + pipeBombZvel = (fix16_to_int(pPlayer->q16horiz + pPlayer->q16horizoff - F16(100)) * 20); + } + else + { + pipeBombFwdVel = 140; + pipeBombZvel = -512 - (fix16_to_int(pPlayer->q16horiz + pPlayer->q16horizoff - F16(100)) * 20); + } + + int pipeSpriteNum = A_InsertSprite(pPlayer->cursectnum, + pPlayer->pos.x+(sintable[(fix16_to_int(pPlayer->q16ang)+512)&2047]>>6), + pPlayer->pos.y+(sintable[fix16_to_int(pPlayer->q16ang)&2047]>>6), + pPlayer->pos.z,HEAVYHBOMB,-16,9,9, + fix16_to_int(pPlayer->q16ang),(pipeBombFwdVel+(pPlayer->hbomb_hold_delay<<5))*2,pipeBombZvel,pPlayer->i,1); + + if (pipeBombFwdVel == 15) + { + sprite[pipeSpriteNum].yvel = 3; + sprite[pipeSpriteNum].z += ZOFFSET3; + } + + if (A_GetHitscanRange(pPlayer->i) < 512) + { + sprite[pipeSpriteNum].ang += 1024; + sprite[pipeSpriteNum].zvel /= 3; + sprite[pipeSpriteNum].xvel /= 3; + } + } + + pPlayer->hbomb_on = 1; + } + else if (*weaponFrame < 12 && TEST_SYNC_KEY(playerBits, SK_FIRE)) + pPlayer->hbomb_hold_delay++; + + if (*weaponFrame == 40) + { + (*weaponFrame) = 0; + pPlayer->curr_weapon = HANDBOMB_WEAPON; + pPlayer->last_weapon = -1; + pPlayer->hbomb_offset = 0; + pPlayer->hbomb_time = 45; + if (pPlayer->ammo_amount[HANDBOMB_WEAPON] > 0) + { + P_AddWeapon(pPlayer, HANDBOMB_WEAPON); + pPlayer->weapon_pos = WEAPON_POS_LOWER; + } + else + P_CheckWeapon(pPlayer); + } + break; + + case PISTOL_WEAPON__STATIC: + if ((*weaponFrame) == 1) + { + A_Shoot(pPlayer->i, SHOTSPARK1); + A_PlaySound(PISTOL_FIRE, pPlayer->i); + pPlayer->noise_radius = 8192; + P_MadeNoise(playerNum); + + lastvisinc = (int32_t) totalclock+32; + pPlayer->visibility = 0; + flashColor = 255+(95<<8); + if (sectorLotag != 857) + { + pPlayer->vel.x -= sintable[(fix16_to_int(pPlayer->q16ang) + 512) & 2047] << 4; + pPlayer->vel.y -= sintable[fix16_to_int(pPlayer->q16ang) & 2047] << 4; + } + } + else if ((*weaponFrame) == 2 && pPlayer->ammo_amount[PISTOL_WEAPON] <= 0) + { + (*weaponFrame) = 0; + P_CheckWeapon(pPlayer); + } + + if (++(*weaponFrame) >= 22) + { + if (pPlayer->ammo_amount[PISTOL_WEAPON] <= 0) + { + (*weaponFrame) = 0; + P_CheckWeapon(pPlayer); + break; + } + else if ((pPlayer->ammo_amount[PISTOL_WEAPON]%6) == 0) + { + switch ((*weaponFrame)) + { + case 24: + A_PlaySound(EJECT_CLIP, pPlayer->i); + break; + case 30: + A_PlaySound(INSERT_CLIP, pPlayer->i); + break; + } + } + else + (*weaponFrame) = 38; + } + + if ((*weaponFrame) == 38) + { + (*weaponFrame) = 0; + P_CheckWeapon(pPlayer); + } + break; + + case SHOTGUN_WEAPON__STATIC: + + if (++(*weaponFrame) == 6 && pPlayer->shotgun_state[0] == 0 && pPlayer->ammo_amount[SHOTGUN_WEAPON] > 1 && TEST_SYNC_KEY(playerBits, SK_FIRE)) + pPlayer->shotgun_state[1] = 1; + if ((*weaponFrame) == 4) + { + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + + pPlayer->ammo_amount[SHOTGUN_WEAPON]--; + + A_PlaySound(SHOTGUN_FIRE, pPlayer->i); + + pPlayer->noise_radius = 8192; + P_MadeNoise(playerNum); + + lastvisinc = (int32_t) totalclock + 32; + pPlayer->visibility = 0; + flashColor = 255+(95<<8); + } + + if ((*weaponFrame) == 7) + { + if (pPlayer->shotgun_state[1]) + { + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + + pPlayer->ammo_amount[SHOTGUN_WEAPON]--; + + A_PlaySound(SHOTGUN_FIRE, pPlayer->i); + if (sectorLotag != 857) + { + pPlayer->vel.x -= sintable[(fix16_to_int(pPlayer->q16ang) + 512) & 2047] << 5; + pPlayer->vel.y -= sintable[fix16_to_int(pPlayer->q16ang) & 2047] << 5; + } + } else if (sectorLotag != 857) + { + pPlayer->vel.x -= sintable[(fix16_to_int(pPlayer->q16ang) + 512) & 2047] << 4; + pPlayer->vel.y -= sintable[fix16_to_int(pPlayer->q16ang) & 2047] << 4; + } + flashColor = 255+(95<<8); + } + + if (pPlayer->shotgun_state[0]) + { + switch (*weaponFrame) + { + case 16: + P_CheckWeapon(pPlayer); + break; + case 17: + A_PlaySound(SHOTGUN_COCK, pPlayer->i); + break; + case 28: + *weaponFrame = 0; + pPlayer->shotgun_state[0] = 0; + pPlayer->shotgun_state[1] = 0; + break; + } + } + else if (pPlayer->shotgun_state[1]) + { + switch (*weaponFrame) + { + case 26: + P_CheckWeapon(pPlayer); + break; + case 27: + A_PlaySound(SHOTGUN_COCK, pPlayer->i); + break; + case 38: + *weaponFrame = 0; + pPlayer->shotgun_state[0] = 0; + pPlayer->shotgun_state[1] = 0; + break; + } + } + else + { + switch (*weaponFrame) + { + case 16: + P_CheckWeapon(pPlayer); + *weaponFrame = 0; + pPlayer->shotgun_state[0] = 1; + pPlayer->shotgun_state[1] = 0; + break; + } + } + break; + + case CHAINGUN_WEAPON__STATIC: + pPlayer->q16horiz += F16(1); + pPlayer->recoil++; + if (++(*weaponFrame) <= 12) + { + if (((*weaponFrame) % 3) == 0) + { + pPlayer->ammo_amount[CHAINGUN_WEAPON]--; + + if (((*weaponFrame) % 3) == 0) + { + spriteNum = A_Spawn(pPlayer->i, SHELL); + + sprite[spriteNum].ang += 1024; + sprite[spriteNum].ang &= 2047; + sprite[spriteNum].xvel += 32; + sprite[spriteNum].z += (3 << 8); + A_SetSprite(spriteNum, CLIPMASK0); + } + + A_PlaySound(CHAINGUN_FIRE, pPlayer->i); + A_Shoot(pPlayer->i, CHAINGUN); + pPlayer->noise_radius = 8192; + P_MadeNoise(playerNum); + lastvisinc = (int32_t) totalclock + 32; + pPlayer->visibility = 0; + flashColor = 255+(95<<8); + if (sectorLotag != 857) + { + pPlayer->vel.x -= sintable[(fix16_to_int(pPlayer->q16ang) + 512) & 2047] << 4; + pPlayer->vel.y -= sintable[fix16_to_int(pPlayer->q16ang) & 2047] << 4; + } + P_CheckWeapon(pPlayer); + + if (!TEST_SYNC_KEY(playerBits, SK_FIRE)) + { + (*weaponFrame) = 0; + break; + } + } + } + else if ((*weaponFrame) > 10) + { + if (TEST_SYNC_KEY(playerBits, SK_FIRE)) + { + (*weaponFrame) = 1; + } + else + { + (*weaponFrame) = 0; + } + } + + break; + + case GROW_WEAPON__STATIC: + if ((*weaponFrame) > 3) + { + (*weaponFrame) = 0; + if (screenpeek == playerNum) + { + pus = 1; + } + + A_Shoot(pPlayer->i, GROWSPARK); + + pPlayer->noise_radius = 1024; + P_MadeNoise(playerNum); + P_CheckWeapon(pPlayer); + } + else + { + (*weaponFrame)++; + } + break; + + case SHRINKER_WEAPON__STATIC: + if ((*weaponFrame) == 1) + { + pPlayer->ammo_amount[SHRINKER_WEAPON]--; + + A_Shoot(pPlayer->i, SHRINKSPARK); + P_CheckWeapon(pPlayer); + } + if (++(*weaponFrame) > 20) + (*weaponFrame) = 0; + break; + + case DEVISTATOR_WEAPON__STATIC: + (*weaponFrame)++; + if ((*weaponFrame) == 2 || (*weaponFrame) == 4) + { + pPlayer->visibility = 0; + flashColor = 255 + (95 << 8); + lastvisinc = (int32_t) totalclock + 32; + A_PlaySound(CHAINGUN_FIRE, pPlayer->i); + A_Shoot(pPlayer->i, SHOTSPARK1); + pPlayer->noise_radius = 16384; + P_MadeNoise(playerNum); + pPlayer->ammo_amount[DEVISTATOR_WEAPON]--; + P_CheckWeapon(pPlayer); + } + if ((*weaponFrame) == 2) + { + pPlayer->q16ang += F16(16); + } + else if ((*weaponFrame) == 4) + { + pPlayer->q16ang -= F16(16); + } + if ((*weaponFrame) > 4) + (*weaponFrame) = 1; + if (!TEST_SYNC_KEY(playerBits, SK_FIRE)) + (*weaponFrame) = 0; + break; + + case MOTORCYCLE_WEAPON__STATIC: + if (!RRRA) break; + (*weaponFrame)++; + if ((*weaponFrame) == 2 || (*weaponFrame) == 4) + { + pPlayer->visibility = 0; + flashColor = 255 + (95 << 8); + lastvisinc = (int32_t) totalclock + 32; + A_PlaySound(CHAINGUN_FIRE, pPlayer->i); + A_Shoot(pPlayer->i, CHAINGUN); + pPlayer->noise_radius = 16384; + P_MadeNoise(playerNum); + pPlayer->ammo_amount[MOTORCYCLE_WEAPON]--; + if (pPlayer->ammo_amount[MOTORCYCLE_WEAPON] <= 0) + *weaponFrame = 0; + else + P_CheckWeapon(pPlayer); + } + if ((*weaponFrame) == 2) + { + pPlayer->q16ang += F16(4); + } + else if ((*weaponFrame) == 4) + { + pPlayer->q16ang -= F16(4); + } + if ((*weaponFrame) > 4) + (*weaponFrame) = 1; + if (!TEST_SYNC_KEY(playerBits, SK_FIRE)) + (*weaponFrame) = 0; + break; + + case BOAT_WEAPON__STATIC: + if (!RRRA) break; + if (*weaponFrame == 3) + { + pPlayer->moto_speed -= 20; + pPlayer->ammo_amount[BOAT_WEAPON]--; + A_Shoot(pPlayer->i, RRTILE1790); + } + (*weaponFrame)++; + if ((*weaponFrame) > 20) + { + (*weaponFrame) = 0; + P_CheckWeapon(pPlayer); + } + if (pPlayer->ammo_amount[BOAT_WEAPON] <= 0) + (*weaponFrame) = 0; + else + P_CheckWeapon(pPlayer); + break; + + case FREEZE_WEAPON__STATIC: + (*weaponFrame)++; + if ((*weaponFrame) >= 7 && (*weaponFrame) <= 11) + A_Shoot(pPlayer->i, FIRELASER); + + if ((*weaponFrame) == 5) + { + A_PlaySound(CAT_FIRE, pPlayer->i); + pPlayer->noise_radius = 2048; + P_MadeNoise(playerNum); + } + else if ((*weaponFrame) == 9) + { + pPlayer->ammo_amount[FREEZE_WEAPON]--; + pPlayer->visibility = 0; + flashColor = 72 + (88 << 8) + (140 << 16); + lastvisinc = (int32_t) totalclock + 32; + P_CheckWeapon(pPlayer); + } + else if ((*weaponFrame) == 12) + { + pPlayer->vel.x -= sintable[(fix16_to_int(pPlayer->q16ang) + 512) & 2047] << 4; + pPlayer->vel.y -= sintable[fix16_to_int(pPlayer->q16ang) & 2047] << 4; + pPlayer->q16horiz += F16(20); + pPlayer->recoil += 20; + } + if ((*weaponFrame) > 20) + (*weaponFrame) = 0; + break; + + case TRIPBOMB_WEAPON__STATIC: + if ((*weaponFrame) == 3) + { + int Zvel; + int FwdVel; + + if (playerNum == screenpeek) + pus = 1; + pPlayer->ammo_amount[TRIPBOMB_WEAPON]--; + pPlayer->gotweapon &= ~(1<on_ground && TEST_SYNC_KEY(playerBits, SK_CROUCH) && (!RRRA || !pPlayer->on_motorcycle)) + { + FwdVel = 15; + Zvel = (fix16_to_int(pPlayer->q16horiz + pPlayer->q16horizoff - F16(100)) * 20); + } + else + { + FwdVel = 32; + Zvel = -512 - (fix16_to_int(pPlayer->q16horiz + pPlayer->q16horizoff - F16(100)) * 20); + } + + A_InsertSprite(pPlayer->cursectnum, + pPlayer->pos.x+(sintable[(fix16_to_int(pPlayer->q16ang)+512)&2047]>>6), + pPlayer->pos.y+(sintable[fix16_to_int(pPlayer->q16ang)&2047]>>6), + pPlayer->pos.z,TRIPBOMBSPRITE,-16,9,9, + fix16_to_int(pPlayer->q16ang),FwdVel*2,Zvel,pPlayer->i,1); + } + (*weaponFrame)++; + if ((*weaponFrame) > 20) + { + (*weaponFrame) = 0; + P_CheckWeapon(pPlayer); + } + break; + + case BOWLINGBALL_WEAPON__STATIC: + if ((*weaponFrame) == 30) + { + pPlayer->ammo_amount[BOWLINGBALL_WEAPON]--; + A_PlaySound(354, pPlayer->i); + A_Shoot(pPlayer->i, BOWLINGBALL); + pPlayer->noise_radius = 1024; + P_MadeNoise(playerNum); + } + if ((*weaponFrame) < 30) + P_Thrust(pPlayer, 4); + (*weaponFrame)++; + if ((*weaponFrame) > 40) + { + (*weaponFrame) = 0; + pPlayer->gotweapon &= ~(1 << BOWLINGBALL_WEAPON); + P_CheckWeapon(pPlayer); + } + break; + + case KNEE_WEAPON__STATIC: + if (++(*weaponFrame) == 3) + A_PlaySound(426, pPlayer->i); + + if ((*weaponFrame) == 12) + { + A_Shoot(pPlayer->i, KNEE); + pPlayer->noise_radius = 1024; + P_MadeNoise(playerNum); + } + else if ((*weaponFrame) == 16) + (*weaponFrame) = 0; + + if (pPlayer->wantweaponfire >= 0) + P_CheckWeapon(pPlayer); + break; + + case SLINGBLADE_WEAPON__STATIC: + if (!RRRA) break; + if (++(*weaponFrame) == 3) + A_PlaySound(252, pPlayer->i); + + if ((*weaponFrame) == 8) + { + A_Shoot(pPlayer->i, SLINGBLADE); + pPlayer->noise_radius = 1024; + P_MadeNoise(playerNum); + } + else if ((*weaponFrame) == 16) + (*weaponFrame) = 0; + + if (pPlayer->wantweaponfire >= 0) + P_CheckWeapon(pPlayer); + break; + + case RPG_WEAPON__STATIC: + if (++(*weaponFrame) == 4) + { + pPlayer->ammo_amount[RPG_WEAPON]--; + if (pPlayer->ammo_amount[HANDBOMB_WEAPON]) + pPlayer->ammo_amount[HANDBOMB_WEAPON]--; + lastvisinc = (int32_t) totalclock + 32; + pPlayer->visibility = 0; + flashColor = 255+(95<<8); + A_Shoot(pPlayer->i, RPG); + pPlayer->noise_radius = 32768; + P_MadeNoise(playerNum); + P_CheckWeapon(pPlayer); + } + else if ((*weaponFrame) == 16) + A_PlaySound(450, pPlayer->i); + else if ((*weaponFrame) == 34) + (*weaponFrame) = 0; + break; + + case CHICKEN_WEAPON__STATIC: + if (!RRRA) break; + if (++(*weaponFrame) == 4) + { + pPlayer->ammo_amount[CHICKEN_WEAPON]--; + lastvisinc = (int32_t) totalclock + 32; + pPlayer->visibility = 0; + flashColor = 255+(95<<8); + A_Shoot(pPlayer->i, RPG2); + pPlayer->noise_radius = 32768; + P_MadeNoise(playerNum); + P_CheckWeapon(pPlayer); + } + else if ((*weaponFrame) == 16) + A_PlaySound(450, pPlayer->i); + else if ((*weaponFrame) == 34) + (*weaponFrame) = 0; + break; + } + } + else if (WW2GI) + { + if (PWEAPON(playerNum, pPlayer->curr_weapon, WorksLike) == HANDBOMB_WEAPON) + { + if (PWEAPON(playerNum, pPlayer->curr_weapon, HoldDelay) && ((*weaponFrame) == PWEAPON(playerNum, pPlayer->curr_weapon, FireDelay)) && TEST_SYNC_KEY(playerBits, SK_FIRE)) + { + pPlayer->rapid_fire_hold = 1; + return; + } + + if (++(*weaponFrame) == PWEAPON(playerNum, pPlayer->curr_weapon, HoldDelay)) + { + pPlayer->ammo_amount[pPlayer->curr_weapon]--; + + //int pipeBombType; + int pipeBombZvel; + int pipeBombFwdVel; + + if (pPlayer->on_ground && TEST_SYNC_KEY(playerBits, SK_CROUCH)) + { + pipeBombFwdVel = 15; + pipeBombZvel = (fix16_to_int(pPlayer->q16horiz + pPlayer->q16horizoff - F16(100)) * 20); + } + else + { + pipeBombFwdVel = 140; + pipeBombZvel = -512 - (fix16_to_int(pPlayer->q16horiz + pPlayer->q16horizoff - F16(100)) * 20); + } + + int pipeSpriteNum = A_InsertSprite(pPlayer->cursectnum, + pPlayer->pos.x+(sintable[(fix16_to_int(pPlayer->q16ang)+512)&2047]>>6), + pPlayer->pos.y+(sintable[fix16_to_int(pPlayer->q16ang)&2047]>>6), + pPlayer->pos.z,PWEAPON(playerNum, pPlayer->curr_weapon, Shoots),-16,9,9, + fix16_to_int(pPlayer->q16ang),(pipeBombFwdVel+(pPlayer->hbomb_hold_delay<<5)),pipeBombZvel,pPlayer->i,1); + + int pipeLifeTime = Gv_GetVarByLabel("GRENADE_LIFETIME", NAM_GRENADE_LIFETIME, -1, playerNum); + int pipeLifeVariance = Gv_GetVarByLabel("GRENADE_LIFETIME_VAR", NAM_GRENADE_LIFETIME_VAR, -1, playerNum); + sprite[pipeSpriteNum].extra = pipeLifeTime + + mulscale14(krand2(), pipeLifeVariance) + - pipeLifeVariance; + + if (pipeBombFwdVel == 15) + { + sprite[pipeSpriteNum].yvel = 3; + sprite[pipeSpriteNum].z += ZOFFSET3; + } + + if (A_GetHitscanRange(pPlayer->i) < 512) + { + sprite[pipeSpriteNum].ang += 1024; + sprite[pipeSpriteNum].zvel /= 3; + sprite[pipeSpriteNum].xvel /= 3; + } + + pPlayer->hbomb_on = 1; + } + else if ((*weaponFrame) < PWEAPON(playerNum, pPlayer->curr_weapon, HoldDelay) && TEST_SYNC_KEY(playerBits, SK_FIRE)) + pPlayer->hbomb_hold_delay++; + else if ((*weaponFrame) > PWEAPON(playerNum, pPlayer->curr_weapon, TotalTime)) + { + (*weaponFrame) = 0; + P_CheckWeapon(pPlayer); + } + } + else if (PWEAPON(playerNum, pPlayer->curr_weapon, WorksLike) == HANDREMOTE_WEAPON) + { + if (++(*weaponFrame) == PWEAPON(playerNum, pPlayer->curr_weapon, FireDelay)) + { + if (PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_BOMB_TRIGGER) + pPlayer->hbomb_on = 0; + + if (PWEAPON(playerNum, pPlayer->curr_weapon, Shoots) != 0) + { + if (!(PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_NOVISIBLE)) + { + lastvisinc = (int32_t) totalclock+32; + pPlayer->visibility = 0; + } + + P_SetWeaponGamevars(playerNum, pPlayer); + A_Shoot(pPlayer->i, PWEAPON(playerNum, pPlayer->curr_weapon, Shoots)); + } + } + + if ((*weaponFrame) >= PWEAPON(playerNum, pPlayer->curr_weapon, TotalTime)) + { + (*weaponFrame) = 0; + if (pPlayer->ammo_amount[HANDBOMB_WEAPON] > 0) + P_AddWeapon(pPlayer, HANDBOMB_WEAPON); + else P_CheckWeapon(pPlayer); + } + } + else + { + // the basic weapon... + (*weaponFrame)++; + + if (PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_CHECKATRELOAD) + { + if (*weaponFrame == PWEAPON(playerNum, pPlayer->curr_weapon, Reload)) + P_CheckWeapon(pPlayer); + } + + if (PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_STANDSTILL + && *weaponFrame < (PWEAPON(playerNum, pPlayer->curr_weapon, FireDelay)+1)) + { + pPlayer->pos.z = pPlayer->opos.z; + pPlayer->vel.z = 0; + } + + if (*weaponFrame == PWEAPON(playerNum, pPlayer->curr_weapon, Sound2Time)) + if (PWEAPON(playerNum, pPlayer->curr_weapon, Sound2Sound) > 0) + A_PlaySound(PWEAPON(playerNum, pPlayer->curr_weapon, Sound2Sound),pPlayer->i); + + if (*weaponFrame == PWEAPON(playerNum, pPlayer->curr_weapon, SpawnTime)) + P_DoWeaponSpawn(playerNum); + + if (*weaponFrame == PWEAPON(playerNum, pPlayer->curr_weapon, FireDelay)) + P_FireWeapon(playerNum); + + if (*weaponFrame > PWEAPON(playerNum, pPlayer->curr_weapon, FireDelay) + && *weaponFrame < PWEAPON(playerNum, pPlayer->curr_weapon, TotalTime)) + { + if (PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_AUTOMATIC) + { + if (TEST_SYNC_KEY(playerBits, SK_FIRE) == 0) + *weaponFrame = PWEAPON(playerNum, pPlayer->curr_weapon, TotalTime); + if (PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_FIREEVERYTHIRD) + { + if (((*(weaponFrame))%3) == 0) + { + P_FireWeapon(playerNum); + P_DoWeaponSpawn(playerNum); + } + } + if (PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_FIREEVERYOTHER) + { + P_FireWeapon(playerNum); + P_DoWeaponSpawn(playerNum); + } + } + } + else if (*weaponFrame >= PWEAPON(playerNum, pPlayer->curr_weapon, TotalTime)) + { + if (PWEAPON(playerNum, pPlayer->curr_weapon, Reload) > PWEAPON(playerNum, pPlayer->curr_weapon, TotalTime) && pPlayer->ammo_amount[pPlayer->curr_weapon] > 0 + && PWEAPON(playerNum, pPlayer->curr_weapon, Clip) && pPlayer->ammo_amount[pPlayer->curr_weapon] % PWEAPON(playerNum, pPlayer->curr_weapon, Clip) == 0) + { + int const weaponReloadTime = PWEAPON(playerNum, pPlayer->curr_weapon, Reload) + - PWEAPON(playerNum, pPlayer->curr_weapon, TotalTime); + + if ((*weaponFrame) == (PWEAPON(playerNum, pPlayer->curr_weapon, TotalTime)+1)) + { + A_PlaySound(EJECT_CLIP, pPlayer->i); + } + else if ((*weaponFrame) == + (PWEAPON(playerNum, pPlayer->curr_weapon, Reload) - (weaponReloadTime / 3))) + { + A_PlaySound(INSERT_CLIP, pPlayer->i); + } + if ((*weaponFrame) >= (PWEAPON(playerNum, pPlayer->curr_weapon, Reload))) + { + *weaponFrame = 0; + } + } + else + { + if (PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_AUTOMATIC) + { + if (TEST_SYNC_KEY(playerBits, SK_FIRE)) + { + *weaponFrame = + (PWEAPON(playerNum, pPlayer->curr_weapon, Flags) & WEAPON_RANDOMRESTART) ? 1 + (krand2() & 3) : 1; + } + else *weaponFrame = 0; + } + else *weaponFrame = 0; + } + } + } + } + else + { + switch (DYNAMICWEAPONMAP(pPlayer->curr_weapon)) + { + case HANDBOMB_WEAPON__STATIC: + if ((*weaponFrame) == 6 && TEST_SYNC_KEY(playerBits, SK_FIRE)) + { + pPlayer->rapid_fire_hold = 1; + break; + } + + if (++(*weaponFrame) == 12) + { + pPlayer->ammo_amount[pPlayer->curr_weapon]--; + + //if (numplayers < 2 || g_netServer) + { + int pipeBombZvel; + int pipeBombFwdVel; + + if (pPlayer->on_ground && TEST_SYNC_KEY(playerBits, SK_CROUCH)) + { + pipeBombFwdVel = 15; + pipeBombZvel = (fix16_to_int(pPlayer->q16horiz + pPlayer->q16horizoff - F16(100)) * 20); + } + else + { + pipeBombFwdVel = 140; + pipeBombZvel = -512 - (fix16_to_int(pPlayer->q16horiz + pPlayer->q16horizoff - F16(100)) * 20); + } + + int pipeSpriteNum = A_InsertSprite(pPlayer->cursectnum, + pPlayer->pos.x+(sintable[(fix16_to_int(pPlayer->q16ang)+512)&2047]>>6), + pPlayer->pos.y+(sintable[fix16_to_int(pPlayer->q16ang)&2047]>>6), + pPlayer->pos.z,HEAVYHBOMB,-16,9,9, + fix16_to_int(pPlayer->q16ang),(pipeBombFwdVel+(pPlayer->hbomb_hold_delay<<5)),pipeBombZvel,pPlayer->i,1); + + if (NAM) + sprite[pipeSpriteNum].extra = mulscale(krand2(), 30, 14)+90; + + if (pipeBombFwdVel == 15) + { + sprite[pipeSpriteNum].yvel = 3; + sprite[pipeSpriteNum].z += ZOFFSET3; + } + + if (A_GetHitscanRange(pPlayer->i) < 512) + { + sprite[pipeSpriteNum].ang += 1024; + sprite[pipeSpriteNum].zvel /= 3; + sprite[pipeSpriteNum].xvel /= 3; + } + } + + pPlayer->hbomb_on = 1; + } + else if ((*weaponFrame) < 12 && TEST_SYNC_KEY(playerBits, SK_FIRE)) + pPlayer->hbomb_hold_delay++; + else if ((*weaponFrame) > 19) + { + (*weaponFrame) = 0; + if (NAM) + { + // don't change to remote when in NAM: grenades are timed + P_CheckWeapon(pPlayer); + } + else + { + pPlayer->weapon_pos = WEAPON_POS_RAISE; + pPlayer->curr_weapon = HANDREMOTE_WEAPON; + pPlayer->last_weapon = -1; + } + } + break; + + case HANDREMOTE_WEAPON__STATIC: + if (++(*weaponFrame) == 2) + { + pPlayer->hbomb_on = 0; + } + + if ((*weaponFrame) == 10) + { + (*weaponFrame) = 0; + /// WHAT THE HELL DOES THIS DO....????????????? + int weapon = NAM ? TRIPBOMB_WEAPON : HANDBOMB_WEAPON; + if (pPlayer->ammo_amount[weapon] > 0) + { + P_AddWeapon(pPlayer, weapon); + } + else + { + P_CheckWeapon(pPlayer); + } + } + break; + + case PISTOL_WEAPON__STATIC: + if ((*weaponFrame) == 1) + { + A_Shoot(pPlayer->i, SHOTSPARK1); + A_PlaySound(PISTOL_FIRE, pPlayer->i); + lastvisinc = (int32_t) totalclock+32; + pPlayer->visibility = 0; + flashColor = 255+(95<<8); + } + else if ((*weaponFrame) == 2) + { + A_Spawn(pPlayer->i, SHELL); + } + + if (++(*weaponFrame) >= 5) + { + if (pPlayer->ammo_amount[PISTOL_WEAPON] <= 0 || (pPlayer->ammo_amount[PISTOL_WEAPON]%(NAM ? 20 : 12))) + { + (*weaponFrame) = 0; + P_CheckWeapon(pPlayer); + } + else + { + switch ((*weaponFrame)) + { + case 5: + A_PlaySound(EJECT_CLIP, pPlayer->i); + break; + case 8: + A_PlaySound(INSERT_CLIP, pPlayer->i); + break; + } + } + } + + if ((*weaponFrame) == (NAM ? 50 : 27)) + { + (*weaponFrame) = 0; + P_CheckWeapon(pPlayer); + } + break; + + case SHOTGUN_WEAPON__STATIC: + if (++(*weaponFrame) == 4) + { + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + A_Shoot(pPlayer->i, SHOTGUN); + + pPlayer->ammo_amount[SHOTGUN_WEAPON]--; + + A_PlaySound(SHOTGUN_FIRE, pPlayer->i); + + lastvisinc = (int32_t) totalclock + 32; + pPlayer->visibility = 0; + flashColor = 255+(95<<8); + } + + switch ((*weaponFrame)) + { + case 13: + P_CheckWeapon(pPlayer); + break; + case 15: + A_PlaySound(SHOTGUN_COCK, pPlayer->i); + break; + case 17: + case 20: + pPlayer->kickback_pic++; + break; + case 24: + spriteNum = A_Spawn(pPlayer->i, SHOTGUNSHELL); + sprite[spriteNum].ang += 1024; + A_SetSprite(spriteNum, CLIPMASK0); + sprite[spriteNum].ang += 1024; + pPlayer->kickback_pic++; + break; + case 31: + (*weaponFrame) = 0; + return; + } + break; + + case CHAINGUN_WEAPON__STATIC: + if (++(*weaponFrame) <= 12) + { + if (((*weaponFrame) % 3) == 0) + { + pPlayer->ammo_amount[CHAINGUN_WEAPON]--; + + if (((*weaponFrame) % 3) == 0) + { + spriteNum = A_Spawn(pPlayer->i, SHELL); + + sprite[spriteNum].ang += 1024; + sprite[spriteNum].ang &= 2047; + sprite[spriteNum].xvel += 32; + sprite[spriteNum].z += (3 << 8); + A_SetSprite(spriteNum, CLIPMASK0); + } + + A_PlaySound(CHAINGUN_FIRE, pPlayer->i); + A_Shoot(pPlayer->i, CHAINGUN); + lastvisinc = (int32_t) totalclock + 32; + pPlayer->visibility = 0; + flashColor = 255+(95<<8); + P_CheckWeapon(pPlayer); + + if (!TEST_SYNC_KEY(playerBits, SK_FIRE)) + { + (*weaponFrame) = 0; + break; + } + } + } + else if ((*weaponFrame) > 10) + { + if (TEST_SYNC_KEY(playerBits, SK_FIRE)) + { + (*weaponFrame) = 1; + } + else + { + (*weaponFrame) = 0; + } + } + + break; + + case GROW_WEAPON__STATIC: + if ((!NAM && (*weaponFrame) > 3) || (NAM && ++(*weaponFrame) == 3)) + { + if (NAM) + { + (*weaponFrame)++; + if (pPlayer->ammo_amount[GROW_WEAPON] <= 1) + (*weaponFrame) = 0; + } + else + (*weaponFrame) = 0; + if (screenpeek == playerNum) + { + pus = 1; + } + + pPlayer->ammo_amount[GROW_WEAPON]--; + + A_Shoot(pPlayer->i, GROWSPARK); + + pPlayer->visibility = 0; + flashColor = 216+(52<<8)+(20<<16); + lastvisinc = (int32_t) totalclock + 32; + P_CheckWeapon(pPlayer); + } + else if (!NAM) + { + (*weaponFrame)++; + } + if (NAM && (*weaponFrame) > 30) + { + // reload now... + (*weaponFrame) = 0; + + pPlayer->visibility = 0; + flashColor = 216+(52<<8)+(20<<16); + lastvisinc = (int32_t) totalclock + 32; + P_CheckWeapon(pPlayer); + P_CheckWeapon(pPlayer); + } + break; + + case SHRINKER_WEAPON__STATIC: + if ((!NAM && (*weaponFrame) > 10) || (NAM && (*weaponFrame) == 10)) + { + if (NAM) + { + // fire now, but wait for reload... + (*weaponFrame)++; + } + else + (*weaponFrame) = 0; + + pPlayer->ammo_amount[SHRINKER_WEAPON]--; + + A_Shoot(pPlayer->i, SHRINKER); + + if (!NAM) + { + pPlayer->visibility = 0; + flashColor = 176+(252<<8)+(120<<16); + lastvisinc = (int32_t) totalclock + 32; + P_CheckWeapon(pPlayer); + } + } + else if (NAM && (*weaponFrame) > 30) + { + (*weaponFrame) = 0; + pPlayer->visibility = 0; + flashColor = 176+(252<<8)+(120<<16); + lastvisinc = (int32_t) totalclock + 32; + P_CheckWeapon(pPlayer); + } + else + { + (*weaponFrame)++; + } + break; + + case DEVISTATOR_WEAPON__STATIC: + if ((*weaponFrame) > 0) + { + if (++(*weaponFrame) & 1) + { + pPlayer->visibility = 0; + flashColor = 255+(95<<8); + lastvisinc = (int32_t) totalclock + 32; + A_Shoot(pPlayer->i, RPG); + pPlayer->ammo_amount[DEVISTATOR_WEAPON]--; + P_CheckWeapon(pPlayer); + } + if ((*weaponFrame) > 5) + { + (*weaponFrame) = 0; + } + } + break; + + case FREEZE_WEAPON__STATIC: + if ((*weaponFrame) < 4) + { + if (++(*weaponFrame) == 3) + { + pPlayer->ammo_amount[FREEZE_WEAPON]--; + pPlayer->visibility = 0; + flashColor = 72+(88<<8)+(140<<16); + lastvisinc = (int32_t) totalclock + 32; + A_Shoot(pPlayer->i, FREEZEBLAST); + P_CheckWeapon(pPlayer); + } + if (sprite[pPlayer->i].xrepeat < 32) + { + (*weaponFrame) = 0; + } + } + else + { + if (TEST_SYNC_KEY(playerBits, SK_FIRE)) + { + (*weaponFrame) = 1; + A_PlaySound(CAT_FIRE, pPlayer->i); + } + else + { + (*weaponFrame) = 0; + } + } + break; + + case TRIPBOMB_WEAPON__STATIC: + if ((*weaponFrame) < 4) + { + pPlayer->pos.z = pPlayer->opos.z; + pPlayer->vel.z = 0; + if ((*weaponFrame) == 3) + { + A_Shoot(pPlayer->i, HANDHOLDINGLASER); + } + } + if ((*weaponFrame) == 16) + { + (*weaponFrame) = 0; + P_CheckWeapon(pPlayer); + pPlayer->weapon_pos = WEAPON_POS_LOWER; + } + else + { + (*weaponFrame)++; + } + break; + + case KNEE_WEAPON__STATIC: + if (++(*weaponFrame) == 7) + { + A_Shoot(pPlayer->i, KNEE); + } + else if ((*weaponFrame) == 14) + { + if (TEST_SYNC_KEY(playerBits, SK_FIRE)) + { + (*weaponFrame) = 1+(krand2()&3); + } + else + { + (*weaponFrame) = 0; + } + } + + if (pPlayer->wantweaponfire >= 0) + { + P_CheckWeapon(pPlayer); + } + break; + + case RPG_WEAPON__STATIC: + if (++(*weaponFrame) == 4) + { + pPlayer->ammo_amount[RPG_WEAPON]--; + lastvisinc = (int32_t) totalclock + 32; + pPlayer->visibility = 0; + flashColor = 255+(95<<8); + A_Shoot(pPlayer->i, RPG); + P_CheckWeapon(pPlayer); + } + else if ((*weaponFrame) == 20) + { + (*weaponFrame) = 0; + } + break; + } + } +#ifdef POLYMER + if (flashColor) + { + spritetype *s = &sprite[pPlayer->i]; + int32_t x = ((sintable[(s->ang + 512) & 2047]) >> 7), y = ((sintable[(s->ang) & 2047]) >> 7); + + s->x += x; + s->y += y; + G_AddGameLight(0, pPlayer->i, PHEIGHT, 8192, flashColor, PR_LIGHT_PRIO_MAX_GAME); + actor[pPlayer->i].lightcount = 2; + s->x -= x; + s->y -= y; + } +#endif // POLYMER + } +} + +void P_EndLevel(void) +{ + for (bssize_t TRAVERSE_CONNECT(playerNum)) + g_player[playerNum].ps->gm = MODE_EOL; + + if (ud.from_bonus) + { + ud.level_number = ud.from_bonus; + m_level_number = ud.level_number; + ud.from_bonus = 0; + } + else + { + ud.level_number = (++ud.level_number < MAXLEVELS) ? ud.level_number : 0; + m_level_number = ud.level_number; + } +} + +static int P_DoFist(DukePlayer_t *pPlayer) +{ + // the fist punching NUKEBUTTON + + if (++(pPlayer->fist_incs) == 28) + { + if (ud.recstat == 1) + G_CloseDemoWrite(); + + S_PlaySound(PIPEBOMB_EXPLODE); + P_PalFrom(pPlayer, 48, 64, 64, 64); + } + + if (pPlayer->fist_incs > 42) + { + if (pPlayer->buttonpalette && ud.from_bonus == 0) + { + for (bssize_t TRAVERSE_CONNECT(playerNum)) + g_player[playerNum].ps->gm = MODE_EOL; + + ud.from_bonus = ud.level_number + 1; + + if ((unsigned)ud.secretlevel <= MAXLEVELS) + ud.level_number = ud.secretlevel - 1; + + m_level_number = ud.level_number; + } + else + P_EndLevel(); + + pPlayer->fist_incs = 0; + + return 1; + } + + return 0; +} + +#ifdef YAX_ENABLE +void getzsofslope_player(int sectNum, int playerX, int playerY, int32_t *pCeilZ, int32_t *pFloorZ) +{ + int didCeiling = 0; + + if ((sector[sectNum].ceilingstat & 512) == 0) + { + int const neighborSect = yax_getneighborsect(playerX, playerY, sectNum, YAX_CEILING); + + if (neighborSect >= 0) + { + *pCeilZ = getceilzofslope(neighborSect, playerX, playerY); + didCeiling = 1; + } + } + + int didFloor = 0; + + if ((sector[sectNum].floorstat & 512) == 0) + { + int const neighborSect = yax_getneighborsect(playerX, playerY, sectNum, YAX_FLOOR); + + if (neighborSect >= 0) + { + *pFloorZ = getflorzofslope(neighborSect, playerX, playerY); + didFloor = 1; + } + } + + if (!didCeiling || !didFloor) + { + int32_t ceilingZ, floorZ; + getzsofslope(sectNum, playerX, playerY, &ceilingZ, &floorZ); + + if (!didCeiling) + *pCeilZ = ceilingZ; + + if (!didFloor) + *pFloorZ = floorZ; + } +} +#endif + +void P_UpdatePosWhenViewingCam(DukePlayer_t *pPlayer) +{ + int const newOwner = pPlayer->newowner; + pPlayer->pos = *(vec3_t *)&sprite[newOwner]; + pPlayer->q16ang = fix16_from_int(SA(newOwner)); + pPlayer->vel.x = 0; + pPlayer->vel.y = 0; + sprite[pPlayer->i].xvel = 0; + pPlayer->q16look_ang = 0; + pPlayer->q16rotscrnang = 0; +} + +static void P_DoWater(int const playerNum, int const playerBits, int const floorZ, int const ceilZ) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + // under water + pPlayer->pycount += 32; + pPlayer->pycount &= 2047; + pPlayer->jumping_counter = 0; + pPlayer->pyoff = sintable[pPlayer->pycount] >> 7; + + if (!A_CheckSoundPlaying(pPlayer->i, DUKE_UNDERWATER)) + A_PlaySound(DUKE_UNDERWATER, pPlayer->i); + + if (TEST_SYNC_KEY(playerBits, SK_JUMP) && (!RRRA || !pPlayer->on_motorcycle)) + { + pPlayer->vel.z = max(min(-348, pPlayer->vel.z - 348), -(256 * 6)); + } + else if ((TEST_SYNC_KEY(playerBits, SK_CROUCH) && (!RRRA || !pPlayer->on_motorcycle)) + || (RRRA && pPlayer->on_motorcycle)) + { + pPlayer->vel.z = min(max(348, pPlayer->vel.z + 348), (256 * 6)); + } + else + { + // normal view + if (pPlayer->vel.z < 0) + pPlayer->vel.z = min(0, pPlayer->vel.z + 256); + + if (pPlayer->vel.z > 0) + pPlayer->vel.z = max(0, pPlayer->vel.z - 256); + } + + if (pPlayer->vel.z > 2048) + pPlayer->vel.z >>= 1; + + pPlayer->pos.z += pPlayer->vel.z; + + if (pPlayer->pos.z > (floorZ-(15<<8))) + pPlayer->pos.z += ((floorZ-(15<<8))-pPlayer->pos.z)>>1; + + if (pPlayer->pos.z < ceilZ+ZOFFSET6) + { + pPlayer->pos.z = ceilZ+ZOFFSET6; + pPlayer->vel.z = 0; + } + + if (pPlayer->scuba_on && (krand2()&255) < 8) + { + int const spriteNum = A_Spawn(pPlayer->i, WATERBUBBLE); + int const q16ang = fix16_to_int(pPlayer->q16ang); + + sprite[spriteNum].x += sintable[(q16ang + 512 + 64 - (g_globalRandom & 128)+(RR ? 128 : 0)) & 2047] >> 6; + sprite[spriteNum].y += sintable[(q16ang + 64 - (g_globalRandom & 128)+(RR ? 128 : 0)) & 2047] >> 6; + sprite[spriteNum].xrepeat = 3; + sprite[spriteNum].yrepeat = 2; + sprite[spriteNum].z = pPlayer->pos.z + ZOFFSET3; + if (RR) + sprite[spriteNum].cstat = 514; + } +} +static void P_DoJetpack(int const playerNum, int const playerBits, int const playerShrunk, int const sectorLotag, int const floorZ) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + pPlayer->on_ground = 0; + pPlayer->jumping_counter = 0; + pPlayer->hard_landing = 0; + pPlayer->falling_counter = 0; + pPlayer->pycount += 32; + pPlayer->pycount &= 2047; + pPlayer->pyoff = sintable[pPlayer->pycount] >> 7; + + g_player[playerNum].horizSkew = 0; + + if (pPlayer->jetpack_on < 11) + { + pPlayer->jetpack_on++; + pPlayer->pos.z -= (pPlayer->jetpack_on<<7); //Goin up + } + else if (pPlayer->jetpack_on == 11 && !A_CheckSoundPlaying(pPlayer->i, DUKE_JETPACK_IDLE)) + A_PlaySound(DUKE_JETPACK_IDLE, pPlayer->i); + + int const zAdjust = playerShrunk ? 512 : 2048; + + if (TEST_SYNC_KEY(playerBits, SK_JUMP)) // jumping, flying up + { + if (VM_OnEvent(EVENT_SOARUP, pPlayer->i, playerNum) == 0) + { + pPlayer->pos.z -= zAdjust; + pPlayer->crack_time = 777; + } + } + + if (TEST_SYNC_KEY(playerBits, SK_CROUCH)) // crouching, flying down + { + if (VM_OnEvent(EVENT_SOARDOWN, pPlayer->i, playerNum) == 0) + { + pPlayer->pos.z += zAdjust; + pPlayer->crack_time = 777; + } + } + + int const Zdiff = (playerShrunk == 0 && (sectorLotag == 0 || sectorLotag == ST_2_UNDERWATER)) ? 32 : 16; + + if (sectorLotag != ST_2_UNDERWATER && pPlayer->scuba_on == 1) + pPlayer->scuba_on = 0; + + if (pPlayer->pos.z > (floorZ - (Zdiff << 8))) + pPlayer->pos.z += ((floorZ - (Zdiff << 8)) - pPlayer->pos.z) >> 1; + + if (pPlayer->pos.z < (actor[pPlayer->i].ceilingz + (18 << 8))) + pPlayer->pos.z = actor[pPlayer->i].ceilingz + (18 << 8); +} + +static void P_Dead(int const playerNum, int const sectorLotag, int const floorZ, int const ceilZ) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + spritetype *const pSprite = &sprite[pPlayer->i]; + + if (ud.recstat == 1 && (!g_netServer && ud.multimode < 2)) + G_CloseDemoWrite(); + + if (/*(numplayers < 2 || g_netServer) && */pPlayer->dead_flag == 0) + P_FragPlayer(playerNum); + + if (sectorLotag == ST_2_UNDERWATER) + { + if (pPlayer->on_warping_sector == 0) + { + if (klabs(pPlayer->pos.z-floorZ) >(PHEIGHT>>1)) + pPlayer->pos.z += 348; + } + else + { + pSprite->z -= 512; + pSprite->zvel = -348; + } + + clipmove((vec3_t *) pPlayer, &pPlayer->cursectnum, + 0, 0, 164, (4L<<8), (4L<<8), CLIPMASK0); + // p->bobcounter += 32; + } + + Bmemcpy(&pPlayer->opos, &pPlayer->pos, sizeof(vec3_t)); + pPlayer->opyoff = pPlayer->pyoff; + + pPlayer->q16horiz = F16(100); + pPlayer->q16horizoff = 0; + + updatesector(pPlayer->pos.x, pPlayer->pos.y, &pPlayer->cursectnum); + + pushmove((vec3_t *) pPlayer, &pPlayer->cursectnum, 128L, (4L<<8), (20L<<8), CLIPMASK0); + + if (floorZ > ceilZ + ZOFFSET2 && pSprite->pal != 1) + pPlayer->q16rotscrnang = fix16_from_int((pPlayer->dead_flag + ((floorZ+pPlayer->pos.z)>>7)))&0x7FFFFFF; + + pPlayer->on_warping_sector = 0; +} + + +static void P_HandlePal(DukePlayer_t *const pPlayer) +{ + pPlayer->pals.f--; +} + +void P_ProcessInput(int playerNum) +{ + auto &thisPlayer = g_player[playerNum]; + + if (DEER) + { + P_DHProcessInput(playerNum); + return; + } + if (thisPlayer.playerquitflag == 0) + return; + + thisPlayer.horizAngleAdjust = 0; + thisPlayer.horizSkew = 0; + + auto const pPlayer = thisPlayer.ps; + auto const pSprite = &sprite[pPlayer->i]; + + ++pPlayer->player_par; + + uint32_t playerBits = thisPlayer.input->bits; + + if (RR) + { + if (RRRA) + g_canSeePlayer = 1; + else + g_canSeePlayer = playerNum; + } + + if (pPlayer->cheat_phase > 0) + playerBits = 0; + + if (RRRA) + { + if (pPlayer->on_motorcycle && pSprite->extra > 0) + { + int var64, var68, var6c, var74, var7c; + int16_t var84; + if (pPlayer->moto_speed < 0) + pPlayer->moto_speed = 0; + if (TEST_SYNC_KEY(playerBits, SK_CROUCH)) + { + var64 = 1; + playerBits &= ~(1<on_ground) + { + if (pPlayer->moto_speed == 0 && var64) + { + if (!A_CheckSoundPlaying(pPlayer->i, 187)) + A_PlaySound(187,pPlayer->i); + } + else if (pPlayer->moto_speed == 0 && !A_CheckSoundPlaying(pPlayer->i, 214)) + { + if (A_CheckSoundPlaying(pPlayer->i, 187)) + S_StopEnvSound(187, pPlayer->i); + A_PlaySound(214,pPlayer->i); + } + else if (pPlayer->moto_speed >= 50 && !A_CheckSoundPlaying(pPlayer->i, 188)) + { + A_PlaySound(188,pPlayer->i); + } + else if (!A_CheckSoundPlaying(pPlayer->i, 188) && !A_CheckSoundPlaying(pPlayer->i, 214)) + { + A_PlaySound(188,pPlayer->i); + } + } + } + else + { + var68 = 0; + if (A_CheckSoundPlaying(pPlayer->i, 214)) + { + S_StopEnvSound(214, pPlayer->i); + if (!A_CheckSoundPlaying(pPlayer->i, 189)) + A_PlaySound(189,pPlayer->i); + } + if (A_CheckSoundPlaying(pPlayer->i, 188)) + { + S_StopEnvSound(188, pPlayer->i); + if (!A_CheckSoundPlaying(pPlayer->i, 189)) + A_PlaySound(189, pPlayer->i); + } + if (!A_CheckSoundPlaying(pPlayer->i, 189) && !A_CheckSoundPlaying(pPlayer->i, 187)) + A_PlaySound(187,pPlayer->i); + } + if (TEST_SYNC_KEY(playerBits, SK_AIM_UP)) + { + var6c = 1; + playerBits &= ~(1<drink_amt > 88 && pPlayer->moto_drink == 0) + { + var84 = krand2() & 63; + if (var84 == 1) + pPlayer->moto_drink = -10; + else if (var84 == 2) + pPlayer->moto_drink = 10; + } + else if (pPlayer->drink_amt > 99 && pPlayer->moto_drink == 0) + { + var84 = krand2() & 31; + if (var84 == 1) + pPlayer->moto_drink = -20; + else if (var84 == 2) + pPlayer->moto_drink = 20; + } + if (pPlayer->on_ground == 1) + { + if (var64 && pPlayer->moto_speed > 0) + { + if (pPlayer->moto_on_oil) + pPlayer->moto_speed -= 2; + else + pPlayer->moto_speed -= 4; + if (pPlayer->moto_speed < 0) + pPlayer->moto_speed = 0; + pPlayer->moto_bump_target = -30; + pPlayer->moto_do_bump = 1; + } + else if (var68 && !var64) + { + if (pPlayer->moto_speed < 40) + { + pPlayer->moto_bump_target = 70; + pPlayer->moto_bump_fast = 1; + } + pPlayer->moto_speed += 2; + if (pPlayer->moto_speed > 120) + pPlayer->moto_speed = 120; + if (!pPlayer->not_on_water) + if (pPlayer->moto_speed > 80) + pPlayer->moto_speed = 80; + } + else if (pPlayer->moto_speed > 0) + pPlayer->moto_speed--; + if (pPlayer->moto_do_bump && (!var64 || pPlayer->moto_speed == 0)) + { + pPlayer->moto_bump_target = 0; + pPlayer->moto_do_bump = 0; + } + if (var6c && pPlayer->moto_speed <= 0 && !var64) + { + int var88; + pPlayer->moto_speed = -15; + var88 = var7c; + var7c = var74; + var74 = var88; + } + } + if (pPlayer->moto_speed != 0 && pPlayer->on_ground == 1) + { + if (!pPlayer->moto_bump) + if ((krand2() & 3) == 2) + pPlayer->moto_bump_target = (pPlayer->moto_speed>>4)*((krand2()&7)-4); + if (var74 || pPlayer->moto_drink < 0) + { + if (pPlayer->moto_drink < 0) + pPlayer->moto_drink++; + } + else if (var7c || pPlayer->moto_drink > 0) + { + if (pPlayer->moto_drink > 0) + pPlayer->moto_drink--; + } + } + if (pPlayer->moto_turb) + { + if (pPlayer->moto_turb <= 1) + { + pPlayer->q16horiz = F16(100); + pPlayer->moto_turb = 0; + pPlayer->moto_bump_target = 0; + pPlayer->moto_bump = 0; + } + else + { + pPlayer->q16horiz = F16(100+((krand2()&15)-7)); + pPlayer->moto_turb--; + pPlayer->moto_drink = (krand2()&3)-2; + } + } + else if (pPlayer->moto_bump_target > pPlayer->moto_bump) + { + if (pPlayer->moto_bump_fast) + pPlayer->moto_bump += 6; + else + pPlayer->moto_bump++; + if (pPlayer->moto_bump_target < pPlayer->moto_bump) + pPlayer->moto_bump = pPlayer->moto_bump_target; + pPlayer->q16horiz = F16(100+pPlayer->moto_bump/3); + } + else if (pPlayer->moto_bump_target < pPlayer->moto_bump) + { + if (pPlayer->moto_bump_fast) + pPlayer->moto_bump -= 6; + else + pPlayer->moto_bump--; + if (pPlayer->moto_bump_target > pPlayer->moto_bump) + pPlayer->moto_bump = pPlayer->moto_bump_target; + pPlayer->q16horiz = F16(100+pPlayer->moto_bump/3); + } + else + { + pPlayer->moto_bump_target = 0; + pPlayer->moto_bump_fast = 0; + } + if (pPlayer->moto_speed >= 20 && pPlayer->on_ground == 1 && (var74 || var7c)) + { + short var8c, var90, var94, var98; + var8c = pPlayer->moto_speed; + var90 = fix16_to_int(pPlayer->q16ang); + if (var74) + var94 = -10; + else + var94 = 10; + if (var94 < 0) + var98 = 350; + else + var98 = -350; + if (pPlayer->moto_on_mud || pPlayer->moto_on_oil || !pPlayer->not_on_water) + { + if (pPlayer->moto_on_oil) + var8c <<= 3; + else + var8c <<= 2; + if (pPlayer->moto_do_bump) + { + pPlayer->vel.x += (var8c>>5)*(sintable[(var94*-51+var90+512)&2047]<<4); + pPlayer->vel.y += (var8c>>5)*(sintable[(var94*-51+var90)&2047]<<4); + pPlayer->q16ang = F16((var90-(var98>>2))&2047); + } + else + { + pPlayer->vel.x += (var8c>>7)*(sintable[(var94*-51+var90+512)&2047]<<4); + pPlayer->vel.y += (var8c>>7)*(sintable[(var94*-51+var90)&2047]<<4); + pPlayer->q16ang = F16((var90-(var98>>6))&2047); + } + pPlayer->moto_on_mud = 0; + pPlayer->moto_on_oil = 0; + } + else + { + if (pPlayer->moto_do_bump) + { + pPlayer->vel.x += (var8c >> 5)*(sintable[(var94*-51 + var90 + 512) & 2047] << 4); + pPlayer->vel.y += (var8c>>5)*(sintable[(var94*-51+var90)&2047]<<4); + pPlayer->q16ang = F16((var90-(var98>>4))&2047); + if (!A_CheckSoundPlaying(pPlayer->i, 220)) + A_PlaySound(220,pPlayer->i); + } + else + { + pPlayer->vel.x += (var8c >> 7)*(sintable[(var94*-51 + var90 + 512) & 2047] << 4); + pPlayer->vel.y += (var8c>>7)*(sintable[(var94*-51+var90)&2047]<<4); + pPlayer->q16ang = F16((var90-(var98>>7))&2047); + } + } + } + else if (pPlayer->moto_speed >= 20 && pPlayer->on_ground == 1 && (pPlayer->moto_on_mud || pPlayer->moto_on_oil)) + { + short var9c, vara0, vara4 = 0; + var9c = pPlayer->moto_speed; + vara0 = fix16_to_int(pPlayer->q16ang); + var84 = krand2()&1; + if (var84 == 0) + vara4 = -10; + else if (var84 == 1) + vara4 = 10; + if (pPlayer->moto_on_oil) + var9c *= 10; + else + var9c *= 5; + pPlayer->vel.x += (var9c>>7)*(sintable[(vara4*-51+vara0+512)&2047]<<4); + pPlayer->vel.y += (var9c>>7)*(sintable[(vara4*-51+vara0)&2047]<<4); + } + pPlayer->moto_on_mud = 0; + pPlayer->moto_on_oil = 0; + } + else if (pPlayer->on_boat && pSprite->extra > 0) + { + int vara8, varac, varb0, varb4, varbc, varc4; + int16_t varcc; + if (pPlayer->not_on_water) + { + if (pPlayer->moto_speed > 0) + { + if (!A_CheckSoundPlaying(pPlayer->i, 88)) + A_PlaySound(88,pPlayer->i); + } + else + { + if (!A_CheckSoundPlaying(pPlayer->i, 87)) + A_PlaySound(87,pPlayer->i); + } + } + if (pPlayer->moto_speed < 0) + pPlayer->moto_speed = 0; + if (TEST_SYNC_KEY(playerBits, SK_CROUCH) && TEST_SYNC_KEY(playerBits, SK_JUMP)) + { + vara8 = 1; + varac = 0; + playerBits &= ~(1<moto_speed == 0 && !A_CheckSoundPlaying(pPlayer->i, 89)) + { + if (A_CheckSoundPlaying(pPlayer->i, 87)) + S_StopEnvSound(pPlayer->i, 87); + A_PlaySound(89,pPlayer->i); + } + else if (pPlayer->moto_speed >= 50 && !A_CheckSoundPlaying(pPlayer->i, 88)) + A_PlaySound(88,pPlayer->i); + else if (!A_CheckSoundPlaying(pPlayer->i, 88) && !A_CheckSoundPlaying(pPlayer->i, 89)) + A_PlaySound(88,pPlayer->i); + } + else + { + varac = 0; + if (A_CheckSoundPlaying(pPlayer->i, 89)) + { + S_StopEnvSound(pPlayer->i, 89); + if (!A_CheckSoundPlaying(pPlayer->i, 90)) + A_PlaySound(90,pPlayer->i); + } + if (A_CheckSoundPlaying(pPlayer->i, 88)) + { + S_StopEnvSound(pPlayer->i, 88); + if (!A_CheckSoundPlaying(pPlayer->i, 90)) + A_PlaySound(90,pPlayer->i); + } + if (!A_CheckSoundPlaying(pPlayer->i, 90) && !A_CheckSoundPlaying(pPlayer->i, 87)) + A_PlaySound(87,pPlayer->i); + } + if (TEST_SYNC_KEY(playerBits, SK_CROUCH)) + { + varb0 = 1; + playerBits &= ~(1<i, 91) && pPlayer->moto_speed > 30 && !pPlayer->not_on_water) + A_PlaySound(91,pPlayer->i); + } + else + { + varbc = 0; + } + if (TEST_SYNC_KEY(playerBits, SK_LOOK_LEFT)) + { + varc4 = 1; + playerBits &= ~(1<< SK_LOOK_LEFT); + if (!A_CheckSoundPlaying(pPlayer->i, 91) && pPlayer->moto_speed > 30 && !pPlayer->not_on_water) + A_PlaySound(91,pPlayer->i); + } + else + { + varc4 = 0; + } + if (!pPlayer->not_on_water) + { + if (pPlayer->drink_amt > 88 && pPlayer->moto_drink == 0) + { + varcc = krand2() & 63; + if (varcc == 1) + pPlayer->moto_drink = -10; + else if (varcc == 2) + pPlayer->moto_drink = 10; + } + else if (pPlayer->drink_amt > 99 && pPlayer->moto_drink == 0) + { + varcc = krand2() & 31; + if (varcc == 1) + pPlayer->moto_drink = -20; + else if (varcc == 2) + pPlayer->moto_drink = 20; + } + } + if (pPlayer->on_ground == 1) + { + if (vara8) + { + if (pPlayer->moto_speed <= 25) + { + pPlayer->moto_speed++; + if (!A_CheckSoundPlaying(pPlayer->i, 182)) + A_PlaySound(182, pPlayer->i); + } + else + { + pPlayer->moto_speed -= 2; + if (pPlayer->moto_speed < 0) + pPlayer->moto_speed = 0; + pPlayer->moto_bump_target = 30; + pPlayer->moto_do_bump = 1; + } + } + else if (varb0 && pPlayer->moto_speed > 0) + { + pPlayer->moto_speed -= 2; + if (pPlayer->moto_speed < 0) + pPlayer->moto_speed = 0; + pPlayer->moto_bump_target = 30; + pPlayer->moto_do_bump = 1; + } + else if (varac) + { + if (pPlayer->moto_speed < 40) + if (!pPlayer->not_on_water) + { + pPlayer->moto_bump_target = -30; + pPlayer->moto_bump_fast = 1; + } + pPlayer->moto_speed++; + if (pPlayer->moto_speed > 120) + pPlayer->moto_speed = 120; + } + else if (pPlayer->moto_speed > 0) + pPlayer->moto_speed--; + if (pPlayer->moto_do_bump && (!varb0 || pPlayer->moto_speed == 0)) + { + pPlayer->moto_bump_target = 0; + pPlayer->moto_do_bump = 0; + } + if (varb4 && pPlayer->moto_speed == 0 && !varb0) + { + int vard0; + if (!pPlayer->not_on_water) + pPlayer->moto_speed = -25; + else + pPlayer->moto_speed = -20; + vard0 = varc4; + varc4 = varbc; + varbc = vard0; + } + } + if (pPlayer->moto_speed != 0 && pPlayer->on_ground == 1) + { + if (!pPlayer->moto_bump) + if ((krand2() & 15) == 14) + pPlayer->moto_bump_target = (pPlayer->moto_speed>>4)*((krand2()&3)-2); + if (varbc || pPlayer->moto_drink < 0) + { + if (pPlayer->moto_drink < 0) + pPlayer->moto_drink++; + } + else if (varc4 || pPlayer->moto_drink > 0) + { + if (pPlayer->moto_drink > 0) + pPlayer->moto_drink--; + } + } + if (pPlayer->moto_turb) + { + if (pPlayer->moto_turb <= 1) + { + pPlayer->q16horiz = F16(100); + pPlayer->moto_turb = 0; + pPlayer->moto_bump_target = 0; + pPlayer->moto_bump = 0; + } + else + { + pPlayer->q16horiz = F16(100+((krand2()&15)-7)); + pPlayer->moto_turb--; + pPlayer->moto_drink = (krand2()&3)-2; + } + } + else if (pPlayer->moto_bump_target > pPlayer->moto_bump) + { + if (pPlayer->moto_bump_fast) + pPlayer->moto_bump += 6; + else + pPlayer->moto_bump++; + if (pPlayer->moto_bump_target < pPlayer->moto_bump) + pPlayer->moto_bump = pPlayer->moto_bump_target; + pPlayer->q16horiz = F16(100+pPlayer->moto_bump/3); + } + else if (pPlayer->moto_bump_target < pPlayer->moto_bump) + { + if (pPlayer->moto_bump_fast) + pPlayer->moto_bump -= 6; + else + pPlayer->moto_bump--; + if (pPlayer->moto_bump_target > pPlayer->moto_bump) + pPlayer->moto_bump = pPlayer->moto_bump_target; + pPlayer->q16horiz = F16(100+pPlayer->moto_bump/3); + } + else + { + pPlayer->moto_bump_target = 0; + pPlayer->moto_bump_fast = 0; + } + if (pPlayer->moto_speed > 0 && pPlayer->on_ground == 1 && (varbc || varc4)) + { + short vard4, vard8, vardc, vare0; + vard4 = pPlayer->moto_speed; + vard8 = fix16_to_int(pPlayer->q16ang); + if (varbc) + vardc = -10; + else + vardc = 10; + if (vardc < 0) + vare0 = 350; + else + vare0 = -350; + vard4 <<= 2; + if (pPlayer->moto_do_bump) + { + pPlayer->vel.x += (vard4>>6)*(sintable[(vardc*-51+vard8+512)&2047]<<4); + pPlayer->vel.y += (vard4>>6)*(sintable[(vardc*-51+vard8)&2047]<<4); + pPlayer->q16ang = F16((vard8-(vare0>>5))&2047); + } + else + { + pPlayer->vel.x += (vard4>>7)*(sintable[(vardc*-51+vard8+512)&2047]<<4); + pPlayer->vel.y += (vard4>>7)*(sintable[(vardc*-51+vard8)&2047]<<4); + pPlayer->q16ang = F16((vard8-(vare0>>6))&2047); + } + } + if (pPlayer->not_on_water) + if (pPlayer->moto_speed > 50) + pPlayer->moto_speed -= (pPlayer->moto_speed>>1); + } + } + + if (pPlayer->cursectnum == -1) + { + if (pSprite->extra > 0 && ud.noclip == 0) + { + P_QuickKill(pPlayer); + A_PlaySound(SQUISHED, pPlayer->i); + } + + pPlayer->cursectnum = 0; + } + + int sectorLotag = sector[pPlayer->cursectnum].lotag; + + if (RR) + { + if (sectorLotag == 867) + { + int spriteNum = headspritesect[pPlayer->cursectnum]; + while (spriteNum >= 0) + { + int const nextSprite = nextspritesect[spriteNum]; + if (sprite[spriteNum].picnum == RRTILE380) + if (sprite[spriteNum].z - ZOFFSET3 < pPlayer->pos.z) + sectorLotag = 2; + spriteNum = nextSprite; + } + } + else if (sectorLotag == 7777) + if (ud.volume_number == 1 && ud.level_number == 6) + g_lastLevel = 1; + + if (sectorLotag == 848 && sector[pPlayer->cursectnum].floorpicnum == WATERTILE2) + sectorLotag = 1; + + if (sectorLotag == 857) + pSprite->clipdist = 1; + else + pSprite->clipdist = 64; + } + + pPlayer->spritebridge = 0; + //pPlayer->sbs = 0; + + int32_t floorZ, ceilZ, highZhit, lowZhit; + if (!RR || pSprite->clipdist == 64) + getzrange((vec3_t *)pPlayer, pPlayer->cursectnum, &ceilZ, &highZhit, &floorZ, &lowZhit, 163, CLIPMASK0); + else + getzrange((vec3_t *)pPlayer, pPlayer->cursectnum, &ceilZ, &highZhit, &floorZ, &lowZhit, 4, CLIPMASK0); + +#ifdef YAX_ENABLE + getzsofslope_player(pPlayer->cursectnum, pPlayer->pos.x, pPlayer->pos.y, &pPlayer->truecz, &pPlayer->truefz); +#else + getzsofslope(pPlayer->cursectnum, pPlayer->pos.x, pPlayer->pos.y, &pPlayer->truecz, &pPlayer->truefz); +#endif + int const trueFloorZ = pPlayer->truefz; + int const trueFloorDist = klabs(pPlayer->pos.z - trueFloorZ); + + if ((lowZhit & 49152) == 16384 && sectorLotag == 1 && trueFloorDist > PHEIGHT + ZOFFSET2) + sectorLotag = 0; + + actor[pPlayer->i].floorz = floorZ; + actor[pPlayer->i].ceilingz = ceilZ; + + if (highZhit >= 0 && (highZhit&49152) == 49152) + { + highZhit &= (MAXSPRITES-1); + + if (sprite[highZhit].statnum == STAT_ACTOR && sprite[highZhit].extra >= 0) + { + highZhit = 0; + ceilZ = pPlayer->truecz; + } + if (RR) + { + if (sprite[highZhit].picnum == RRTILE3587) + { + if (!pPlayer->stairs) + { + pPlayer->stairs = 10; + if (TEST_SYNC_KEY(playerBits, SK_JUMP) && (!RRRA || !pPlayer->on_motorcycle)) + { + highZhit = 0; + ceilZ = pPlayer->truecz; + } + } + else + pPlayer->stairs--; + } + } + } + + if (lowZhit >= 0 && (lowZhit&49152) == 49152) + { + int spriteNum = lowZhit&(MAXSPRITES-1); + + if ((sprite[spriteNum].cstat&33) == 33) + { + sectorLotag = 0; + pPlayer->footprintcount = 0; + pPlayer->spritebridge = 1; + //pPlayer->sbs = spriteNum; + } + else if (!RRRA) + goto check_enemy_sprite; + + if (RRRA) + { + if (pPlayer->on_motorcycle) + { + if (A_CheckEnemySprite(&sprite[spriteNum])) + { + actor[spriteNum].picnum = MOTOHIT; + actor[spriteNum].extra = 2+(pPlayer->moto_speed>>1); + pPlayer->moto_speed -= pPlayer->moto_speed >> 4; + } + } + if (pPlayer->on_boat) + { + if (A_CheckEnemySprite(&sprite[spriteNum])) + { + actor[spriteNum].picnum = MOTOHIT; + actor[spriteNum].extra = 2+(pPlayer->moto_speed>>1); + pPlayer->moto_speed -= pPlayer->moto_speed >> 4; + } + } + else + { +check_enemy_sprite: + if (A_CheckEnemySprite(&sprite[spriteNum]) && sprite[spriteNum].xrepeat > 24 + && klabs(pSprite->z - sprite[spriteNum].z) < (84 << 8)) + { + // TX: I think this is what makes the player slide off enemies... might + // be a good sprite flag to add later. + // Helix: there's also SLIDE_ABOVE_ENEMY. + int spriteAng = getangle(sprite[spriteNum].x - pPlayer->pos.x, + sprite[spriteNum].y - pPlayer->pos.y); + pPlayer->vel.x -= sintable[(spriteAng + 512) & 2047] << 4; + pPlayer->vel.y -= sintable[spriteAng & 2047] << 4; + } + } + } + if (RR) + { + if (sprite[spriteNum].picnum == RRTILE3587) + { + if (!pPlayer->stairs) + { + pPlayer->stairs = 10; + if (TEST_SYNC_KEY(playerBits, SK_CROUCH) && (!RRRA || !pPlayer->on_motorcycle)) + { + ceilZ = sprite[spriteNum].z; + highZhit = 0; + floorZ = sprite[spriteNum].z + ZOFFSET6; + } + } + else + pPlayer->stairs--; + } + else if (sprite[spriteNum].picnum == TOILET || sprite[spriteNum].picnum == RRTILE2121) + { + if (TEST_SYNC_KEY(playerBits, SK_CROUCH) && (!RRRA || !pPlayer->on_motorcycle)) + { + A_PlaySound(436, pPlayer->i); + pPlayer->last_pissed_time = 4000; + pPlayer->eat_amt = 0; + } + } + } + } + + if (pSprite->extra > 0) + P_IncurDamage(pPlayer); + else + { + pSprite->extra = 0; + pPlayer->inv_amount[GET_SHIELD] = 0; + } + + pPlayer->last_extra = pSprite->extra; + pPlayer->loogcnt = (pPlayer->loogcnt > 0) ? pPlayer->loogcnt - 1 : 0; + + if (pPlayer->fist_incs && P_DoFist(pPlayer) && !RR) return; + + if (pPlayer->timebeforeexit > 1 && pPlayer->last_extra > 0) + { + if (--pPlayer->timebeforeexit == GAMETICSPERSEC*5) + { + FX_StopAllSounds(); + S_ClearSoundLocks(); + + if (pPlayer->customexitsound >= 0) + { + S_PlaySound(pPlayer->customexitsound); + P_DoQuote(QUOTE_WEREGONNAFRYYOURASS,pPlayer); + } + } + else if (pPlayer->timebeforeexit == 1) + { + for (bssize_t TRAVERSE_CONNECT(playerNum)) + g_player[playerNum].ps->gm = MODE_EOL; + + if (RR && ud.level_number == 6 && ud.volume_number == 0) + g_turdLevel = 1; + if (!RR && ud.from_bonus) + { + ud.level_number = ud.from_bonus; + m_level_number = ud.level_number; + ud.from_bonus = 0; + } + else + { + ud.level_number = (++ud.level_number < MAXLEVELS) ? ud.level_number : 0; + m_level_number = ud.level_number; + } + return; + } + } + + if (pPlayer->pals.f > 0) + P_HandlePal(pPlayer); + + if (pPlayer->fta > 0 && --pPlayer->fta == 0) + { + pub = pus = NUMPAGES; + pPlayer->ftq = 0; + } + + if (g_levelTextTime > 0) + g_levelTextTime--; + + if (pSprite->extra <= 0) + { + P_Dead(playerNum, sectorLotag, floorZ, ceilZ); + return; + } + + if (pPlayer->transporter_hold > 0) + { + pPlayer->transporter_hold--; + if (pPlayer->transporter_hold == 0 && pPlayer->on_warping_sector) + pPlayer->transporter_hold = 2; + } + else if (pPlayer->transporter_hold < 0) + pPlayer->transporter_hold++; + + if (pPlayer->newowner >= 0) + { + P_UpdatePosWhenViewingCam(pPlayer); + P_DoCounters(playerNum); + + if ((WW2GI ? PWEAPON(playerNum, pPlayer->curr_weapon, WorksLike) : pPlayer->curr_weapon) == HANDREMOTE_WEAPON) + P_ProcessWeapon(playerNum); + + return; + } + + if (TEST_SYNC_KEY(playerBits, SK_LOOK_LEFT) && (!RRRA || !pPlayer->on_motorcycle)) + { + // look_left + if (VM_OnEvent(EVENT_LOOKLEFT,pPlayer->i,playerNum) == 0) + { + thisPlayer.lookLeft = true; + } + else + { + thisPlayer.lookLeft = false; + } + } + else + { + thisPlayer.lookLeft = false; + } + + if (TEST_SYNC_KEY(playerBits, SK_LOOK_RIGHT) && (!RRRA || !pPlayer->on_motorcycle)) + { + // look_right + if (VM_OnEvent(EVENT_LOOKRIGHT,pPlayer->i,playerNum) == 0) + { + thisPlayer.lookRight = true; + } + else + { + thisPlayer.lookRight = false; + } + } + else + { + thisPlayer.lookRight = false; + } + + int velocityModifier = TICSPERFRAME; + const uint8_t *const weaponFrame = &pPlayer->kickback_pic; + int floorZOffset = 40; + int const playerShrunk = (pSprite->yrepeat < (RR ? 8 : 32)); + + if (pPlayer->on_crane >= 0) + goto HORIZONLY; + + pPlayer->weapon_sway = (pSprite->xvel < 32 || pPlayer->on_ground == 0 || pPlayer->bobcounter == 1024) + ? (((pPlayer->weapon_sway & 2047) > (1024 + 96)) + ? (pPlayer->weapon_sway - 96) + : (((pPlayer->weapon_sway & 2047) < (1024 - 96))) + ? (pPlayer->weapon_sway + 96) + : 1024) + : pPlayer->bobcounter; + + // NOTE: This silently wraps if the difference is too great, e.g. used to do + // that when teleported by silent SE7s. + pSprite->xvel = ksqrt(uhypsq(pPlayer->pos.x - pPlayer->bobpos.x, pPlayer->pos.y - pPlayer->bobpos.y)); + + if (pPlayer->on_ground) + pPlayer->bobcounter += sprite[pPlayer->i].xvel>>1; + + if (ud.noclip == 0 && ((uint16_t)pPlayer->cursectnum >= MAXSECTORS || sector[pPlayer->cursectnum].floorpicnum == MIRROR)) + { + pPlayer->pos.x = pPlayer->opos.x; + pPlayer->pos.y = pPlayer->opos.y; + } + else + { + pPlayer->opos.x = pPlayer->pos.x; + pPlayer->opos.y = pPlayer->pos.y; + } + + pPlayer->bobpos.x = pPlayer->pos.x; + pPlayer->bobpos.y = pPlayer->pos.y; + pPlayer->opos.z = pPlayer->pos.z; + pPlayer->opyoff = pPlayer->pyoff; + + // Shrinking code + + if (RR) + { + if (sectorLotag == 17 || (RRRA && sectorLotag == 18)) + { + if (GetAnimationGoal(§or[pPlayer->cursectnum].floorz) >= 0) + { + if (!S_CheckSoundPlaying(pPlayer->i, 432)) + A_PlaySound(432, pPlayer->i); + } + else + S_StopSound(432); + } + if (pPlayer->sea_sick_stat) + { + pPlayer->pycount += 32; + pPlayer->pycount &= 2047; + if (pPlayer->sea_sick) + pPlayer->pyoff = sintable[pPlayer->pycount]>>2; + else + pPlayer->pyoff = sintable[pPlayer->pycount]>>7; + } + } + + if (sectorLotag == ST_2_UNDERWATER) + P_DoWater(playerNum, playerBits, floorZ, ceilZ); + else if (!RR && pPlayer->jetpack_on) + P_DoJetpack(playerNum, playerBits, playerShrunk, sectorLotag, floorZ); + else + { + pPlayer->airleft = 15 * GAMETICSPERSEC; // 13 seconds + pPlayer->scuba_on = 0; + + if (sectorLotag == ST_1_ABOVE_WATER && pPlayer->spritebridge == 0) + { + floorZOffset = 12; + + if (playerShrunk == 0) + { + floorZOffset = 34; + pPlayer->pycount += 32; + pPlayer->pycount &= 2047; + pPlayer->pyoff = sintable[pPlayer->pycount] >> 6; + } + + if (playerShrunk == 0 && trueFloorDist <= PHEIGHT) + { + if (pPlayer->on_ground == 1) + { + if (pPlayer->dummyplayersprite < 0) + pPlayer->dummyplayersprite = A_Spawn(pPlayer->i,PLAYERONWATER); + + pPlayer->footprintcount = 6; + //sprite[pPlayer->dummyplayersprite].cstat |= 32768; + //sprite[pPlayer->dummyplayersprite].pal = sprite[pPlayer->i].pal; + pPlayer->footprintpal = 0; + pPlayer->footprintshade = 0; + if (sector[pPlayer->cursectnum].floorpicnum == FLOORSLIME) + { + pPlayer->footprintpal = 8; + pPlayer->footprintshade = 0; + } + else if (RRRA && (sector[pPlayer->cursectnum].floorpicnum == RRTILE7756 || sector[pPlayer->cursectnum].floorpicnum == RRTILE7888)) + { + pPlayer->footprintpal = 0; + pPlayer->footprintshade = 40; + } + } + } + } + else if ((!RRRA || pPlayer->on_motorcycle) && pPlayer->footprintcount > 0 && pPlayer->on_ground) + { + if (pPlayer->cursectnum >= 0 && (sector[pPlayer->cursectnum].floorstat & 2) != 2) + { + int spriteNum = -1; + + for (spriteNum = headspritesect[pPlayer->cursectnum]; spriteNum >= 0; spriteNum = nextspritesect[spriteNum]) + { + if (sprite[spriteNum].picnum == FOOTPRINTS || sprite[spriteNum].picnum == FOOTPRINTS2 || + sprite[spriteNum].picnum == FOOTPRINTS3 || sprite[spriteNum].picnum == FOOTPRINTS4) + { + if (klabs(sprite[spriteNum].x - pPlayer->pos.x) < 384 && + klabs(sprite[spriteNum].y - pPlayer->pos.y) < 384) + break; + } + } + + if (spriteNum < 0) + { + pPlayer->footprintcount--; + if (pPlayer->cursectnum >= 0 && sector[pPlayer->cursectnum].lotag == 0 && + sector[pPlayer->cursectnum].hitag == 0) +#ifdef YAX_ENABLE + if (yax_getbunch(pPlayer->cursectnum, YAX_FLOOR) < 0 || (sector[pPlayer->cursectnum].floorstat & 512)) +#endif + { + switch (krand2() & 3) + { + case 0: spriteNum = A_Spawn(pPlayer->i, FOOTPRINTS); break; + case 1: spriteNum = A_Spawn(pPlayer->i, FOOTPRINTS2); break; + case 2: spriteNum = A_Spawn(pPlayer->i, FOOTPRINTS3); break; + default: spriteNum = A_Spawn(pPlayer->i, FOOTPRINTS4); break; + } + sprite[spriteNum].pal = pPlayer->footprintpal; + sprite[spriteNum].shade = pPlayer->footprintshade; + } + } + } + } + + if (pPlayer->pos.z < (floorZ-(floorZOffset<<8))) //falling + { + // not jumping or crouching + + if ((!TEST_SYNC_KEY(playerBits, SK_JUMP) && !TEST_SYNC_KEY(playerBits, SK_CROUCH)) && pPlayer->on_ground && + (sector[pPlayer->cursectnum].floorstat & 2) && pPlayer->pos.z >= (floorZ - (floorZOffset << 8) - ZOFFSET2)) + pPlayer->pos.z = floorZ - (floorZOffset << 8); + else + { + if (RRRA && (pPlayer->on_motorcycle || pPlayer->on_boat) && floorZ - (floorZOffset << 9) > pPlayer->pos.z) + { + if (pPlayer->moto_on_ground) + { + pPlayer->moto_bump_target = 80; + pPlayer->moto_bump_fast = 1; + pPlayer->vel.z -= g_spriteGravity*(pPlayer->moto_speed>>4); + pPlayer->moto_on_ground = 0; + if (A_CheckSoundPlaying(pPlayer->i, 188)) + S_StopEnvSound(188, pPlayer->i); + A_PlaySound(189, pPlayer->i); + } + else + { + pPlayer->vel.z += g_spriteGravity-80+(120-pPlayer->moto_speed); + if (!A_CheckSoundPlaying(pPlayer->i, 189) && !A_CheckSoundPlaying(pPlayer->i, 190)) + A_PlaySound(190, pPlayer->i); + } + } + else + pPlayer->vel.z += (g_spriteGravity + 80); // (TICSPERFRAME<<6); + + if (pPlayer->vel.z >= (4096 + 2048)) + pPlayer->vel.z = (4096 + 2048); + + if (pPlayer->vel.z > 2400 && pPlayer->falling_counter < 255) + { + pPlayer->falling_counter++; + if (pPlayer->falling_counter >= 38 && !A_CheckSoundPlaying(pPlayer->i, -1, CHAN_VOICE)) + { + A_PlaySound(DUKE_SCREAM, pPlayer->i, CHAN_VOICE); + } + } + + if ((pPlayer->pos.z + pPlayer->vel.z) >= (floorZ - (floorZOffset << 8)) && pPlayer->cursectnum >= 0) // hit the ground + { + if (sector[pPlayer->cursectnum].lotag != ST_1_ABOVE_WATER) + { + if (RRRA) + pPlayer->moto_on_ground = 1; + if (pPlayer->falling_counter > 62 || (RRRA && pPlayer->falling_counter > 2 && sector[pPlayer->cursectnum].lotag == 802)) + P_QuickKill(pPlayer); + else if (pPlayer->falling_counter > 9) + { + // Falling damage. + pSprite->extra -= pPlayer->falling_counter - (krand2() & 3); + + if (pSprite->extra <= 0) + A_PlaySound(SQUISHED, pPlayer->i); + else + { + A_PlaySound(DUKE_LAND, pPlayer->i); + A_PlaySound(DUKE_LAND_HURT, pPlayer->i); + } + + P_PalFrom(pPlayer, 32, 16, 0, 0); + } + else if (pPlayer->vel.z > 2048) + { + if (RRRA && pPlayer->on_motorcycle) + { + if (A_CheckSoundPlaying(pPlayer->i, 190)) + S_StopEnvSound(pPlayer->i, 190); + A_PlaySound(191, pPlayer->i); + pPlayer->moto_turb = 12; + } + else + A_PlaySound(DUKE_LAND, pPlayer->i); + } + else if (RRRA && pPlayer->vel.z > 1024 && pPlayer->on_motorcycle) + { + A_PlaySound(DUKE_LAND, pPlayer->i); + pPlayer->moto_turb = 12; + } + } + } + else + pPlayer->on_ground = 0; + } + } + else + { + pPlayer->falling_counter = 0; + + S_StopEnvSound(-1, pPlayer->i, CHAN_VOICE); + + if ((sectorLotag != ST_1_ABOVE_WATER && sectorLotag != ST_2_UNDERWATER) && + (pPlayer->on_ground == 0 && pPlayer->vel.z > (6144 >> 1))) + pPlayer->hard_landing = pPlayer->vel.z>>10; + + pPlayer->on_ground = 1; + + if (floorZOffset==40) + { + //Smooth on the ground + int Zdiff = ((floorZ - (floorZOffset << 8)) - pPlayer->pos.z) >> 1; + + if (klabs(Zdiff) < 256) + Zdiff = 0; + + pPlayer->pos.z += ((klabs(Zdiff) >= 256) ? (((floorZ - (floorZOffset << 8)) - pPlayer->pos.z) >> 1) : 0); + pPlayer->vel.z -= 768; + + if (pPlayer->vel.z < 0) + pPlayer->vel.z = 0; + } + else if (pPlayer->jumping_counter == 0) + { + pPlayer->pos.z += ((floorZ - (floorZOffset << 7)) - pPlayer->pos.z) >> 1; // Smooth on the water + + if (pPlayer->on_warping_sector == 0 && pPlayer->pos.z > floorZ - ZOFFSET2) + { + pPlayer->pos.z = floorZ - ZOFFSET2; + pPlayer->vel.z >>= 1; + } + } + + pPlayer->on_warping_sector = 0; + + if (TEST_SYNC_KEY(playerBits, SK_CROUCH) && (!RRRA || !pPlayer->on_motorcycle)) + { + // crouching + if (VM_OnEvent(EVENT_CROUCH,pPlayer->i,playerNum) == 0) + { + pPlayer->pos.z += (2048+768); + pPlayer->crack_time = 777; + } + } + + // jumping + if (!TEST_SYNC_KEY(playerBits, SK_JUMP) && (!RRRA || !pPlayer->on_motorcycle) && pPlayer->jumping_toggle == 1) + pPlayer->jumping_toggle = 0; + else if (TEST_SYNC_KEY(playerBits, SK_JUMP) && (!RRRA || !pPlayer->on_motorcycle) && pPlayer->jumping_toggle == 0) + { + if (pPlayer->jumping_counter == 0) + if ((floorZ-ceilZ) > (56<<8)) + { + if (VM_OnEvent(EVENT_JUMP,pPlayer->i,playerNum) == 0) + { + pPlayer->jumping_counter = 1; + pPlayer->jumping_toggle = 1; + } + } + } + + if (!RR && pPlayer->jumping_counter && !TEST_SYNC_KEY(playerBits, SK_JUMP)) + pPlayer->jumping_toggle = 0; + } + + if (pPlayer->jumping_counter) + { + if (!TEST_SYNC_KEY(playerBits, SK_JUMP) && (!RRRA || !pPlayer->on_motorcycle) && pPlayer->jumping_toggle == 1) + pPlayer->jumping_toggle = 0; + + if (pPlayer->jumping_counter < (RR ? 768 : (1024+256))) + { + if (sectorLotag == ST_1_ABOVE_WATER && pPlayer->jumping_counter > 768) + { + pPlayer->jumping_counter = 0; + pPlayer->vel.z = -512; + } + else + { + pPlayer->vel.z -= (sintable[(2048-128+pPlayer->jumping_counter)&2047])/12; + pPlayer->jumping_counter += 180; + pPlayer->on_ground = 0; + } + } + else + { + pPlayer->jumping_counter = 0; + pPlayer->vel.z = 0; + } + } + + pPlayer->pos.z += pPlayer->vel.z; + + if (pPlayer->pos.z < (ceilZ+ZOFFSET6)) + { + pPlayer->jumping_counter = 0; + if (pPlayer->vel.z < 0) + pPlayer->vel.x = pPlayer->vel.y = 0; + pPlayer->vel.z = 128; + pPlayer->pos.z = ceilZ+ZOFFSET6; + } + } + + if (P_CheckLockedMovement(playerNum) & IL_NOMOVE) + { + velocityModifier = 0; + pPlayer->vel.x = 0; + pPlayer->vel.y = 0; + } + else if (thisPlayer.input->q16avel) + pPlayer->crack_time = 777; + + if (pPlayer->spritebridge == 0) + { + int const floorPicnum = sector[pSprite->sectnum].floorpicnum; + + if (!RR && (floorPicnum == PURPLELAVA || sector[pSprite->sectnum].ceilingpicnum == PURPLELAVA)) + { + if (pPlayer->inv_amount[GET_BOOTS] > 0) + { + pPlayer->inv_amount[GET_BOOTS]--; + pPlayer->inven_icon = ICON_BOOTS; + if (pPlayer->inv_amount[GET_BOOTS] <= 0) + P_SelectNextInvItem(pPlayer); + } + else + { + if (!A_CheckSoundPlaying(pPlayer->i,DUKE_LONGTERM_PAIN)) + A_PlaySound(DUKE_LONGTERM_PAIN,pPlayer->i); + P_PalFrom(pPlayer, 32, 0, 8, 0); + pSprite->extra--; + } + } + + if (RRRA && pPlayer->on_ground && trueFloorDist <= PHEIGHT+ZOFFSET2 && (floorPicnum == RRTILE7768 || floorPicnum == RRTILE7820)) + { + if ((krand2() & 3) == 1) + { + if (pPlayer->on_motorcycle) + pSprite->extra -= 2; + else + pSprite->extra -= 4; + A_PlaySound(DUKE_LONGTERM_PAIN, pPlayer->i); + } + } + else if (pPlayer->on_ground && trueFloorDist <= PHEIGHT+ZOFFSET2 && P_CheckFloorDamage(pPlayer, floorPicnum)) + { + P_DoQuote(QUOTE_BOOTS_ON, pPlayer); + pPlayer->inv_amount[GET_BOOTS] -= 2; + if (pPlayer->inv_amount[GET_BOOTS] <= 0) + { + pPlayer->inv_amount[GET_BOOTS] = 0; + P_SelectNextInvItem(pPlayer); + } + } + } + + if (pPlayer->vel.x || pPlayer->vel.y || thisPlayer.input->fvel || thisPlayer.input->svel) + { + pPlayer->crack_time = 777; + + int const checkWalkSound = sintable[pPlayer->bobcounter & 2047] >> 12; + + if (RRRA) + { + if (pPlayer->spritebridge == 0 && pPlayer->on_ground) + { + if (sectorLotag == ST_1_ABOVE_WATER) + pPlayer->not_on_water = 0; + else if (pPlayer->on_boat) + { + if (sectorLotag == 1234) + pPlayer->not_on_water = 0; + else + pPlayer->not_on_water = 1; + } + else + pPlayer->not_on_water = 1; + } + } + + if ((trueFloorDist < PHEIGHT + ZOFFSET3)) + { + if (checkWalkSound == 1 || checkWalkSound == 3) + { + if (pPlayer->spritebridge == 0 && pPlayer->walking_snd_toggle == 0 && pPlayer->on_ground) + { + switch (sectorLotag) + { + case 0: + { + int const walkPicnum = (lowZhit >= 0 && (lowZhit & 49152) == 49152) + ? TrackerCast(sprite[lowZhit & (MAXSPRITES - 1)].picnum) + : TrackerCast(sector[pPlayer->cursectnum].floorpicnum); + + if (!RR) + switch (DYNAMICTILEMAP(walkPicnum)) + { + case PANNEL1__STATIC: + case PANNEL2__STATIC: + A_PlaySound(DUKE_WALKINDUCTS, pPlayer->i); + pPlayer->walking_snd_toggle = 1; + break; + } + } + break; + + case ST_1_ABOVE_WATER: + if ((krand2() & 1) == 0 && (!RRRA || (!pPlayer->on_boat && !pPlayer->on_motorcycle && sector[pPlayer->cursectnum].lotag != 321))) + A_PlaySound(DUKE_ONWATER, pPlayer->i); + pPlayer->walking_snd_toggle = 1; + break; + } + } + } + else if (pPlayer->walking_snd_toggle > 0) + pPlayer->walking_snd_toggle--; + } + + if (pPlayer->jetpack_on == 0 && pPlayer->inv_amount[GET_STEROIDS] > 0 && pPlayer->inv_amount[GET_STEROIDS] < 400) + velocityModifier <<= 1; + + pPlayer->vel.x += (((thisPlayer.input->fvel) * velocityModifier) << 6); + pPlayer->vel.y += (((thisPlayer.input->svel) * velocityModifier) << 6); + + int playerSpeedReduction = 0; + + if (!RRRA && pPlayer->on_ground && (TEST_SYNC_KEY(playerBits, SK_CROUCH) + || (*weaponFrame > 10 && pPlayer->curr_weapon == KNEE_WEAPON))) + playerSpeedReduction = 0x2000; + else if (sectorLotag == ST_2_UNDERWATER) + playerSpeedReduction = 0x1400; + + pPlayer->vel.x = mulscale16(pPlayer->vel.x, pPlayer->runspeed - playerSpeedReduction); + pPlayer->vel.y = mulscale16(pPlayer->vel.y, pPlayer->runspeed - playerSpeedReduction); + + if (RR) + { + if (RRRA) + { + if (sector[pPlayer->cursectnum].floorpicnum == RRTILE7888) + { + if (pPlayer->on_motorcycle && pPlayer->on_ground) + pPlayer->moto_on_oil = 1; + } + else if (sector[pPlayer->cursectnum].floorpicnum == RRTILE7889) + { + if (pPlayer->on_motorcycle) + { + if (pPlayer->on_ground) + pPlayer->moto_on_mud = 1; + } + else if (pPlayer->inv_amount[GET_BOOTS] > 0) + pPlayer->inv_amount[GET_BOOTS]--; + else + { + pPlayer->vel.x = mulscale16(pPlayer->vel.x, pPlayer->runspeed); + pPlayer->vel.y = mulscale16(pPlayer->vel.y, pPlayer->runspeed); + } + } + } + if (sector[pPlayer->cursectnum].floorpicnum == RRTILE3073 || sector[pPlayer->cursectnum].floorpicnum == RRTILE2702) + { + if (RRRA && pPlayer->on_motorcycle) + { + if (pPlayer->on_ground) + { + pPlayer->vel.x = mulscale16(pPlayer->vel.x, pPlayer->runspeed-0x1800); + pPlayer->vel.y = mulscale16(pPlayer->vel.y, pPlayer->runspeed-0x1800); + } + } + else if (pPlayer->inv_amount[GET_BOOTS] > 0) + pPlayer->inv_amount[GET_BOOTS]--; + else + { + pPlayer->vel.x = mulscale16(pPlayer->vel.x, pPlayer->runspeed-0x1800); + pPlayer->vel.y = mulscale16(pPlayer->vel.y, pPlayer->runspeed-0x1800); + } + } + } + + if (klabs(pPlayer->vel.x) < 2048 && klabs(pPlayer->vel.y) < 2048) + pPlayer->vel.x = pPlayer->vel.y = 0; + + if (playerShrunk) + { + pPlayer->vel.x = mulscale16(pPlayer->vel.x, pPlayer->runspeed - (pPlayer->runspeed >> 1) + (pPlayer->runspeed >> 2)); + pPlayer->vel.y = mulscale16(pPlayer->vel.y, pPlayer->runspeed - (pPlayer->runspeed >> 1) + (pPlayer->runspeed >> 2)); + } + } + +HORIZONLY:; + int stepHeight = (sectorLotag == ST_1_ABOVE_WATER || pPlayer->spritebridge == 1) ? pPlayer->autostep_sbw : pPlayer->autostep; + +#ifdef EDUKE32_TOUCH_DEVICES + if (TEST_SYNC_KEY(playerBits, SK_CROUCH)) + stepHeight = pPlayer->autostep_sbw; +#endif + + if (ud.noclip) + { + pPlayer->pos.x += pPlayer->vel.x >> 14; + pPlayer->pos.y += pPlayer->vel.y >> 14; + updatesector(pPlayer->pos.x, pPlayer->pos.y, &pPlayer->cursectnum); + changespritesect(pPlayer->i, pPlayer->cursectnum); + // This makes the player view lower when shrunk. NOTE that it can get the + // view below the sector floor (and does, when on the ground). + if (pPlayer->jetpack_on == 0 && sectorLotag != ST_2_UNDERWATER && sectorLotag != ST_1_ABOVE_WATER && playerShrunk) + pPlayer->pos.z += ZOFFSET5; + if (RRRA && pPlayer->hurt_delay2 > 0) + pPlayer->hurt_delay2--; + } + else + { +#ifdef YAX_ENABLE + int const playerSectNum = pPlayer->cursectnum; + int16_t ceilingBunch, floorBunch; + + if (playerSectNum >= 0) + yax_getbunches(playerSectNum, &ceilingBunch, &floorBunch); + + // This updatesectorz conflicts with Duke3D's way of teleporting through water, + // so make it a bit conditional... OTOH, this way we have an ugly z jump when + // changing from above water to underwater + + if ((playerSectNum >= 0 && !(sector[playerSectNum].lotag == ST_1_ABOVE_WATER && pPlayer->on_ground && floorBunch >= 0)) + && ((floorBunch >= 0 && !(sector[playerSectNum].floorstat & 512)) + || (ceilingBunch >= 0 && !(sector[playerSectNum].ceilingstat & 512)))) + { + pPlayer->cursectnum += MAXSECTORS; // skip initial z check, restored by updatesectorz + updatesectorz(pPlayer->pos.x, pPlayer->pos.y, pPlayer->pos.z, &pPlayer->cursectnum); + } +#endif + int spriteNum = clipmove((vec3_t *)pPlayer, &pPlayer->cursectnum, pPlayer->vel.x, pPlayer->vel.y, 164, + (4L << 8), stepHeight, CLIPMASK0); + + // This makes the player view lower when shrunk. NOTE that it can get the + // view below the sector floor (and does, when on the ground). + if (pPlayer->jetpack_on == 0 && sectorLotag != ST_2_UNDERWATER && sectorLotag != ST_1_ABOVE_WATER && playerShrunk) + pPlayer->pos.z += ZOFFSET5; + + if (spriteNum) + P_CheckTouchDamage(pPlayer, spriteNum); + else if(RRRA && pPlayer->hurt_delay2 > 0) + pPlayer->hurt_delay2--; + + if (RR) + { + if ((spriteNum & 49152) == 32768) + { + int const wallNum = spriteNum&(MAXWALLS-1); + if (RRRA && pPlayer->on_motorcycle) + { + int16_t var104, var108, var10c; + var104 = 0; + var108 = getangle(wall[wall[wallNum].point2].x-wall[wallNum].x,wall[wall[wallNum].point2].y-wall[wallNum].y); + var10c = klabs(fix16_to_int(pPlayer->q16ang)-var108); + switch (krand2()&1) + { + case 0: + pPlayer->q16ang += F16(pPlayer->moto_speed>>1); + break; + case 1: + pPlayer->q16ang -= F16(pPlayer->moto_speed>>1); + break; + } + if (var10c >= 441 && var10c <= 581) + { + var104 = (pPlayer->moto_speed*pPlayer->moto_speed)>>8; + pPlayer->moto_speed = 0; + if (A_CheckSoundPlaying(pPlayer->i, 238) == 0) + A_PlaySound(238,pPlayer->i); + } + else if (var10c >= 311 && var10c <= 711) + { + var104 = (pPlayer->moto_speed*pPlayer->moto_speed)>>11; + pPlayer->moto_speed -= (pPlayer->moto_speed>>1)+(pPlayer->moto_speed>>2); + if (A_CheckSoundPlaying(pPlayer->i, 238) == 0) + A_PlaySound(238,pPlayer->i); + } + else if (var10c >= 111 && var10c <= 911) + { + var104 = (pPlayer->moto_speed*pPlayer->moto_speed)>>14; + pPlayer->moto_speed -= (pPlayer->moto_speed>>1); + if (A_CheckSoundPlaying(pPlayer->i, 239) == 0) + A_PlaySound(239,pPlayer->i); + } + else + { + var104 = (pPlayer->moto_speed*pPlayer->moto_speed)>>15; + pPlayer->moto_speed -= (pPlayer->moto_speed>>3); + if (A_CheckSoundPlaying(pPlayer->i, 240) == 0) + A_PlaySound(240,pPlayer->i); + } + pSprite->extra -= var104; + if (pSprite->extra <= 0) + { + A_PlaySound(SQUISHED,pPlayer->i); + P_PalFrom(pPlayer,63,63,0,0); + } + else if (var104) + A_PlaySound(DUKE_LAND_HURT,pPlayer->i); + } + else if (RRRA && pPlayer->on_boat) + { + short var114, var118; + var114 = getangle(wall[wall[wallNum].point2].x-wall[wallNum].x,wall[wall[wallNum].point2].y-wall[wallNum].y); + var118 = klabs(fix16_to_int(pPlayer->q16ang)-var114); + switch (krand2()&1) + { + case 0: + pPlayer->q16ang += F16(pPlayer->moto_speed>>2); + break; + case 1: + pPlayer->q16ang -= F16(pPlayer->moto_speed>>2); + break; + } + if (var118 >= 441 && var118 <= 581) + { + pPlayer->moto_speed = ((pPlayer->moto_speed>>1)+(pPlayer->moto_speed>>2))>>2; + if (sectorLotag == 1) + if (A_CheckSoundPlaying(pPlayer->i, 178) == 0) + A_PlaySound(178,pPlayer->i); + } + else if (var118 >= 311 && var118 <= 711) + { + pPlayer->moto_speed -= ((pPlayer->moto_speed>>1)+(pPlayer->moto_speed>>2))>>3; + if (sectorLotag == 1) + if (A_CheckSoundPlaying(pPlayer->i, 179) == 0) + A_PlaySound(179,pPlayer->i); + } + else if (var118 >= 111 && var118 <= 911) + { + pPlayer->moto_speed -= (pPlayer->moto_speed>>4); + if (sectorLotag == 1) + if (A_CheckSoundPlaying(pPlayer->i, 180) == 0) + A_PlaySound(180,pPlayer->i); + } + else + { + pPlayer->moto_speed -= (pPlayer->moto_speed>>6); + if (sectorLotag == 1) + if (A_CheckSoundPlaying(pPlayer->i, 181) == 0) + A_PlaySound(181,pPlayer->i); + } + } + else + { + if (wall[wallNum].lotag >= 40 && wall[wallNum].lotag <= 44) + { + if (wall[wallNum].lotag < 44) + G_DoFurniture(wallNum,pPlayer->cursectnum,playerNum); + pushmove(&pPlayer->pos,&pPlayer->cursectnum,172L,(4L<<8),(4L<<8),CLIPMASK0); + } + } + } + else if ((spriteNum & 49152) == 49152) + { + spriteNum &= (MAXSPRITES-1); + + if (RRRA && pPlayer->on_motorcycle) + { + if (A_CheckEnemySprite(&sprite[spriteNum]) || sprite[spriteNum].picnum == APLAYER) + { + if (sprite[spriteNum].picnum != APLAYER) + { + if (numplayers == 1) + { + int tilt_status = pPlayer->tilt_status; + vec3_t const vect = { + sintable[(tilt_status*20+fix16_to_int(pPlayer->q16ang)+512)&2047]>>8, + sintable[(tilt_status*20+fix16_to_int(pPlayer->q16ang))&2047]>>8,sprite[spriteNum].zvel + }; + + A_MoveSprite(spriteNum,&vect,CLIPMASK0); + } + } + else + actor[spriteNum].owner = pPlayer->i; + actor[spriteNum].picnum = MOTOHIT; + actor[spriteNum].extra = pPlayer->moto_speed>>1; + pPlayer->moto_speed -= pPlayer->moto_speed>>2; + pPlayer->moto_turb = 6; + } + else if ((sprite[spriteNum].picnum == RRTILE2431 || sprite[spriteNum].picnum == RRTILE2443 || sprite[spriteNum].picnum == RRTILE2451 || sprite[spriteNum].picnum == RRTILE2455) + && sprite[spriteNum].picnum != ACTIVATORLOCKED && pPlayer->moto_speed > 45) + { + A_PlaySound(SQUISHED,spriteNum); + if (sprite[spriteNum].picnum == RRTILE2431 || sprite[spriteNum].picnum == RRTILE2451) + { + if (sprite[spriteNum].lotag != 0) + { + for(bssize_t otherSprite = 0; otherSprite < MAXSPRITES; otherSprite++) + { + if ((sprite[otherSprite].picnum == RRTILE2431 || sprite[otherSprite].picnum == RRTILE2451) && sprite[otherSprite].pal == 4) + { + if (sprite[spriteNum].lotag == sprite[otherSprite].lotag) + { + sprite[otherSprite].xrepeat = 0; + sprite[otherSprite].yrepeat = 0; + } + } + } + } + A_DoGuts(spriteNum,RRTILE2460,12); + A_DoGuts(spriteNum,RRTILE2465,3); + } + else + A_DoGuts(spriteNum,RRTILE2465,3); + A_DoGuts(spriteNum,RRTILE2465,3); + sprite[spriteNum].xrepeat = 0; + sprite[spriteNum].yrepeat = 0; + } + } + else if (RRRA && pPlayer->on_boat) + { + if (A_CheckEnemySprite(&sprite[spriteNum]) || sprite[spriteNum].picnum == APLAYER) + { + if (sprite[spriteNum].picnum != APLAYER) + { + if (numplayers == 1) + { + int tilt_status = pPlayer->tilt_status; + vec3_t const vect = { + sintable[(tilt_status*20+fix16_to_int(pPlayer->q16ang)+512)&2047]>>9, + sintable[(tilt_status*20+fix16_to_int(pPlayer->q16ang))&2047]>>9,sprite[spriteNum].zvel + }; + + A_MoveSprite(spriteNum,&vect,CLIPMASK0); + } + } + else + actor[spriteNum].owner = pPlayer->i; + actor[spriteNum].picnum = MOTOHIT; + actor[spriteNum].extra = pPlayer->moto_speed>>2; + pPlayer->moto_speed -= pPlayer->moto_speed>>2; + pPlayer->moto_turb = 6; + } + } + else if (A_CheckEnemySprite(&sprite[spriteNum])) + { + if (sprite[spriteNum].statnum != STAT_ACTOR) + { + actor[spriteNum].timetosleep = 0; + if (sprite[spriteNum].picnum == BILLYRAY) + A_PlaySound(404, spriteNum); + else + A_PlayAlertSound(spriteNum); + changespritestat(spriteNum, STAT_ACTOR); + } + } + if (sprite[spriteNum].picnum == RRTILE3410) + { + P_QuickKill(pPlayer); + A_PlaySound(446, pPlayer->i); + } + else if (RRRA && sprite[spriteNum].picnum == RRTILE2443 && sprite[spriteNum].pal == 19) + { + sprite[spriteNum].pal = 0; + pPlayer->drug_mode = 5; + pPlayer->drug_timer = (int32_t) totalclock; + sprite[pPlayer->i].extra = pPlayer->max_player_health; + } + } + } + } + + if (pPlayer->jetpack_on == 0) + { + if (pSprite->xvel > 16) + { + if (sectorLotag != ST_1_ABOVE_WATER && sectorLotag != ST_2_UNDERWATER && pPlayer->on_ground && (!RRRA || !pPlayer->sea_sick_stat)) + { + pPlayer->pycount += 52; + pPlayer->pycount &= 2047; + pPlayer->pyoff = klabs(pSprite->xvel * sintable[pPlayer->pycount]) / 1596; + } + } + else if (sectorLotag != ST_2_UNDERWATER && sectorLotag != ST_1_ABOVE_WATER && (!RRRA || !pPlayer->sea_sick_stat)) + pPlayer->pyoff = 0; + } + + pPlayer->pos.z += PHEIGHT; + setsprite(pPlayer->i, &pPlayer->pos); + pPlayer->pos.z -= PHEIGHT; + + if (RR) + { + if (sectorLotag == 800 && (!RRRA || !pPlayer->lotag800kill)) + { + if (RRRA) + pPlayer->lotag800kill = 1; + P_QuickKill(pPlayer); + return; + } + } + + // ST_2_UNDERWATER + if (pPlayer->cursectnum >= 0 && sectorLotag < 3) + { + usectortype const *pSector = (usectortype *)§or[pPlayer->cursectnum]; + + // TRAIN_SECTOR_TO_SE_INDEX + if ((!ud.noclip && pSector->lotag == ST_31_TWO_WAY_TRAIN) && + ((unsigned)pSector->hitag < MAXSPRITES && sprite[pSector->hitag].xvel && actor[pSector->hitag].t_data[0] == 0)) + { + P_QuickKill(pPlayer); + return; + } + } + + if ((pPlayer->cursectnum >= 0 && trueFloorDist < PHEIGHT && pPlayer->on_ground && sectorLotag != ST_1_ABOVE_WATER && + playerShrunk == 0 && sector[pPlayer->cursectnum].lotag == ST_1_ABOVE_WATER) && (!A_CheckSoundPlaying(pPlayer->i, DUKE_ONWATER))) + if (!RRRA || (!pPlayer->on_boat && !pPlayer->on_motorcycle && sector[pPlayer->cursectnum].lotag != 321)) + A_PlaySound(DUKE_ONWATER, pPlayer->i); + + if (pPlayer->cursectnum >= 0 && pPlayer->cursectnum != pSprite->sectnum) + changespritesect(pPlayer->i, pPlayer->cursectnum); + + if (pPlayer->cursectnum >= 0 && ud.noclip == 0) + { + int const squishPlayer = (pushmove((vec3_t *)pPlayer, &pPlayer->cursectnum, (!RR || pSprite->clipdist == 64) ? 164 : 16, (4L << 8), (4L << 8), CLIPMASK0) < 0 && + A_GetFurthestAngle(pPlayer->i, 8) < 512); + + if (squishPlayer || klabs(actor[pPlayer->i].floorz-actor[pPlayer->i].ceilingz) < (48<<8)) + { + if (!(sector[pSprite->sectnum].lotag & 0x8000u) && + (isanunderoperator(sector[pSprite->sectnum].lotag) || isanearoperator(sector[pSprite->sectnum].lotag))) + G_ActivateBySector(pSprite->sectnum, pPlayer->i); + + if (squishPlayer) + { + P_QuickKill(pPlayer); + return; + } + } + else if (klabs(floorZ - ceilZ) < ZOFFSET5 && isanunderoperator(sector[pPlayer->cursectnum].lotag)) + G_ActivateBySector(pPlayer->cursectnum, pPlayer->i); + + if (RR && sector[pPlayer->cursectnum].ceilingz > (sector[pPlayer->cursectnum].floorz-ZOFFSET4)) + { + P_QuickKill(pPlayer); + return; + } + } + + if (pPlayer->return_to_center > 0) + pPlayer->return_to_center--; + + if (TEST_SYNC_KEY(playerBits, SK_CENTER_VIEW) || pPlayer->hard_landing) + if (VM_OnEvent(EVENT_RETURNTOCENTER, pPlayer->i,playerNum) == 0) + { + pPlayer->return_to_center = 9; + thisPlayer.horizRecenter = true; + } + + if (TEST_SYNC_KEY(playerBits, SK_LOOK_UP)) + { + if (VM_OnEvent(EVENT_LOOKUP, pPlayer->i, playerNum) == 0) + { + pPlayer->return_to_center = 9; + thisPlayer.horizRecenter = true; + thisPlayer.horizAngleAdjust = float(12<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN))); + } + } + else if (TEST_SYNC_KEY(playerBits, SK_LOOK_DOWN)) + { + if (VM_OnEvent(EVENT_LOOKDOWN,pPlayer->i,playerNum) == 0) + { + pPlayer->return_to_center = 9; + thisPlayer.horizRecenter = true; + thisPlayer.horizAngleAdjust = -float(12<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN))); + } + } + else if (TEST_SYNC_KEY(playerBits, SK_AIM_UP) && (!RRRA || !pPlayer->on_motorcycle)) + { + if (VM_OnEvent(EVENT_AIMUP,pPlayer->i,playerNum) == 0) + { + thisPlayer.horizAngleAdjust = float(6 << (int)(TEST_SYNC_KEY(playerBits, SK_RUN))); + thisPlayer.horizRecenter = false; + } + } + else if (TEST_SYNC_KEY(playerBits, SK_AIM_DOWN) && (!RRRA || !pPlayer->on_motorcycle)) + { + if (VM_OnEvent(EVENT_AIMDOWN,pPlayer->i,playerNum) == 0) + { + thisPlayer.horizAngleAdjust = -float(6 << (int)(TEST_SYNC_KEY(playerBits, SK_RUN))); + thisPlayer.horizRecenter = false; + } + } + if (RR && pPlayer->recoil && *weaponFrame == 0) + { + int delta = pPlayer->recoil >> 1; + if (!delta) delta++; + pPlayer->recoil -= delta; + pPlayer->q16horiz -= F16(delta); + } + + if (pPlayer->hard_landing > 0) + { + thisPlayer.horizSkew = -(pPlayer->hard_landing << 4); + pPlayer->hard_landing--; + } + + //Shooting code/changes + + if (pPlayer->show_empty_weapon > 0) + { + --pPlayer->show_empty_weapon; + + if (!RR && pPlayer->show_empty_weapon == 0) + { + if (pPlayer->last_full_weapon == GROW_WEAPON) + pPlayer->subweapon |= (1 << GROW_WEAPON); + else if (pPlayer->last_full_weapon == SHRINKER_WEAPON) + pPlayer->subweapon &= ~(1 << GROW_WEAPON); + + P_AddWeapon(pPlayer, pPlayer->last_full_weapon); + return; + } + } + + if (RR && pPlayer->show_empty_weapon == 1) + { + P_AddWeapon(pPlayer, pPlayer->last_full_weapon); + return; + } + + if (pPlayer->knee_incs > 0) + { + thisPlayer.horizSkew = -48; + thisPlayer.horizRecenter = true; + pPlayer->return_to_center = 9; + + if (++pPlayer->knee_incs > 15) + { + pPlayer->knee_incs = 0; + pPlayer->holster_weapon = 0; + pPlayer->weapon_pos = klabs(pPlayer->weapon_pos); + + if (pPlayer->actorsqu >= 0 && sprite[pPlayer->actorsqu].statnum != MAXSTATUS && + dist(&sprite[pPlayer->i], &sprite[pPlayer->actorsqu]) < 1400) + { + A_DoGuts(pPlayer->actorsqu, JIBS6, 7); + A_Spawn(pPlayer->actorsqu, BLOODPOOL); + A_PlaySound(SQUISHED, pPlayer->actorsqu); + switch (DYNAMICTILEMAP(sprite[pPlayer->actorsqu].picnum)) + { + case FEM1__STATIC: + case FEM2__STATIC: + case FEM3__STATIC: + case FEM4__STATIC: + case FEM5__STATIC: + case FEM6__STATIC: + case FEM7__STATIC: + case FEM8__STATIC: + case FEM9__STATIC: + case PODFEM1__STATIC: + if (RR) + break; + fallthrough__; + case FEM10__STATIC: + case NAKED1__STATIC: + case STATUE__STATIC: + if (sprite[pPlayer->actorsqu].yvel) + G_OperateRespawns(sprite[pPlayer->actorsqu].yvel); + A_DeleteSprite(pPlayer->actorsqu); + break; + case APLAYER__STATIC: + { + int playerSquished = P_Get(pPlayer->actorsqu); + P_QuickKill(g_player[playerSquished].ps); + g_player[playerSquished].ps->frag_ps = playerNum; + break; + } + default: + if (A_CheckEnemySprite(&sprite[pPlayer->actorsqu])) + P_AddKills(pPlayer, 1); + A_DeleteSprite(pPlayer->actorsqu); + break; + } + } + pPlayer->actorsqu = -1; + } + else if (pPlayer->actorsqu >= 0) + pPlayer->q16ang += fix16_from_int( + G_GetAngleDelta(fix16_to_int(pPlayer->q16ang), + getangle(sprite[pPlayer->actorsqu].x - pPlayer->pos.x, sprite[pPlayer->actorsqu].y - pPlayer->pos.y)) + >> 2); + } + + if (P_DoCounters(playerNum)) + return; + + switch (pPlayer->weapon_pos) + { + case WEAPON_POS_LOWER: + if (pPlayer->last_weapon >= 0) + { + pPlayer->weapon_pos = WEAPON_POS_RAISE; + pPlayer->last_weapon = -1; + } + else if (pPlayer->holster_weapon == 0) + pPlayer->weapon_pos = WEAPON_POS_RAISE; + break; + case 0: break; + default: pPlayer->weapon_pos--; break; + } + + P_ProcessWeapon(playerNum); +} + +void P_DHProcessInput(int playerNum) +{ + auto &thisPlayer = g_player[playerNum]; + + if (thisPlayer.playerquitflag == 0) + return; + + thisPlayer.horizAngleAdjust = 0; + thisPlayer.horizSkew = 0; + + auto const pPlayer = thisPlayer.ps; + auto const pSprite = &sprite[pPlayer->i]; + + ++pPlayer->player_par; + + uint32_t playerBits = thisPlayer.input->bits; + + pSprite->cstat = 0; + + if (pPlayer->cheat_phase > 0) + playerBits = 0; + + if (pPlayer->cursectnum == -1) + { + return; + } + + int sectorLotag = sector[pPlayer->cursectnum].lotag; + + pSprite->clipdist = 64; + + pPlayer->spritebridge = 0; + //pPlayer->sbs = 0; + + int32_t floorZ, ceilZ, highZhit, lowZhit; + getzrange((vec3_t *)pPlayer, pPlayer->cursectnum, &ceilZ, &highZhit, &floorZ, &lowZhit, 163, CLIPMASK0); + +#ifdef YAX_ENABLE + getzsofslope_player(pPlayer->cursectnum, pPlayer->pos.x, pPlayer->pos.y, &pPlayer->truecz, &pPlayer->truefz); +#else + getzsofslope(pPlayer->cursectnum, pPlayer->pos.x, pPlayer->pos.y, &pPlayer->truecz, &pPlayer->truefz); +#endif + int const trueFloorZ = pPlayer->truefz; + int const trueFloorDist = klabs(pPlayer->pos.z - trueFloorZ); + + if ((lowZhit & 49152) == 16384 && sectorLotag == 1 && trueFloorDist > PHEIGHT + ZOFFSET2) + sectorLotag = 0; + + actor[pPlayer->i].floorz = floorZ; + actor[pPlayer->i].ceilingz = ceilZ; + + if (pPlayer->q16horizoff > 0) + { + pPlayer->q16horizoff -= ((pPlayer->q16horizoff >> 3) + fix16_one); + pPlayer->q16horizoff = max(pPlayer->q16horizoff, 0); + } + else if (pPlayer->q16horizoff < 0) + { + pPlayer->q16horizoff += (((-pPlayer->q16horizoff) >> 3) + fix16_one); + pPlayer->q16horizoff = min(pPlayer->q16horizoff, 0); + } + + if (highZhit >= 0 && (highZhit&49152) == 49152) + { + highZhit &= (MAXSPRITES-1); + + if (sprite[highZhit].statnum == STAT_ACTOR && sprite[highZhit].extra >= 0) + { + highZhit = 0; + ceilZ = pPlayer->truecz; + } + } + + if (lowZhit >= 0 && (lowZhit&49152) == 49152) + { + int spriteNum = lowZhit&(MAXSPRITES-1); + + if ((sprite[spriteNum].cstat&33) == 33) + { + sectorLotag = 0; + pPlayer->footprintcount = 0; + pPlayer->spritebridge = 1; + //pPlayer->sbs = spriteNum; + } + if (A_CheckEnemySprite(&sprite[spriteNum]) && sprite[spriteNum].xrepeat > 24 + && klabs(pSprite->z - sprite[spriteNum].z) < (84 << 8)) + { + // TX: I think this is what makes the player slide off enemies... might + // be a good sprite flag to add later. + // Helix: there's also SLIDE_ABOVE_ENEMY. + int spriteAng = getangle(sprite[spriteNum].x - pPlayer->pos.x, + sprite[spriteNum].y - pPlayer->pos.y); + pPlayer->vel.x -= sintable[(spriteAng + 512) & 2047] << 4; + pPlayer->vel.y -= sintable[spriteAng & 2047] << 4; + } + } + + pSprite->extra = 32; + pPlayer->inv_amount[GET_SHIELD] = 0; + + pPlayer->last_extra = pSprite->extra; + pPlayer->loogcnt = (pPlayer->loogcnt > 0) ? pPlayer->loogcnt - 1 : 0; + + if (pPlayer->timebeforeexit > 1 && pPlayer->last_extra > 0) + { + if (--pPlayer->timebeforeexit == GAMETICSPERSEC*5) + { + FX_StopAllSounds(); + S_ClearSoundLocks(); + + if (pPlayer->customexitsound >= 0) + { + S_PlaySound(pPlayer->customexitsound); + P_DoQuote(QUOTE_WEREGONNAFRYYOURASS,pPlayer); + } + } + else if (pPlayer->timebeforeexit == 1) + { + for (bssize_t TRAVERSE_CONNECT(playerNum)) + g_player[playerNum].ps->gm = MODE_EOL; + + ud.level_number = (++ud.level_number < MAXLEVELS) ? ud.level_number : 0; + ud.m_level_number = ud.level_number; + return; + } + } + + if (pPlayer->pals.f > 0) + P_HandlePal(pPlayer); + + if (pPlayer->fta > 0 && --pPlayer->fta == 0) + { + pub = pus = NUMPAGES; + pPlayer->ftq = 0; + } + + if (g_levelTextTime > 0) + g_levelTextTime--; + + if (pPlayer->newowner >= 0) + { + P_UpdatePosWhenViewingCam(pPlayer); + P_DoCounters(playerNum); + + return; + } + + if (TEST_SYNC_KEY(playerBits, SK_LOOK_LEFT) && !pPlayer->on_motorcycle) + { + // look_left + thisPlayer.lookLeft = true; + } + else + { + thisPlayer.lookLeft = false; + } + + if (TEST_SYNC_KEY(playerBits, SK_LOOK_RIGHT) && !pPlayer->on_motorcycle) + { + // look_right + thisPlayer.lookRight = true; + } + else + { + thisPlayer.lookRight = false; + } + + int velocityModifier = TICSPERFRAME; + const uint8_t *const weaponFrame = &pPlayer->kickback_pic; + int floorZOffset = 40; + int const playerShrunk = (pSprite->yrepeat < 8); + + pPlayer->weapon_sway = (pSprite->xvel < 32 || pPlayer->on_ground == 0 || pPlayer->bobcounter == 1024) + ? (((pPlayer->weapon_sway & 2047) > (1024 + 96)) + ? (pPlayer->weapon_sway - 96) + : (((pPlayer->weapon_sway & 2047) < (1024 - 96))) + ? (pPlayer->weapon_sway + 96) + : 1024) + : pPlayer->bobcounter; + + // NOTE: This silently wraps if the difference is too great, e.g. used to do + // that when teleported by silent SE7s. + pSprite->xvel = ksqrt(uhypsq(pPlayer->pos.x - pPlayer->bobpos.x, pPlayer->pos.y - pPlayer->bobpos.y)); + + if (pPlayer->on_ground) + pPlayer->bobcounter += sprite[pPlayer->i].xvel>>1; + + if (ud.noclip == 0 && ((uint16_t)pPlayer->cursectnum >= MAXSECTORS || sector[pPlayer->cursectnum].floorpicnum == MIRROR)) + { + pPlayer->pos.x = pPlayer->opos.x; + pPlayer->pos.y = pPlayer->opos.y; + } + else + { + pPlayer->opos.x = pPlayer->pos.x; + pPlayer->opos.y = pPlayer->pos.y; + } + + pPlayer->bobpos.x = pPlayer->pos.x; + pPlayer->bobpos.y = pPlayer->pos.y; + pPlayer->opos.z = pPlayer->pos.z; + pPlayer->opyoff = pPlayer->pyoff; + + // Shrinking code + + if (sectorLotag == ST_2_UNDERWATER) + { + } + else + { + pPlayer->scuba_on = 0; + + if (pPlayer->pos.z < (floorZ-(floorZOffset<<8))) //falling + { + // not jumping or crouching + + if ((!TEST_SYNC_KEY(playerBits, SK_JUMP) && !TEST_SYNC_KEY(playerBits, SK_CROUCH)) && pPlayer->on_ground && + (sector[pPlayer->cursectnum].floorstat & 2) && pPlayer->pos.z >= (floorZ - (floorZOffset << 8) - ZOFFSET2)) + pPlayer->pos.z = floorZ - (floorZOffset << 8); + else + { + pPlayer->on_ground = 0; + pPlayer->vel.z += (g_spriteGravity + 80); // (TICSPERFRAME<<6); + + if (pPlayer->vel.z >= (4096 + 2048)) + pPlayer->vel.z = (4096 + 2048); + + if (pPlayer->vel.z > 2400 && pPlayer->falling_counter < 255) + { + pPlayer->falling_counter++; + if (pPlayer->falling_counter >= 38 && !A_CheckSoundPlaying(pPlayer->i, -1, CHAN_VOICE)) + { + int32_t voice = A_PlaySound(DUKE_SCREAM,pPlayer->i); + if (voice <= 127) // XXX: p->scream_voice is an int8_t + pPlayer->scream_voice = voice; + } + } + + if ((pPlayer->pos.z + pPlayer->vel.z) >= (floorZ - (floorZOffset << 8)) && pPlayer->cursectnum >= 0) // hit the ground + { + ghsound_footstepsound(playerNum, 1); + } + } + } + else + { + pPlayer->falling_counter = 0; + + if ((sectorLotag != ST_1_ABOVE_WATER && sectorLotag != ST_2_UNDERWATER) && + (pPlayer->on_ground == 0 && pPlayer->vel.z > (6144 >> 1))) + pPlayer->hard_landing = pPlayer->vel.z>>10; + + pPlayer->on_ground = 1; + + if (floorZOffset==40) + { + //Smooth on the ground + int Zdiff = ((floorZ - (floorZOffset << 8)) - pPlayer->pos.z) >> 1; + + if (klabs(Zdiff) < 256) + Zdiff = 0; + + pPlayer->pos.z += ((klabs(Zdiff) >= 256) ? (((floorZ - (floorZOffset << 8)) - pPlayer->pos.z) >> 1) : 0); + pPlayer->vel.z -= 768; + + if (pPlayer->vel.z < 0) + pPlayer->vel.z = 0; + } + else if (pPlayer->jumping_counter == 0) + { + pPlayer->pos.z += ((floorZ - (floorZOffset << 7)) - pPlayer->pos.z) >> 1; // Smooth on the water + + if (pPlayer->on_warping_sector == 0 && pPlayer->pos.z > floorZ - ZOFFSET2) + { + pPlayer->pos.z = floorZ - ZOFFSET2; + pPlayer->vel.z >>= 1; + } + } + + pPlayer->on_warping_sector = 0; + + if (TEST_SYNC_KEY(playerBits, SK_CROUCH) && !pPlayer->on_motorcycle) + { + // crouching + pPlayer->pos.z += (2048+768); + pPlayer->crack_time = 777; + } + + // jumping + if (!TEST_SYNC_KEY(playerBits, SK_JUMP) && !pPlayer->on_motorcycle && pPlayer->jumping_toggle == 1) + pPlayer->jumping_toggle = 0; + else if (TEST_SYNC_KEY(playerBits, SK_JUMP) && !pPlayer->on_motorcycle && pPlayer->jumping_toggle == 0) + { + if (pPlayer->jumping_counter == 0) + if ((floorZ-ceilZ) > (56<<8)) + { + pPlayer->jumping_counter = 1; + pPlayer->jumping_toggle = 1; + } + } + } + + if (pPlayer->jumping_counter) + { + if (!TEST_SYNC_KEY(playerBits, SK_JUMP) && !pPlayer->on_motorcycle && pPlayer->jumping_toggle == 1) + pPlayer->jumping_toggle = 0; + + if (pPlayer->jumping_counter < 768) + { + if (sectorLotag == ST_1_ABOVE_WATER && pPlayer->jumping_counter > 768) + { + pPlayer->jumping_counter = 0; + pPlayer->vel.z = -512; + } + else + { + pPlayer->vel.z -= (sintable[(2048-128+pPlayer->jumping_counter)&2047])/12; + pPlayer->jumping_counter += 180; + pPlayer->on_ground = 0; + } + } + else + { + pPlayer->jumping_counter = 0; + pPlayer->vel.z = 0; + } + } + + pPlayer->pos.z += pPlayer->vel.z; + + if (pPlayer->pos.z < (ceilZ+ZOFFSET6)) + { + pPlayer->jumping_counter = 0; + if (pPlayer->vel.z < 0) + pPlayer->vel.x = pPlayer->vel.y = 0; + pPlayer->vel.z = 128; + pPlayer->pos.z = ceilZ+ZOFFSET6; + } + } + + if (P_CheckLockedMovement(playerNum) & IL_NOMOVE) + { + velocityModifier = 0; + pPlayer->vel.x = 0; + pPlayer->vel.y = 0; + } + else if (thisPlayer.input->q16avel) + pPlayer->crack_time = 777; + + if (pPlayer->vel.x || pPlayer->vel.y || thisPlayer.input->fvel || thisPlayer.input->svel) + { + pPlayer->crack_time = 777; + + pPlayer->not_on_water = 1; + + pPlayer->vel.x += (((thisPlayer.input->fvel) * velocityModifier) << 6); + pPlayer->vel.y += (((thisPlayer.input->svel) * velocityModifier) << 6); + + pPlayer->vel.x = mulscale16(pPlayer->vel.x, pPlayer->runspeed); + pPlayer->vel.y = mulscale16(pPlayer->vel.y, pPlayer->runspeed); + + if (klabs(pPlayer->vel.x) < 2048 && klabs(pPlayer->vel.y) < 2048) + pPlayer->vel.x = pPlayer->vel.y = 0; + } + + int stepHeight = (sectorLotag == ST_1_ABOVE_WATER || pPlayer->spritebridge == 1) ? pPlayer->autostep_sbw : pPlayer->autostep; + +#ifdef EDUKE32_TOUCH_DEVICES + if (TEST_SYNC_KEY(playerBits, SK_CROUCH)) + stepHeight = pPlayer->autostep_sbw; +#endif + + int spriteNum; + + if (ud.noclip) + { + spriteNum = 0; + pPlayer->pos.x += pPlayer->vel.x >> 14; + pPlayer->pos.y += pPlayer->vel.y >> 14; + updatesector(pPlayer->pos.x, pPlayer->pos.y, &pPlayer->cursectnum); + changespritesect(pPlayer->i, pPlayer->cursectnum); + } + else + { +#ifdef YAX_ENABLE + int const playerSectNum = pPlayer->cursectnum; + int16_t ceilingBunch, floorBunch; + + if (playerSectNum >= 0) + yax_getbunches(playerSectNum, &ceilingBunch, &floorBunch); + + // This updatesectorz conflicts with Duke3D's way of teleporting through water, + // so make it a bit conditional... OTOH, this way we have an ugly z jump when + // changing from above water to underwater + + if ((playerSectNum >= 0 && !(sector[playerSectNum].lotag == ST_1_ABOVE_WATER && pPlayer->on_ground && floorBunch >= 0)) + && ((floorBunch >= 0 && !(sector[playerSectNum].floorstat & 512)) + || (ceilingBunch >= 0 && !(sector[playerSectNum].ceilingstat & 512)))) + { + pPlayer->cursectnum += MAXSECTORS; // skip initial z check, restored by updatesectorz + updatesectorz(pPlayer->pos.x, pPlayer->pos.y, pPlayer->pos.z, &pPlayer->cursectnum); + } +#endif + int const oldSector = pPlayer->cursectnum; + spriteNum = clipmove((vec3_t *)pPlayer, &pPlayer->cursectnum, pPlayer->vel.x, pPlayer->vel.y, 164, + (4L << 8), stepHeight, CLIPMASK0); + + if (pPlayer->cursectnum >= 0 && pPlayer->cursectnum < numsectors && sector[pPlayer->cursectnum].hitag == 2002) + { + pPlayer->pos = pPlayer->opos; + pPlayer->cursectnum = oldSector; + P_DoQuote(152, pPlayer); + clipmove((vec3_t*)pPlayer, &pPlayer->cursectnum, 0, 0, 164, (4L << 8), stepHeight, CLIPMASK0); + } + } + + int waterSector = (sector[pPlayer->cursectnum].hitag == 2003); + + if (waterSector) + pPlayer->pos.z += 2048; + + if ((spriteNum & 49152) == 32768) + { + } + else if ((spriteNum & 49152) == 49152) + { + spriteNum &= (MAXSPRITES-1); + + ghsound_plrtouchedsprite(spriteNum, playerNum); + ghdeploy_plrtouchedsprite(spriteNum, playerNum); + } + + if (pPlayer->jetpack_on == 0) + { + if (thisPlayer.input->fvel && pPlayer->on_ground) + { + pPlayer->pycount += 64; + pPlayer->pycount &= 2047; + if (TEST_SYNC_KEY(playerBits, SK_CROUCH)) + { + pPlayer->pyoff = klabs(sintable[pPlayer->pycount]) >> 6; + ghsound_footstepsound(playerNum, 2); + } + else if (TEST_SYNC_KEY(playerBits, SK_RUN)) + { + pPlayer->pyoff = klabs(sintable[pPlayer->pycount]) >> 5; + pPlayer->pyoff += 256; + if (waterSector) + pPlayer->pyoff += 512; + ghsound_footstepsound(playerNum, 1); + } + else + { + pPlayer->pyoff = klabs(sintable[pPlayer->pycount]) >> 6; + pPlayer->pyoff += 16; + if (waterSector) + pPlayer->pyoff += 512; + ghsound_footstepsound(playerNum, 0); + } + } + else + pPlayer->pyoff = 0; + } + + pPlayer->pos.z += PHEIGHT; + setsprite(pPlayer->i, &pPlayer->pos); + pPlayer->pos.z -= PHEIGHT; + + if (pPlayer->cursectnum >= 0 && pPlayer->cursectnum != pSprite->sectnum) + changespritesect(pPlayer->i, pPlayer->cursectnum); + + if (pPlayer->cursectnum >= 0 && ud.noclip == 0) + { + int const squishPlayer = (pushmove((vec3_t *)pPlayer, &pPlayer->cursectnum, (!RR || pSprite->clipdist == 64) ? 164 : 16, (4L << 8), (4L << 8), CLIPMASK0) < 0 && + A_GetFurthestAngle(pPlayer->i, 8) < 512); + } + + if (pPlayer->return_to_center > 0) + pPlayer->return_to_center--; + + if (TEST_SYNC_KEY(playerBits, SK_CENTER_VIEW) || pPlayer->hard_landing) + { + pPlayer->return_to_center = 9; + thisPlayer.horizRecenter = true; + } + + if (TEST_SYNC_KEY(playerBits, SK_LOOK_UP)) + { + pPlayer->return_to_center = 9; + thisPlayer.horizRecenter = true; + thisPlayer.horizAngleAdjust = float(12<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN))); + } + else if (TEST_SYNC_KEY(playerBits, SK_LOOK_DOWN)) + { + pPlayer->return_to_center = 9; + thisPlayer.horizRecenter = true; + thisPlayer.horizAngleAdjust = -float(12<<(int)(TEST_SYNC_KEY(playerBits, SK_RUN))); + } + else if (TEST_SYNC_KEY(playerBits, SK_AIM_UP) && !pPlayer->on_motorcycle) + { + thisPlayer.horizAngleAdjust = float(6 << (int)(TEST_SYNC_KEY(playerBits, SK_RUN))); + thisPlayer.horizRecenter = false; + } + else if (TEST_SYNC_KEY(playerBits, SK_AIM_DOWN) && !pPlayer->on_motorcycle) + { + thisPlayer.horizAngleAdjust = -float(6 << (int)(TEST_SYNC_KEY(playerBits, SK_RUN))); + thisPlayer.horizRecenter = false; + } + if (RR && pPlayer->recoil && *weaponFrame == 0) + { + int delta = pPlayer->recoil >> 1; + if (!delta) delta++; + pPlayer->recoil -= delta; + pPlayer->q16horiz -= F16(delta); + } + + if (pPlayer->hard_landing > 0) + { + thisPlayer.horizSkew = -(pPlayer->hard_landing << 4); + pPlayer->hard_landing--; + } + + if (TEST_SYNC_KEY(playerBits, SK_FIRE)) + A_DHShoot(playerNum); +} + +int P_HasKey(int sectNum, int playerNum) +{ + if (g_sectorExtra[sectNum] == 0) + return 1; + if (g_sectorExtra[sectNum] > 6) + return 1; + + int key = g_sectorExtra[sectNum]; + if (key > 3) + key -= 3; + + if (g_player[playerNum].ps->keys[key] == 1) + { + g_sectorExtra[sectNum] = 0; + return 1; + } + return 0; +} + +END_DUKE_NS diff --git a/source/duke/src/player.h b/source/duke/src/player.h new file mode 100644 index 000000000..11db93abb --- /dev/null +++ b/source/duke/src/player.h @@ -0,0 +1,385 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef player_h_ +#define player_h_ + +#include "inv.h" +#include "namesdyn.h" +#include "fix16.h" +#include "net.h" + +BEGIN_DUKE_NS + +extern int32_t g_mostConcurrentPlayers; + +#define MOVEFIFOSIZ 256 + +#define NAM_GRENADE_LIFETIME 120 +#define NAM_GRENADE_LIFETIME_VAR 30 + +#define HORIZ_MIN -99 +#define HORIZ_MAX 299 +#define AUTO_AIM_ANGLE 48 +#define PHEIGHT_DUKE (38<<8) +#define PHEIGHT_RR (40<<8); +extern int32_t PHEIGHT; + +#define TRIPBOMB_TRIPWIRE 0x00000001 +#define TRIPBOMB_TIMER 0x00000002 + +#define PIPEBOMB_REMOTE 0x00000001 +#define PIPEBOMB_TIMER 0x00000002 + +#define WEAPON_POS_LOWER -9 +#define WEAPON_POS_RAISE 10 +#define WEAPON_POS_START 6 + +#define MAX_WEAPON_RECS 256 + +enum weaponflags_t { + WEAPON_SPAWNTYPE1 = 0x00000000, // just spawn + WEAPON_HOLSTER_CLEARS_CLIP = 0x00000001, // 'holstering' clears the current clip + WEAPON_GLOWS = 0x00000002, // weapon 'glows' (shrinker and grower) + WEAPON_AUTOMATIC = 0x00000004, // automatic fire (continues while 'fire' is held down + WEAPON_FIREEVERYOTHER = 0x00000008, // during 'hold time' fire every frame + WEAPON_FIREEVERYTHIRD = 0x00000010, // during 'hold time' fire every third frame + WEAPON_RANDOMRESTART = 0x00000020, // restart for automatic is 'randomized' by RND 3 + WEAPON_AMMOPERSHOT = 0x00000040, // uses ammo for each shot (for automatic) + WEAPON_BOMB_TRIGGER = 0x00000080, // weapon is the 'bomb' trigger + WEAPON_NOVISIBLE = 0x00000100, // weapon use does not cause user to become 'visible' + WEAPON_THROWIT = 0x00000200, // weapon 'throws' the 'shoots' item... + WEAPON_CHECKATRELOAD = 0x00000400, // check weapon availability at 'reload' time + WEAPON_STANDSTILL = 0x00000800, // player stops jumping before actual fire (like tripbomb in duke) + WEAPON_SPAWNTYPE2 = 0x00001000, // spawn like shotgun shells + WEAPON_SPAWNTYPE3 = 0x00002000, // spawn like chaingun shells +}; + +enum gamemode_t { + MODE_MENU = 0x00000001, + MODE_DEMO = 0x00000002, + MODE_GAME = 0x00000004, + MODE_EOL = 0x00000008, + MODE_TYPE = 0x00000010, + MODE_RESTART = 0x00000020, + MODE_SENDTOWHOM = 0x00000040, +}; + +// Player Actions. +enum playeraction_t { + pstanding = 0x00000001, + pwalking = 0x00000002, + prunning = 0x00000004, + pducking = 0x00000008, + pfalling = 0x00000010, + pjumping = 0x00000020, + phigher = 0x00000040, + pwalkingback = 0x00000080, + prunningback = 0x00000100, + pkicking = 0x00000200, + pshrunk = 0x00000400, + pjetpack = 0x00000800, + ponsteroids = 0x00001000, + ponground = 0x00002000, + palive = 0x00004000, + pdead = 0x00008000, + pfacing = 0x00010000 +}; + +typedef struct { + vec3_t pos; + int16_t ang, sect; +} playerspawn_t; + +typedef struct { + int16_t got_access, last_extra, inv_amount[GET_MAX], curr_weapon, holoduke_on; + int16_t last_weapon, weapon_pos, kickback_pic; + int16_t ammo_amount[MAX_WEAPONS], frag[MAXPLAYERS]; + uint32_t gotweapon; + char inven_icon, jetpack_on, heat_on; +} DukeStatus_t; + +typedef struct { + uint32_t bits; + int16_t fvel, svel; + fix16_t q16avel, q16horz; + int8_t extbits; +} input_t; + +#pragma pack(push,1) +// XXX: r1625 changed a lot types here, among others +// * int32_t --> int16_t +// * int16_t --> int8_t +// * char --> int8_t +// Need to carefully think about implications! +// TODO: rearrange this if the opportunity arises! +typedef struct { + vec3_t pos, opos, vel, npos; + vec2_t bobpos, fric; + + fix16_t q16horiz, q16horizoff, oq16horiz, oq16horizoff; + fix16_t q16ang, oq16ang, q16angvel; + + int32_t truefz, truecz, player_par; + int32_t randomflamex, exitx, exity; + int32_t runspeed, max_player_health, max_shield_amount; + int32_t autostep, autostep_sbw; + + uint32_t interface_toggle_flag; + uint16_t max_actors_killed, actors_killed; + uint32_t gotweapon; + uint16_t zoom; + + int16_t loogiex[64], loogiey[64], sbs, sound_pitch; + + int16_t cursectnum, last_extra, subweapon; + int16_t max_ammo_amount[MAX_WEAPONS], ammo_amount[MAX_WEAPONS], inv_amount[GET_MAX]; + int16_t wackedbyactor, pyoff, opyoff; + fix16_t q16look_ang; + + int16_t newowner, jumping_counter, airleft; + int16_t fta, ftq, access_wallnum, access_spritenum; + int16_t got_access, weapon_ang, visibility; + int16_t somethingonplayer, on_crane, i, one_parallax_sectnum; + int16_t random_club_frame, one_eighty_count; + int16_t dummyplayersprite, extra_extra8; + int16_t actorsqu, timebeforeexit, customexitsound, last_pissed_time; + fix16_t one_eighty_target; + + int16_t weaprecs[MAX_WEAPON_RECS], weapon_sway, crack_time, bobcounter; + + int16_t dead_flag; + fix16_t oq16rotscrnang, q16rotscrnang; // JBF 20031220: added orotscrnang + int16_t holoduke_on, pycount; + int16_t transporter_hold/*, clipdist*/; + + uint8_t max_secret_rooms, secret_rooms; + // XXX: 255 values for frag(gedself) seems too small. + uint8_t frag, fraggedself, quick_kick, last_quick_kick; + uint8_t return_to_center, reloading, weapreccnt; + uint8_t aim_mode, auto_aim, weaponswitch, movement_lock, team; + uint8_t tipincs, hbomb_hold_delay, frag_ps, kickback_pic; + + uint8_t gm, on_warping_sector, footprintcount, hurt_delay; + uint8_t hbomb_on, jumping_toggle, rapid_fire_hold, on_ground; + uint8_t inven_icon, buttonpalette, over_shoulder_on, show_empty_weapon; + + uint8_t jetpack_on, spritebridge, lastrandomspot; + uint8_t scuba_on, footprintpal, heat_on, invdisptime; + + uint8_t holster_weapon, falling_counter, footprintshade; + uint8_t refresh_inventory, last_full_weapon; + + uint8_t toggle_key_flag, knuckle_incs, knee_incs, access_incs; + uint8_t walking_snd_toggle, palookup, hard_landing, fist_incs; + + int8_t numloogs, loogcnt, scream_voice; + int8_t last_weapon, cheat_phase, weapon_pos, wantweaponfire, curr_weapon; + + uint8_t palette; + palette_t pals; + + int8_t last_used_weapon; + + int16_t recoil; + int32_t stairs; + int32_t hbomb_offset; + int16_t hbomb_time; + uint8_t shotgun_state[2]; + uint8_t make_noise; + int32_t noise_x, noise_y, noise_radius; + uint8_t keys[5]; + int16_t yehaa_timer; + int16_t drink_amt, eat_amt, drink_ang, eat_ang; + int32_t drink_timer, eat_timer; + int16_t level_end_timer; + int16_t moto_speed, moto_drink; + uint8_t on_motorcycle, on_boat, moto_underwater, not_on_water, moto_on_ground; + uint8_t moto_do_bump, moto_bump_fast, moto_on_oil, moto_on_mud; + int16_t moto_bump, moto_bump_target, moto_turb; + int16_t drug_stat[3]; + int32_t drug_aspect; + uint8_t drug_mode, lotag800kill, sea_sick_stat; + int32_t drug_timer; + int32_t sea_sick; + uint8_t hurt_delay2, nocheat; + double tilt_status; + + int32_t dhat60f, dhat613, dhat617, dhat61b, dhat61f; + + int8_t crouch_toggle; + int8_t padding_[3]; +} DukePlayer_t; + +typedef struct +{ + DukePlayer_t *ps; + input_t *input; + + bool horizRecenter; + float horizAngleAdjust; + int8_t horizSkew; + bool lookLeft; + bool lookRight; + double lastInputTicks; + + int32_t movefifoend, syncvalhead, myminlag; + int32_t pcolor, pteam; + // NOTE: wchoice[HANDREMOTE_WEAPON .. MAX_WEAPONS-1] unused + uint8_t frags[MAXPLAYERS], wchoice[MAX_WEAPONS]; + + char vote, gotvote, playerreadyflag, playerquitflag, connected; + char user_name[32]; + char syncval[SYNCFIFOSIZ][MAXSYNCBYTES]; +} playerdata_t; +#pragma pack(pop) + +typedef struct +{ + // NOTE: the member names must be identical to aplWeapon* suffixes. + int32_t WorksLike; // What the original works like + int32_t Clip; // number of items in magazine + int32_t Reload; // delay to reload (include fire) + int32_t FireDelay; // delay to fire + int32_t TotalTime; // The total time the weapon is cycling before next fire. + int32_t HoldDelay; // delay after release fire button to fire (0 for none) + int32_t Flags; // Flags for weapon + int32_t Shoots; // what the weapon shoots + int32_t SpawnTime; // the frame at which to spawn an item + int32_t Spawn; // the item to spawn + int32_t ShotsPerBurst; // number of shots per 'burst' (one ammo per 'burst') + int32_t InitialSound; // Sound made when weapon starts firing. zero for no sound + int32_t FireSound; // Sound made when firing (each time for automatic) + int32_t Sound2Time; // Alternate sound time + int32_t Sound2Sound; // Alternate sound sound ID + int32_t FlashColor; // Muzzle flash color +} weapondata_t; + +# define PWEAPON(Player, Weapon, Wmember) (aplWeapon ## Wmember [Weapon][Player]) +extern intptr_t *aplWeaponClip[MAX_WEAPONS]; // number of items in clip +extern intptr_t *aplWeaponReload[MAX_WEAPONS]; // delay to reload (include fire) +extern intptr_t *aplWeaponFireDelay[MAX_WEAPONS]; // delay to fire +extern intptr_t *aplWeaponHoldDelay[MAX_WEAPONS]; // delay after release fire button to fire (0 for none) +extern intptr_t *aplWeaponTotalTime[MAX_WEAPONS]; // The total time the weapon is cycling before next fire. +extern intptr_t *aplWeaponFlags[MAX_WEAPONS]; // Flags for weapon +extern intptr_t *aplWeaponShoots[MAX_WEAPONS]; // what the weapon shoots +extern intptr_t *aplWeaponSpawnTime[MAX_WEAPONS]; // the frame at which to spawn an item +extern intptr_t *aplWeaponSpawn[MAX_WEAPONS]; // the item to spawn +extern intptr_t *aplWeaponShotsPerBurst[MAX_WEAPONS]; // number of shots per 'burst' (one ammo per 'burst' +extern intptr_t *aplWeaponWorksLike[MAX_WEAPONS]; // What original the weapon works like +extern intptr_t *aplWeaponInitialSound[MAX_WEAPONS]; // Sound made when initialy firing. zero for no sound +extern intptr_t *aplWeaponFireSound[MAX_WEAPONS]; // Sound made when firing (each time for automatic) +extern intptr_t *aplWeaponSound2Time[MAX_WEAPONS]; // Alternate sound time +extern intptr_t *aplWeaponSound2Sound[MAX_WEAPONS]; // Alternate sound sound ID +extern intptr_t *aplWeaponFlashColor[MAX_WEAPONS]; // Color for polymer muzzle flash + +typedef struct { + int32_t cur, count; // "cur" is the only member that is *used* + int32_t gunposx, lookhalfang; // weapon_xoffset, ps->look_ang>>1 + int32_t gunposy, lookhoriz; // gun_pos, looking_arc + int32_t shade; +} hudweapon_t; + +extern input_t inputfifo[MOVEFIFOSIZ][MAXPLAYERS]; +extern playerspawn_t g_playerSpawnPoints[MAXPLAYERS]; +extern playerdata_t *const g_player; +extern int16_t WeaponPickupSprites[MAX_WEAPONS]; +extern hudweapon_t hudweap; +extern int32_t g_levelTextTime; +extern int32_t g_numObituaries; +extern int32_t g_numSelfObituaries; +extern int32_t mouseyaxismode; +extern int32_t ticrandomseed; + +#define SHOOT_HARDCODED_ZVEL INT32_MIN + +int A_Shoot(int spriteNum, int projecTile); + +static inline void P_PalFrom(DukePlayer_t *pPlayer, uint8_t f, uint8_t r, uint8_t g, uint8_t b) +{ + pPlayer->pals.f = f; + pPlayer->pals.r = r; + pPlayer->pals.g = g; + pPlayer->pals.b = b; +} + +void P_AddKills(DukePlayer_t * pPlayer, uint16_t kills); +int32_t A_GetHitscanRange(int spriteNum); +void P_GetInput(int playerNum); +void P_GetInputMotorcycle(int playerNum); +void P_GetInputBoat(int playerNum); +void sub_299C0(void); +void P_DHGetInput(int const playerNum); +void P_AddAmmo(DukePlayer_t * pPlayer, int weaponNum, int addAmount); +void P_AddWeapon(DukePlayer_t *pPlayer, int weaponNum); +void P_CheckWeapon(DukePlayer_t *pPlayer); +void P_DisplayScuba(void); +void P_DisplayWeapon(void); +void P_DropWeapon(int playerNum); +int P_FindOtherPlayer(int playerNum, int32_t *pDist); +void P_FragPlayer(int playerNum); +#ifdef YAX_ENABLE +void getzsofslope_player(int sectNum, int playerX, int playerY, int32_t *pCeilZ, int32_t *pFloorZ); +#endif +void P_UpdatePosWhenViewingCam(DukePlayer_t *pPlayer); +void P_ProcessInput(int playerNum); +void P_DHProcessInput(int playerNum); +void P_QuickKill(DukePlayer_t *pPlayer); +void P_SelectNextInvItem(DukePlayer_t *pPlayer); +void P_UpdateScreenPal(DukePlayer_t *pPlayer); +void P_EndLevel(void); +void P_CheckWeaponI(int playerNum); +int P_GetHudPal(const DukePlayer_t *pPlayer); +int P_GetKneePal(const DukePlayer_t *pPlayer); +int P_GetKneePal(const DukePlayer_t *pPlayer, int hudPal); +int P_GetOverheadPal(const DukePlayer_t *pPlayer); +void P_MadeNoise(int playerNum); +int P_HasKey(int sectNum, int playerNum); + +// Get the player index given an APLAYER sprite pointer. +static inline int P_GetP(const void *pSprite) +{ +#if 0 // unprotected player index retrieval + return spr->yvel; +#elif defined NETCODE_DISABLE + UNREFERENCED_PARAMETER(pSprite); // for NDEBUG build + // NOTE: In the no-netcode build, there's no point to pass player indices + // at all since there is ever only one player. However, merely returning 0 + // would mean making this build less strict than the normal one. + Bassert(((const uspritetype *)pSprite)->yvel == 0); + return 0; +#else + int playerNum = ((const uspritetype *)pSprite)->yvel; + // [JM] Check against MAXPLAYERS as opposed to g_mostConcurrentPlayers + // to prevent CON for disconnected/fake players from executing as playernum 0. + if ((unsigned)playerNum >= MAXPLAYERS) + playerNum = 0; + return playerNum; +#endif +} + +// Get the player index given an APLAYER sprite index. +static inline int P_Get(int32_t spriteNum) { return P_GetP((const uspritetype *)&sprite[spriteNum]); } + +END_DUKE_NS + +#endif diff --git a/source/duke/src/playmve.cpp b/source/duke/src/playmve.cpp new file mode 100644 index 000000000..ba4fdfbd8 --- /dev/null +++ b/source/duke/src/playmve.cpp @@ -0,0 +1,1197 @@ +/* + * InterplayDecoder + * Copyright (C) 2020 sirlemonhead + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This code is based on interplayvideo.c, dpcm.c and ipmovie.c from the FFmpeg project which can be obtained + * from http://www.ffmpeg.org/. Below is the license from interplayvideo.c + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Interplay MVE Video Decoder + * Copyright (C) 2003 The FFmpeg project + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + +#include "playmve.h" +#include "filestream.h" + +#define kAudioBlocks 20 // alloc a lot of blocks - need to store lots of audio data before video frames start. + + +static const int16_t delta_table[] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 47, 51, 56, 61, + 66, 72, 79, 86, 94, 102, 112, 122, + 133, 145, 158, 173, 189, 206, 225, 245, + 267, 292, 318, 348, 379, 414, 452, 493, + 538, 587, 640, 699, 763, 832, 908, 991, + 1081, 1180, 1288, 1405, 1534, 1673, 1826, 1993, + 2175, 2373, 2590, 2826, 3084, 3365, 3672, 4008, + 4373, 4772, 5208, 5683, 6202, 6767, 7385, 8059, + 8794, 9597, 10472, 11428, 12471, 13609, 14851, 16206, + 17685, 19298, 21060, 22981, 25078, 27367, 29864, 32589, + -29973, -26728, -23186, -19322, -15105, -10503, -5481, -1, + 1, 1, 5481, 10503, 15105, 19322, 23186, 26728, + 29973, -32589, -29864, -27367, -25078, -22981, -21060, -19298, + -17685, -16206, -14851, -13609, -12471, -11428, -10472, -9597, + -8794, -8059, -7385, -6767, -6202, -5683, -5208, -4772, + -4373, -4008, -3672, -3365, -3084, -2826, -2590, -2373, + -2175, -1993, -1826, -1673, -1534, -1405, -1288, -1180, + -1081, -991, -908, -832, -763, -699, -640, -587, + -538, -493, -452, -414, -379, -348, -318, -292, + -267, -245, -225, -206, -189, -173, -158, -145, + -133, -122, -112, -102, -94, -86, -79, -72, + -66, -61, -56, -51, -47, -43, -42, -41, + -40, -39, -38, -37, -36, -35, -34, -33, + -32, -31, -30, -29, -28, -27, -26, -25, + -24, -23, -22, -21, -20, -19, -18, -17, + -16, -15, -14, -13, -12, -11, -10, -9, + -8, -7, -6, -5, -4, -3, -2, -1 +}; + +class InterplayDecoder +{ +public: + InterplayDecoder(); + ~InterplayDecoder(); + + bool Open(const char* fileName); + void Close(); + + struct AudioBlock + { + int16_t buf[6000]; + uint32_t size; + }; + + struct AudioData + { + int hFx; + int nChannels; + uint16_t nSampleRate; + uint8_t nBitDepth; + + AudioBlock block[kAudioBlocks]; + int nWrite; + int nRead; + }; + + AudioData audio; + mutex_t mutex; + +private: + struct DecodeMap + { + uint8_t* pData; + uint32_t nSize; + }; + + struct Palette + { + uint8_t r; + uint8_t g; + uint8_t b; + }; + + bool Run(); + uint8_t* GetCurrentFrame(); + uint8_t* GetPreviousFrame(); + void SwapFrames(); + void CopyBlock(uint8_t* pDest, uint8_t* pSrc); + void DecodeBlock0(int32_t offset); + void DecodeBlock1(int32_t offset); + void DecodeBlock2(int32_t offset); + void DecodeBlock3(int32_t offset); + void DecodeBlock4(int32_t offset); + void DecodeBlock5(int32_t offset); + void DecodeBlock7(int32_t offset); + void DecodeBlock8(int32_t offset); + void DecodeBlock9(int32_t offset); + void DecodeBlock10(int32_t offset); + void DecodeBlock11(int32_t offset); + void DecodeBlock12(int32_t offset); + void DecodeBlock13(int32_t offset); + void DecodeBlock14(int32_t offset); + void DecodeBlock15(int32_t offset); + + RedNukem::FileStream file; + + bool bIsPlaying, bAudioStarted; + + uint32_t nTimerRate, nTimerDiv; + uint32_t nWidth, nHeight, nFrame; + double nFps; + uint32_t nFrameDuration; + + uint8_t* pVideoBuffers[2]; + uint32_t nCurrentVideoBuffer, nPreviousVideoBuffer; + int32_t videoStride; + + DecodeMap decodeMap; + + Palette palette[256]; +}; + +// macro to fetch 16-bit little-endian words from a bytestream +#define LE_16(x) ((*x) | ((*(x+1)) << 8)) + +int ClipRange(int val, int min, int max) +{ + if (val < min) + return min; + else if (val > max) + return max; + else + return val; +} + +void ServeAudioSample(const char** ptr, uint32_t* length, void *userdata) +{ + InterplayDecoder* pId = (InterplayDecoder*)userdata; + + mutex_lock(&pId->mutex); + + uint32_t nSize = pId->audio.block[pId->audio.nRead].size; + + *ptr = (char*)pId->audio.block[pId->audio.nRead].buf; + *length = nSize / 2; + + pId->audio.nRead++; + if (pId->audio.nRead >= kAudioBlocks) + pId->audio.nRead = 0; + + mutex_unlock(&pId->mutex); +} + +InterplayDecoder::InterplayDecoder() +{ + bIsPlaying = false; + bAudioStarted = false; + + mutex = 0; + nWidth = 0; + nHeight = 0; + nFrame = 0; + + memset(palette, 0, sizeof(palette)); + + for (int i = 0; i < kAudioBlocks; i++) { + memset(audio.block[i].buf, 0, sizeof(audio.block[i].buf)); + audio.block[i].size = 0; + } + + nFps = 0.0; + nFrameDuration = 0; + nTimerRate = 0; + nTimerDiv = 0; + + audio.nChannels = 0; + audio.nSampleRate = 0; + audio.nBitDepth = 0; + audio.nRead = 0; + audio.nWrite = 0; + audio.hFx = 0; + + pVideoBuffers[0] = nullptr; + pVideoBuffers[1] = nullptr; + + decodeMap.pData = nullptr; + decodeMap.nSize = 0; + + nCurrentVideoBuffer = 0; + nPreviousVideoBuffer = 1; + + videoStride = 0; + + mutex_init(&mutex); +} + +InterplayDecoder::~InterplayDecoder() +{ + file.Close(); + mutex_destroy(&mutex); + + if (decodeMap.pData) { + delete[] decodeMap.pData; + } + + if (pVideoBuffers[0]) { + delete[] pVideoBuffers[0]; + } + if (pVideoBuffers[1]) { + delete[] pVideoBuffers[1]; + } +} + +bool playmve(const char* filename) +{ + InterplayDecoder *id = new InterplayDecoder; + id->Open(filename); + + delete id; + + return true; +} + +void InterplayDecoder::SwapFrames() +{ + int t = nPreviousVideoBuffer; + nPreviousVideoBuffer = nCurrentVideoBuffer; + nCurrentVideoBuffer = t; +} + +void InterplayDecoder::Close() +{ + bIsPlaying = false; + + if (audio.hFx > 0) { + FX_StopSound(audio.hFx); + } +} + +bool InterplayDecoder::Open(const char* fileName) +{ + // open the file (read only) + file.Open(fileName); + if (!file.Is_Open()) + { + initprintf("InterplayDecoder: Can't open file %s\n", fileName); + return false; + } + + char lsig[20]; + + // check the file signature + file.ReadBytes((uint8_t*)lsig, sizeof(lsig)); + if (memcmp(lsig, "Interplay MVE File\x1A\0", sizeof(lsig)) != 0) + { + initprintf("InterplayDecoder: Unknown MVE signature\n "); + return false; + } + + // skip the next 6 bytes + file.Skip(6); + + Run(); + + return true; +} + +bool InterplayDecoder::Run() +{ + uint8_t chunkPreamble[CHUNK_PREAMBLE_SIZE]; + uint8_t opcodePreamble[OPCODE_PREAMBLE_SIZE]; + uint8_t opcodeType; + uint8_t opcodeVersion; + int opcodeSize, chunkSize; + int chunkType = 0; + + auto const oyxaspect = yxaspect; + + int nScale = tabledivide32(scale(65536, ydim << 2, xdim * 3), ((max(nHeight, 240 + 1u) + 239) / 240)); + int nStat = 2|4|8|64|1024; + renderSetAspect(viewingrange, 65536); + + uint32_t nNextFrameTime = (uint32_t)totalclock + nFrameDuration; + + bIsPlaying = true; + + // iterate through the chunks in the file + while (chunkType != CHUNK_END && bIsPlaying) + { + handleevents(); + + // handle timing - wait until we're ready to process the next frame. + if (nNextFrameTime > (uint32_t)totalclock) { + continue; + } + else { + nNextFrameTime = (uint32_t)totalclock + nFrameDuration; + } + + if (file.ReadBytes(chunkPreamble, CHUNK_PREAMBLE_SIZE) != CHUNK_PREAMBLE_SIZE) { + initprintf("InterplayDecoder: could not read from file (EOF?)\n"); + return false; + } + + chunkSize = LE_16(&chunkPreamble[0]); + chunkType = LE_16(&chunkPreamble[2]); + + switch (chunkType) + { + case CHUNK_INIT_AUDIO: + break; + case CHUNK_AUDIO_ONLY: + break; + case CHUNK_INIT_VIDEO: + break; + case CHUNK_VIDEO: + break; + case CHUNK_SHUTDOWN: + break; + case CHUNK_END: + bIsPlaying = false; + break; + default: + break; + } + + // iterate through individual opcodes + while (chunkSize > 0) + { + handleevents(); + + if (KB_KeyWaiting()) { + renderSetAspect(viewingrange, oyxaspect); + Close(); + return true; + } + + if (file.ReadBytes(opcodePreamble, OPCODE_PREAMBLE_SIZE) != OPCODE_PREAMBLE_SIZE) + { + initprintf("InterplayDecoder: could not read from file (EOF?)\n"); + return false; + } + + opcodeSize = LE_16(&opcodePreamble[0]); + opcodeType = opcodePreamble[2]; + opcodeVersion = opcodePreamble[3]; + + chunkSize -= OPCODE_PREAMBLE_SIZE; + chunkSize -= opcodeSize; + + switch (opcodeType) + { + case OPCODE_END_OF_STREAM: + { + file.Skip(opcodeSize); + break; + } + + case OPCODE_END_OF_CHUNK: + { + file.Skip(opcodeSize); + break; + } + + case OPCODE_CREATE_TIMER: + { + nTimerRate = file.ReadUint32LE(); + nTimerDiv = file.ReadUint16LE(); + nFps = 1000000.0f / ((double)nTimerRate * nTimerDiv); + nFrameDuration = 120.0f / nFps; + break; + } + + case OPCODE_INIT_AUDIO_BUFFERS: + { + file.Skip(2); + uint16_t flags = file.ReadUint16LE(); + audio.nSampleRate = file.ReadUint16LE(); + + uint32_t nBufferBytes; + + if (opcodeVersion == 0) { + nBufferBytes = file.ReadUint16LE(); + } + else { + nBufferBytes = file.ReadUint32LE(); + } + + if (flags & 0x1) { + audio.nChannels = 2; + } + else { + audio.nChannels = 1; + } + if (flags & 0x2) { + audio.nBitDepth = 16; + } + else { + audio.nBitDepth = 8; + } + break; + } + + case OPCODE_START_STOP_AUDIO: + { + if (!bAudioStarted) + { + // start audio playback + audio.hFx = FX_StartDemandFeedPlayback(ServeAudioSample, audio.nBitDepth, audio.nChannels, audio.nSampleRate, 0, 128, 128, 128, FX_MUSIC_PRIORITY, fix16_one, -1, this); + bAudioStarted = true; + } + + file.Skip(opcodeSize); + break; + } + + case OPCODE_INIT_VIDEO_BUFFERS: + { + assert(opcodeSize == 8); + nWidth = file.ReadUint16LE() * 8; + nHeight = file.ReadUint16LE() * 8; + + int count = file.ReadUint16LE(); + int truecolour = file.ReadUint16LE(); + assert(truecolour == 0); + + pVideoBuffers[0] = new uint8_t[nWidth * nHeight]; + pVideoBuffers[1] = new uint8_t[nWidth * nHeight]; + + videoStride = nWidth; + + uint8_t* pFrame = (uint8_t*)Xmalloc(nWidth * nHeight); + memset(pFrame, 0, nWidth * nHeight); + walock[kMVETile] = CACHE1D_PERMANENT; + waloff[kMVETile] = (intptr_t)pFrame; + tileSetSize(kMVETile, nHeight, nWidth); + break; + } + + case OPCODE_UNKNOWN_06: + case OPCODE_UNKNOWN_0E: + case OPCODE_UNKNOWN_10: + case OPCODE_UNKNOWN_12: + case OPCODE_UNKNOWN_13: + case OPCODE_UNKNOWN_14: + case OPCODE_UNKNOWN_15: + { + file.Skip(opcodeSize); + break; + } + + case OPCODE_SEND_BUFFER: + { + int nPalStart = file.ReadUint16LE(); + int nPalCount = file.ReadUint16LE(); + + memcpy((char*)waloff[kMVETile], GetCurrentFrame(), nWidth * nHeight); + tileInvalidate(kMVETile, -1, -1); + + nFrame++; + SwapFrames(); + + file.Skip(opcodeSize - 4); + break; + } + + case OPCODE_AUDIO_FRAME: + { + int nStart = file.GetPosition(); + uint16_t seqIndex = file.ReadUint16LE(); + uint16_t streamMask = file.ReadUint16LE(); + uint16_t nSamples = file.ReadUint16LE(); // number of samples this chunk + + int predictor[2]; + int i = 0; + + mutex_lock(&mutex); + + int16_t* pBuf = audio.block[audio.nWrite].buf; + + for (int ch = 0; ch < audio.nChannels; ch++) + { + predictor[ch] = file.ReadUint16LE(); + i++; + + if (predictor[ch] & 0x8000) { + predictor[ch] |= 0xFFFF0000; // sign extend + } + + *pBuf++ = predictor[ch]; + } + + int ch = 0; + for (; i < (nSamples / 2); i++) + { + predictor[ch] += delta_table[file.ReadByte()]; + predictor[ch] = ClipRange(predictor[ch], -32768, 32768); + + *pBuf++ = predictor[ch]; + + // toggle channel + ch ^= audio.nChannels - 1; + } + + audio.block[audio.nWrite].size = nSamples / 2; + audio.nWrite++; + + if (audio.nWrite >= kAudioBlocks) + audio.nWrite = 0; + + int nEnd = file.GetPosition(); + int nRead = nEnd - nStart; + assert(opcodeSize == nRead); + + mutex_unlock(&mutex); + break; + } + + case OPCODE_SILENCE_FRAME: + { + uint16_t seqIndex = file.ReadUint16LE(); + uint16_t streamMask = file.ReadUint16LE(); + uint16_t nStreamLen = file.ReadUint16LE(); + break; + } + + case OPCODE_INIT_VIDEO_MODE: + { + file.Skip(opcodeSize); + break; + } + + case OPCODE_CREATE_GRADIENT: + { + file.Skip(opcodeSize); + initprintf("InterplayDecoder: Create gradient not supported.\n"); + break; + } + + case OPCODE_SET_PALETTE: + { + if (opcodeSize > 0x304 || opcodeSize < 4) { + printf("set_palette opcode with invalid size\n"); + chunkType = CHUNK_BAD; + break; + } + + int nPalStart = file.ReadUint16LE(); + int nPalCount = file.ReadUint16LE(); + + for (int i = nPalStart; i <= nPalCount; i++) + { + palette[i].r = file.ReadByte() << 2; + palette[i].g = file.ReadByte() << 2; + palette[i].b = file.ReadByte() << 2; + } + + paletteSetColorTable(kMVEPal, (uint8_t*)palette); + videoSetPalette(0, kMVEPal, 0); + break; + } + + case OPCODE_SET_PALETTE_COMPRESSED: + { + file.Skip(opcodeSize); + initprintf("InterplayDecoder: Set palette compressed not supported.\n"); + break; + } + + case OPCODE_SET_DECODING_MAP: + { + if (!decodeMap.pData) + { + decodeMap.pData = new uint8_t[opcodeSize]; + decodeMap.nSize = opcodeSize; + } + else + { + if (opcodeSize != decodeMap.nSize) { + delete[] decodeMap.pData; + decodeMap.pData = new uint8_t[opcodeSize]; + decodeMap.nSize = opcodeSize; + } + } + + int nRead = file.ReadBytes(decodeMap.pData, opcodeSize); + assert(nRead == opcodeSize); + break; + } + + case OPCODE_VIDEO_DATA: + { + int nStart = file.GetPosition(); + + // need to skip 14 bytes + file.Skip(14); + + if (decodeMap.nSize) + { + int i = 0; + + for (uint32_t y = 0; y < nHeight; y += 8) + { + for (uint32_t x = 0; x < nWidth; x += 8) + { + uint32_t opcode; + + // alternate between getting low and high 4 bits + if (i & 1) { + opcode = decodeMap.pData[i >> 1] >> 4; + } + else { + opcode = decodeMap.pData[i >> 1] & 0x0F; + } + i++; + + int32_t offset = x + (y * videoStride); + + switch (opcode) + { + default: + break; + case 0: + DecodeBlock0(offset); + break; + case 1: + DecodeBlock1(offset); + break; + case 2: + DecodeBlock2(offset); + break; + case 3: + DecodeBlock3(offset); + break; + case 4: + DecodeBlock4(offset); + break; + case 5: + DecodeBlock5(offset); + break; + case 7: + DecodeBlock7(offset); + break; + case 8: + DecodeBlock8(offset); + break; + case 9: + DecodeBlock9(offset); + break; + case 10: + DecodeBlock10(offset); + break; + case 11: + DecodeBlock11(offset); + break; + case 12: + DecodeBlock12(offset); + break; + case 13: + DecodeBlock13(offset); + break; + case 14: + DecodeBlock14(offset); + break; + case 15: + DecodeBlock15(offset); + break; + } + } + } + } + + int nEnd = file.GetPosition(); + int nSkipBytes = opcodeSize - (nEnd - nStart); // we can end up with 1 byte left we need to skip + assert(nSkipBytes <= 1); + + file.Skip(nSkipBytes); + break; + } + + default: + break; + } + } + + videoClearScreen(0); + + rotatesprite_fs(160 << 16, 100 << 16, nScale, 512, kMVETile, 0, 0, nStat); + videoNextPage(); + } + + renderSetAspect(viewingrange, oyxaspect); + + Close(); + + return true; +} + +void InterplayDecoder::CopyBlock(uint8_t* pDest, uint8_t* pSrc) +{ + for (int y = 0; y < 8; y++) + { + memcpy(pDest, pSrc, 8); + pSrc += (intptr_t)videoStride; + pDest += (intptr_t)videoStride; + } +} + +void InterplayDecoder::DecodeBlock0(int32_t offset) +{ + // copy from the same offset but from the previous frame + uint8_t* pDest = GetCurrentFrame() + (intptr_t)offset; + uint8_t* pSrc = GetPreviousFrame() + (intptr_t)offset; + + CopyBlock(pDest, pSrc); +} + +void InterplayDecoder::DecodeBlock1(int32_t offset) +{ + // nothing to do for this. +} + +void InterplayDecoder::DecodeBlock2(int32_t offset) +{ + // copy block from 2 frames ago using a motion vector; need 1 more byte + uint8_t B = file.ReadByte(); + + int x, y; + + if (B < 56) { + x = 8 + (B % 7); + y = B / 7; + } + else { + x = -14 + ((B - 56) % 29); + y = 8 + ((B - 56) / 29); + } + + uint8_t* pDest = GetCurrentFrame() + (intptr_t)offset; + uint8_t* pSrc = GetCurrentFrame() + (intptr_t)(int64_t)offset + (int64_t)x + (int64_t(y) * (int64_t)videoStride); + + CopyBlock(pDest, pSrc); +} + +void InterplayDecoder::DecodeBlock3(int32_t offset) +{ + // copy 8x8 block from current frame from an up/left block + uint8_t B = file.ReadByte(); + + int x, y; + + // need 1 more byte for motion + if (B < 56) { + x = -(8 + (B % 7)); + y = -(B / 7); + } + else { + x = -(-14 + ((B - 56) % 29)); + y = -(8 + ((B - 56) / 29)); + } + + uint8_t* pDest = GetCurrentFrame() + (intptr_t)offset; + uint8_t* pSrc = GetCurrentFrame() + (intptr_t)(int64_t)offset + (int64_t)x + (int64_t(y) * (int64_t)videoStride); + + CopyBlock(pDest, pSrc); +} + +void InterplayDecoder::DecodeBlock4(int32_t offset) +{ + // copy a block from the previous frame; need 1 more byte + int x, y; + uint8_t B, BL, BH; + + B = file.ReadByte(); + + BL = B & 0x0F; + BH = (B >> 4) & 0x0F; + x = -8 + BL; + y = -8 + BH; + + uint8_t* pDest = GetCurrentFrame() + (intptr_t)offset; + uint8_t* pSrc = GetPreviousFrame() + (intptr_t)(int64_t)offset + (int64_t)x + (int64_t(y) * (int64_t)videoStride); + + CopyBlock(pDest, pSrc); +} + +void InterplayDecoder::DecodeBlock5(int32_t offset) +{ + // copy a block from the previous frame using an expanded range; need 2 more bytes + int8_t x = file.ReadByte(); + int8_t y = file.ReadByte(); + + uint8_t* pDest = GetCurrentFrame() + (intptr_t)offset; + uint8_t* pSrc = GetPreviousFrame() + (intptr_t)(int64_t)offset + (int64_t)x + (int64_t(y) * (int64_t)videoStride); + + CopyBlock(pDest, pSrc); +} + +// Block6 is unknown and skipped + +void InterplayDecoder::DecodeBlock7(int32_t offset) +{ + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint32_t flags = 0; + + uint8_t P[2]; + P[0] = file.ReadByte(); + P[1] = file.ReadByte(); + + // 2-color encoding + if (P[0] <= P[1]) + { + // need 8 more bytes from the stream + for (int y = 0; y < 8; y++) + { + flags = file.ReadByte() | 0x100; + for (; flags != 1; flags >>= 1) { + *pBuffer++ = P[flags & 1]; + } + pBuffer += (videoStride - 8); + } + } + else + { + // need 2 more bytes from the stream + flags = file.ReadUint16LE(); + + for (int y = 0; y < 8; y += 2) + { + for (int x = 0; x < 8; x += 2, flags >>= 1) + { + pBuffer[x] = + pBuffer[x + 1] = + pBuffer[x + videoStride] = + pBuffer[x + 1 + videoStride] = P[flags & 1]; + } + pBuffer += videoStride * 2; + } + } +} + +void InterplayDecoder::DecodeBlock8(int32_t offset) +{ + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint32_t flags = 0; + uint8_t P[4]; + + // 2-color encoding for each 4x4 quadrant, or 2-color encoding on either top and bottom or left and right halves + P[0] = file.ReadByte(); + P[1] = file.ReadByte(); + + if (P[0] <= P[1]) + { + for (int y = 0; y < 16; y++) + { + // new values for each 4x4 block + if (!(y & 3)) + { + if (y) { + P[0] = file.ReadByte(); + P[1] = file.ReadByte(); + } + flags = file.ReadUint16LE(); + } + + for (int x = 0; x < 4; x++, flags >>= 1) { + *pBuffer++ = P[flags & 1]; + } + + pBuffer += videoStride - 4; + // switch to right half + if (y == 7) pBuffer -= 8 * videoStride - 4; + } + } + else + { + flags = file.ReadUint32LE(); + P[2] = file.ReadByte(); + P[3] = file.ReadByte(); + + if (P[2] <= P[3]) + { + // vertical split; left & right halves are 2-color encoded + for (int y = 0; y < 16; y++) + { + for (int x = 0; x < 4; x++, flags >>= 1) { + *pBuffer++ = P[flags & 1]; + } + + pBuffer += videoStride - 4; + + // switch to right half + if (y == 7) { + pBuffer -= 8 * videoStride - 4; + P[0] = P[2]; + P[1] = P[3]; + flags = file.ReadUint32LE(); + } + } + } + else + { + // horizontal split; top & bottom halves are 2-color encoded + for (int y = 0; y < 8; y++) + { + if (y == 4) { + P[0] = P[2]; + P[1] = P[3]; + flags = file.ReadUint32LE(); + } + + for (int x = 0; x < 8; x++, flags >>= 1) + *pBuffer++ = P[flags & 1]; + + pBuffer += (videoStride - 8); + } + } + } +} + +void InterplayDecoder::DecodeBlock9(int32_t offset) +{ + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint8_t P[4]; + + file.ReadBytes(P, 4); + + // 4-color encoding + if (P[0] <= P[1]) + { + if (P[2] <= P[3]) + { + // 1 of 4 colors for each pixel, need 16 more bytes + for (int y = 0; y < 8; y++) + { + // get the next set of 8 2-bit flags + int flags = file.ReadUint16LE(); + + for (int x = 0; x < 8; x++, flags >>= 2) { + *pBuffer++ = P[flags & 0x03]; + } + + pBuffer += (videoStride - 8); + } + } + else + { + // 1 of 4 colors for each 2x2 block, need 4 more bytes + uint32_t flags = file.ReadUint32LE(); + + for (int y = 0; y < 8; y += 2) + { + for (int x = 0; x < 8; x += 2, flags >>= 2) + { + pBuffer[x] = + pBuffer[x + 1] = + pBuffer[x + videoStride] = + pBuffer[x + 1 + videoStride] = P[flags & 0x03]; + } + + pBuffer += videoStride * 2; + } + } + } + else + { + // 1 of 4 colors for each 2x1 or 1x2 block, need 8 more bytes + uint64_t flags = file.ReadUint64LE(); + + if (P[2] <= P[3]) + { + for (int y = 0; y < 8; y++) + { + for (int x = 0; x < 8; x += 2, flags >>= 2) + { + pBuffer[x] = + pBuffer[x + 1] = P[flags & 0x03]; + } + pBuffer += videoStride; + } + } + else + { + for (int y = 0; y < 8; y += 2) + { + for (int x = 0; x < 8; x++, flags >>= 2) + { + pBuffer[x] = + pBuffer[x + videoStride] = P[flags & 0x03]; + } + pBuffer += videoStride * 2; + } + } + } +} + +void InterplayDecoder::DecodeBlock10(int32_t offset) +{ + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint8_t P[8]; + + file.ReadBytes(P, 4); + + // 4-color encoding for each 4x4 quadrant, or 4-color encoding on either top and bottom or left and right halves + if (P[0] <= P[1]) + { + int flags = 0; + + // 4-color encoding for each quadrant; need 32 bytes + for (int y = 0; y < 16; y++) + { + // new values for each 4x4 block + if (!(y & 3)) { + if (y) file.ReadBytes(P, 4); + flags = file.ReadUint32LE(); + } + + for (int x = 0; x < 4; x++, flags >>= 2) { + *pBuffer++ = P[flags & 0x03]; + } + + pBuffer += videoStride - 4; + // switch to right half + if (y == 7) pBuffer -= 8 * videoStride - 4; + } + } + else + { + // vertical split? + int vert; + uint64_t flags = file.ReadUint64LE(); + + file.ReadBytes(P + 4, 4); + vert = P[4] <= P[5]; + + // 4-color encoding for either left and right or top and bottom halves + for (int y = 0; y < 16; y++) + { + for (int x = 0; x < 4; x++, flags >>= 2) + *pBuffer++ = P[flags & 0x03]; + + if (vert) + { + pBuffer += videoStride - 4; + // switch to right half + if (y == 7) pBuffer -= 8 * videoStride - 4; + } + else if (y & 1) pBuffer += (videoStride - 8); + + // load values for second half + if (y == 7) { + memcpy(P, P + 4, 4); + flags = file.ReadUint64LE(); + } + } + } +} + +void InterplayDecoder::DecodeBlock11(int32_t offset) +{ + // 64-color encoding (each pixel in block is a different color) + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + + for (int y = 0; y < 8; y++) + { + file.ReadBytes(pBuffer, 8); + pBuffer += videoStride; + } +} + +void InterplayDecoder::DecodeBlock12(int32_t offset) +{ + // 16-color block encoding: each 2x2 block is a different color + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + + for (int y = 0; y < 8; y += 2) + { + for (int x = 0; x < 8; x += 2) + { + pBuffer[x] = + pBuffer[x + 1] = + pBuffer[x + videoStride] = + pBuffer[x + 1 + videoStride] = file.ReadByte(); + } + pBuffer += videoStride * 2; + } +} + +void InterplayDecoder::DecodeBlock13(int32_t offset) +{ + // 4-color block encoding: each 4x4 block is a different color + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint8_t P[2]; + + for (int y = 0; y < 8; y++) + { + if (!(y & 3)) + { + P[0] = file.ReadByte(); + P[1] = file.ReadByte(); + } + + memset(pBuffer, P[0], 4); + memset(pBuffer + 4, P[1], 4); + pBuffer += videoStride; + } +} + +void InterplayDecoder::DecodeBlock14(int32_t offset) +{ + // 1-color encoding : the whole block is 1 solid color + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint8_t pix = file.ReadByte(); + + for (int y = 0; y < 8; y++) + { + memset(pBuffer, pix, 8); + pBuffer += videoStride; + } +} + +void InterplayDecoder::DecodeBlock15(int32_t offset) +{ + // dithered encoding + uint8_t* pBuffer = GetCurrentFrame() + (intptr_t)offset; + uint8_t P[2]; + + P[0] = file.ReadByte(); + P[1] = file.ReadByte(); + + for (int y = 0; y < 8; y++) + { + for (int x = 0; x < 8; x += 2) + { + *pBuffer++ = P[y & 1]; + *pBuffer++ = P[!(y & 1)]; + } + pBuffer += (videoStride - 8); + } +} + +uint8_t* InterplayDecoder::GetCurrentFrame() +{ + return pVideoBuffers[nCurrentVideoBuffer]; +} + +uint8_t* InterplayDecoder::GetPreviousFrame() +{ + return pVideoBuffers[nPreviousVideoBuffer]; +} diff --git a/source/duke/src/playmve.h b/source/duke/src/playmve.h new file mode 100644 index 000000000..ce2ecbe05 --- /dev/null +++ b/source/duke/src/playmve.h @@ -0,0 +1,100 @@ +/* + * InterplayDecoder + * Copyright (C) 2020 sirlemonhead + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* This code is based on interplayvideo.c, dpcm.c and ipmovie.c from the FFmpeg project which can be obtained + * from http://www.ffmpeg.org/. Below is the license from interplayvideo.c + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +/* + * Interplay MVE Video Decoder + * Copyright (C) 2003 The FFmpeg project + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#pragma once + +#ifndef playmve_h_ +#define playmve_h_ + +#include "baselayer.h" +#include "build.h" +#include "compat.h" +#include "pragmas.h" + +bool playmve(const char* filename); + +#define kMVETile (MAXTILES-1) +#define kMVEPal 5 + +#define CHUNK_PREAMBLE_SIZE 4 +#define OPCODE_PREAMBLE_SIZE 4 + +#define CHUNK_INIT_AUDIO 0x0000 +#define CHUNK_AUDIO_ONLY 0x0001 +#define CHUNK_INIT_VIDEO 0x0002 +#define CHUNK_VIDEO 0x0003 +#define CHUNK_SHUTDOWN 0x0004 +#define CHUNK_END 0x0005 +/* these last types are used internally */ +#define CHUNK_DONE 0xFFFC +#define CHUNK_NOMEM 0xFFFD +#define CHUNK_EOF 0xFFFE +#define CHUNK_BAD 0xFFFF + +#define OPCODE_END_OF_STREAM 0x00 +#define OPCODE_END_OF_CHUNK 0x01 +#define OPCODE_CREATE_TIMER 0x02 +#define OPCODE_INIT_AUDIO_BUFFERS 0x03 +#define OPCODE_START_STOP_AUDIO 0x04 +#define OPCODE_INIT_VIDEO_BUFFERS 0x05 +#define OPCODE_UNKNOWN_06 0x06 +#define OPCODE_SEND_BUFFER 0x07 +#define OPCODE_AUDIO_FRAME 0x08 +#define OPCODE_SILENCE_FRAME 0x09 +#define OPCODE_INIT_VIDEO_MODE 0x0A +#define OPCODE_CREATE_GRADIENT 0x0B +#define OPCODE_SET_PALETTE 0x0C +#define OPCODE_SET_PALETTE_COMPRESSED 0x0D +#define OPCODE_UNKNOWN_0E 0x0E +#define OPCODE_SET_DECODING_MAP 0x0F +#define OPCODE_UNKNOWN_10 0x10 +#define OPCODE_VIDEO_DATA 0x11 +#define OPCODE_UNKNOWN_12 0x12 +#define OPCODE_UNKNOWN_13 0x13 +#define OPCODE_UNKNOWN_14 0x14 +#define OPCODE_UNKNOWN_15 0x15 + +#define PALETTE_COUNT 256 + +#endif diff --git a/source/duke/src/premap.cpp b/source/duke/src/premap.cpp new file mode 100644 index 000000000..8848b69f0 --- /dev/null +++ b/source/duke/src/premap.cpp @@ -0,0 +1,2526 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- +#include "ns.h" // Must come before everything else! + +#include "duke3d.h" +#include "anim.h" +#include "menus.h" +#include "demo.h" +#include "savegame.h" +#include "cmdline.h" +#include "statistics.h" +#include "menu/menu.h" +#include "mapinfo.h" +#include "cmdlib.h" +#include "v_2ddrawer.h" +#include "secrets.h" +#include "glbackend/glbackend.h" + +BEGIN_DUKE_NS + +static int32_t g_whichPalForPlayer = 9; + +static uint8_t precachehightile[2][MAXTILES>>3]; +static int32_t g_precacheCount; +int32_t g_skillSoundVoice = -1; + + +static void flag_precache(int32_t tile, int32_t type) +{ + if (!(gotpic[tile>>3] & pow2char[tile&7])) + g_precacheCount++; + gotpic[tile>>3] |= pow2char[tile&7]; + precachehightile[type][tile>>3] |= pow2char[tile&7]; +} + +static void tloadtile(int32_t tilenume, int32_t type) +{ + int32_t i,j; + + if ((picanm[tilenume].sf&PICANM_ANIMTYPE_MASK)==PICANM_ANIMTYPE_BACK) + { + i = tilenume - picanm[tilenume].num; + j = tilenume; + } + else + { + i = tilenume; + j = tilenume + picanm[tilenume].num; + } + + for (; i<=j; i++) + flag_precache(i, type); +} + +static void G_CacheSpriteNum(int32_t i) +{ + char maxc; + int32_t j; + + if (ud.monsters_off && A_CheckEnemySprite(&sprite[i])) return; + + maxc = 1; + + for (j = PN(i); j <= g_tile[PN(i)].cacherange; j++) + tloadtile(j,1); + + switch (DYNAMICTILEMAP(PN(i))) + { + case HYDRENT__STATIC: + tloadtile(BROKEFIREHYDRENT,1); + for (j = TOILETWATER; j < (TOILETWATER+4); j++) tloadtile(j,1); + break; + case RRTILE2121__STATICRR: + case RRTILE2122__STATICRR: + tloadtile(BROKEFIREHYDRENT, 1); + break; + case TOILET__STATIC: + tloadtile(TOILETBROKE,1); + for (j = TOILETWATER; j < (TOILETWATER+4); j++) tloadtile(j,1); + break; + case STALL__STATIC: + tloadtile(STALLBROKE,1); + for (j = TOILETWATER; j < (TOILETWATER+4); j++) tloadtile(j,1); + break; + case FORCERIPPLE__STATIC: + if (!RR) break; + maxc = 9; + break; + case RUBBERCAN__STATIC: + maxc = 2; + break; + case TOILETWATER__STATIC: + maxc = 4; + break; + case BUBBASTAND__STATICRR: + for (j = BUBBASCRATCH; j < (BUBBASCRATCH+47); j++) tloadtile(j,1); + maxc = 0; + break; + case SBSWIPE__STATICRR: + if (!RRRA) break; + for (j = BUBBASCRATCH; j <= (SBSWIPE+47); j++) tloadtile(j,1); + maxc = 0; + break; + case COOT__STATICRR: + for(j = COOT; j <= (COOT+217); j++) tloadtile(j,1); + for(j = COOTJIBA; j < COOTJIBC+4; j++) tloadtile(j,1); + maxc = 0; + break; + case LTH__STATICRR: + maxc = 105; + for (j = LTH; j < (LTH + maxc); j++) tloadtile(j,1); + maxc = 0; + break; + case BILLYRAY__STATICRR: + maxc = 144; + for (j = BILLYWALK; j < (BILLYWALK + maxc); j++) tloadtile(j,1); + for (j = BILLYJIBA; j <= BILLYJIBB + 4; j++) tloadtile(j,1); + maxc = 0; + break; + case COW__STATICRR: + maxc = 56; + for (j = PN(i); j < (PN(i) + maxc); j++) tloadtile(j,1); + maxc = 0; + break; + case DOGRUN__STATICRR: + for (j = DOGATTACK; j <= DOGATTACK + 35; j++) tloadtile(j,1); + for (j = DOGRUN; j <= DOGRUN + 121; j++) tloadtile(j,1); + maxc = 0; + break; + case RABBIT__STATICRR: + if (!RRRA) break; + for (j = RABBIT; j <= RABBIT + 54; j++) tloadtile(j,1); + for (j = RABBIT + 56; j <= RABBIT + 56 + 49; j++) tloadtile(j,1); + for (j = RABBIT + 56; j <= RABBIT + 56 + 49; j++) tloadtile(j,1); + maxc = 0; + break; + case BIKERB__STATICRR: + case BIKERBV2__STATICRR: + if (!RRRA) break; + for (j = BIKERB; j <= BIKERB + 104; j++) tloadtile(j,1); + maxc = 0; + break; + case BIKER__STATICRR: + if (!RRRA) break; + for (j = BIKER; j <= BIKER + 116; j++) tloadtile(j,1); + for (j = BIKER + 150; j <= BIKER + 150 + 104; j++) tloadtile(j,1); + maxc = 0; + break; + case CHEER__STATICRR: + if (!RRRA) break; + for (j = CHEER; j <= CHEER + 44; j++) tloadtile(j,1); + for (j = CHEER + 47; j <= CHEER + 47 + 211; j++) tloadtile(j,1); + for (j = CHEER + 262; j <= CHEER + 262 + 72; j++) tloadtile(j,1); + maxc = 0; + break; + case CHEERB__STATICRR: + if (!RRRA) break; + for (j = CHEERB; j <= CHEERB + 157 + 83; j++) tloadtile(j,1); + maxc = 0; + break; + case MAMA__STATICRR: + if (!RRRA) break; + for (j = MAMA; j <= MAMA + 78; j++) tloadtile(j,1); + for (j = MAMA + 80; j <= MAMA + 80 + 7; j++) tloadtile(j,1); + for (j = MAMA + 90; j <= MAMA + 90 + 94; j++) tloadtile(j,1); + maxc = 0; + break; + case CHEERBOAT__STATICRR: + if (!RRRA) break; + tloadtile(CHEERBOAT,1); + maxc = 0; + break; + case HULKBOAT__STATICRR: + if (!RRRA) break; + tloadtile(HULKBOAT,1); + maxc = 0; + break; + case MINIONBOAT__STATICRR: + if (!RRRA) break; + tloadtile(MINIONBOAT,1); + maxc = 0; + break; + case BILLYPLAY__STATICRR: + if (!RRRA) break; + for (j = BILLYPLAY; j <= BILLYPLAY + 2; j++) tloadtile(j,1); + maxc = 0; + break; + case COOTPLAY__STATICRR: + if (!RRRA) break; + for (j = COOTPLAY; j <= COOTPLAY + 4; j++) tloadtile(j,1); + maxc = 0; + break; + case PIG__STATICRR: + case PIGSTAYPUT__STATICRR: + maxc = 69; + break; + case TORNADO__STATICRR: + maxc = 7; + break; + case HEN__STATICRR: + case HENSTAND__STATICRR: + maxc = 34; + break; + case FEMPIC1__STATIC: + if (RR) break; + maxc = 44; + break; + case LIZTROOP__STATIC: + case LIZTROOPRUNNING__STATIC: + case LIZTROOPSHOOT__STATIC: + case LIZTROOPJETPACK__STATIC: + case LIZTROOPONTOILET__STATIC: + case LIZTROOPDUCKING__STATIC: + if (RR) break; + for (j = LIZTROOP; j < (LIZTROOP+72); j++) tloadtile(j,1); + for (j=HEADJIB1; j 1)) + { + maxc = 5; + if (RR) + { + for (j = APLAYER; j < APLAYER+220; j++) tloadtile(j,1); + for (j = DUKEGUN; j < DUKELEG+4; j++) tloadtile(j,1); + } + else + for (j = 1420; j < 1420+106; j++) tloadtile(j,1); + } + break; + case ATOMICHEALTH__STATIC: + maxc = 14; + break; + case DRONE__STATIC: + maxc = RR ? 6 : 10; + break; + case EXPLODINGBARREL__STATIC: + case SEENINE__STATIC: + case OOZFILTER__STATIC: + maxc = 3; + break; + case NUKEBARREL__STATIC: + case CAMERA1__STATIC: + maxc = 5; + break; + // caching of HUD sprites for weapons that may be in the level + case CHAINGUNSPRITE__STATIC: + if (RR) break; + for (j=CHAINGUN; j<=CHAINGUN+7; j++) tloadtile(j,1); + break; + case RPGSPRITE__STATIC: + if (RR) break; + for (j=RPGGUN; j<=RPGGUN+2; j++) tloadtile(j,1); + break; + case FREEZESPRITE__STATIC: + if (RR) break; + for (j=FREEZE; j<=FREEZE+5; j++) tloadtile(j,1); + break; + case GROWSPRITEICON__STATIC: + case SHRINKERSPRITE__STATIC: + if (RR) break; + for (j=SHRINKER-2; j<=SHRINKER+5; j++) tloadtile(j,1); + break; + case HBOMBAMMO__STATIC: + case HEAVYHBOMB__STATIC: + if (RR) break; + for (j=HANDREMOTE; j<=HANDREMOTE+5; j++) tloadtile(j,1); + break; + case TRIPBOMBSPRITE__STATIC: + if (RR) break; + for (j=HANDHOLDINGLASER; j<=HANDHOLDINGLASER+4; j++) tloadtile(j,1); + break; + case SHOTGUNSPRITE__STATIC: + if (RR) break; + tloadtile(SHOTGUNSHELL,1); + for (j=SHOTGUN; j<=SHOTGUN+6; j++) tloadtile(j,1); + break; + case DEVISTATORSPRITE__STATIC: + if (RR) break; + for (j=DEVISTATOR; j<=DEVISTATOR+1; j++) tloadtile(j,1); + break; + case VIXEN__STATICRR: + maxc = 214; + for (j = PN(i); j < PN(i) + maxc; j++) tloadtile(j,1); + maxc = 0; + break; + case SBMOVE__STATICRR: + if (RRRA) break; + maxc = 54; + for (j = PN(i); j < PN(i) + maxc; j++) tloadtile(j,1); + maxc = 100; + for (j = SBMOVE; j < SBMOVE + maxc; j++) tloadtile(j,1); + maxc = 0; + break; + case HULK__STATICRR: + maxc = 40; + for (j = PN(i) - 41; j < PN(i) + maxc - 41; j++) tloadtile(j,1); + for (j = HULKJIBA; j <= HULKJIBC + 4; j++) tloadtile(j,1); + maxc = 0; + break; + case MINION__STATICRR: + maxc = 141; + for (j = PN(i); j < PN(i) + maxc; j++) tloadtile(j,1); + for (j = MINJIBA; j <= MINJIBC + 4; j++) tloadtile(j,1); + maxc = 0; + break; + + } + + for (j = PN(i); j < (PN(i)+maxc); j++) tloadtile(j,1); +} + +static void G_PrecacheSprites(void) +{ + int32_t i; + + //for (i=0; i 1)) + tloadtile(FRAGBAR,1); + + tloadtile(VIEWSCREEN,1); + + for (i=STARTALPHANUM; ipalette = palette; + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + + if (!statustext) + { + i = ud.screen_size; + ud.screen_size = 0; + G_UpdateScreenArea(); + videoClearScreen(0L); + } + + videoClearScreen(0); + + int const loadScreenTile = VM_OnEventWithReturn(EVENT_GETLOADTILE, g_player[screenpeek].ps->i, screenpeek, DEER ? 7040 : LOADSCREEN); + + rotatesprite_fs(320<<15,200<<15,65536L,0,loadScreenTile,0,0,2+8+64+BGSTRETCH); + + int const textY = RRRA ? 140 : 90; + + if (boardfilename[0] != 0 && ud.level_number == 7 && ud.volume_number == 0) + { + menutext_center(textY, RR ? GStrings("TXT_ENTRUM") : GStrings("TXT_LOADUM")); + if (RR) + menutext_center(textY+20, boardfilename); + else + gametext_center_shade_pal(textY+10, boardfilename, 14, 2); + } + else if (RR && g_lastLevel) + { + menutext_center(textY,GStrings("TXT_ENTERIN")); + menutext_center(textY+16+8,GStrings("TXT_CLOSEENCOUNTERS")); + } + else + { + menutext_center(textY, RR ? GStrings("TXT_ENTERIN") : GStrings("TXT_LOADING")); + menutext_center(textY+16+8,mapList[(ud.volume_number*MAXLEVELS) + ud.level_number].DisplayName()); + } + +#ifndef EDUKE32_TOUCH_DEVICES + if (statustext) gametext_center_number(180, statustext); +#endif + + if (percent != -1) + { + int32_t ii = scale(scale(xdim-1,288,320),percent,100); + rotatesprite(31<<16,145<<16,65536,0,929,15,0,2+8+16,0,0,ii,ydim-1); + rotatesprite(159<<16,145<<16,65536,0,929,15,0,2+8+16,0,0,ii,ydim-1); + rotatesprite(30<<16,144<<16,65536,0,929,0,0,2+8+16,0,0,ii,ydim-1); + rotatesprite(158<<16,144<<16,65536,0,929,0,0,2+8+16,0,0,ii,ydim-1); + } + + videoNextPage(); + + if (!statustext) + { + inputState.keyFlushChars(); + ud.screen_size = i; + } + } + else + { + if (!statustext) + { + videoClearScreen(0L); + //g_player[myconnectindex].ps->palette = palette; + //G_FadePalette(0,0,0,0); + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + } + /*Gv_SetVar(g_iReturnVarID,LOADSCREEN, -1, -1);*/ + + rotatesprite_fs(320<<15,200<<15,65536L, 0,LOADSCREEN,0,0,2+8+64+BGSTRETCH); + + menutext_center(RRRA?155:105,RR? GStrings("TXT_LOADIN") : GStrings("TXT_Loading...")); + if (statustext) gametext_center_number(180, statustext); + videoNextPage(); + } +} + + + + +void G_CacheMapData(void) +{ + int32_t i,j,pc=0; + int32_t tc; + uint32_t starttime, endtime; + + if (ud.recstat == 2) + return; + + S_TryPlaySpecialMusic(MUS_LOADING); + + starttime = timerGetTicks(); + + cacheAllSounds(); + G_PrecacheSprites(); + + for (i=0; i= 0) + { + tloadtile(wall[i].overpicnum, 0); + } + } + + for (i=0; i>3]) + { + i+=7; + continue; + } + if (gotpic[i>>3] & pow2char[i&7]) + { + // For the hardware renderer precaching the raw pixel data is pointless. + if (videoGetRenderMode() < REND_POLYMOST) + tileLoad(i); + +#ifdef USE_OPENGL + if (r_precache) PrecacheHardwareTextures(i); +#endif + j++; + pc++; + } + else continue; + + if ((j&7) == 0) + G_HandleAsync(); + +#if 0 + if (bpp > 8 && totalclock - tc > TICRATE/4) + { + /*Bsprintf(tempbuf,"%d resources remaining\n",g_precacheCount-pc+1);*/ + int percentage = min(100, tabledivide32_noinline(100 * pc, g_precacheCount)); + + while (percentage > lpc) + { + G_HandleAsync(); + Bsprintf(tempbuf, "Loaded %d%% (%d/%d textures)\n", lpc, pc, g_precacheCount); + G_DoLoadScreen(tempbuf, lpc); + + if (totalclock - tc >= 1) + { + tc = (int32_t) totalclock; + lpc++; + } + +// Printf("percentage %d lpc %d\n", percentage, lpc); + } + + tc = (int32_t) totalclock; + } +#endif + } + + Bmemset(gotpic, 0, sizeof(gotpic)); + + endtime = timerGetTicks(); + Printf("Cache time: %dms\n", endtime-starttime); +} + +extern int32_t fragbarheight(void) +{ + if (ud.screen_size > 0 && !(ud.statusbarflags & STATUSBAR_NOFRAGBAR) +#ifdef SPLITSCREEN_MOD_HACKS + && !g_fakeMultiMode +#endif + && (g_netServer || ud.multimode > 1) && GTFLAGS(GAMETYPE_FRAGBAR)) + { + int32_t i, j = 0; + + for (TRAVERSE_CONNECT(i)) + if (i > j) + j = i; + + return ((j + 3) >> 2) << 3; + } + + return 0; +} + +void G_UpdateScreenArea(void) +{ + if (!in3dmode()) + return; + + ud.screen_size = clamp(ud.screen_size, 0, 64); + if (ud.screen_size == 0) + renderFlushPerms(); + + { + const int32_t ss = max(ud.screen_size-8,0); + + int32_t x1 = scale(ss,xdim,160); + int32_t x2 = xdim-x1; + + int32_t y1 = scale(ss,(200 * 100) - ((tilesiz[BOTTOMSTATUSBAR].y >> (RR ? 1 : 0)) * ud.statusbarscale),200 - tilesiz[BOTTOMSTATUSBAR].y); + int32_t y2 = 200*100-y1; + + if (RR && ud.screen_size <= 12) + { + x1 = 0; + x2 = xdim; + y1 = 0; + if (ud.statusbarmode) + y2 = 200*100; + } + + y1 += fragbarheight()*100; + if (ud.screen_size >= 8 && ud.statusbarmode==0) + y2 -= (tilesiz[BOTTOMSTATUSBAR].y >> (RR ? 1 : 0))*ud.statusbarscale; + y1 = scale(y1,ydim,200*100); + y2 = scale(y2,ydim,200*100); + + videoSetViewableArea(x1,y1,x2-1,y2-1); + } + + pub = NUMPAGES; + pus = NUMPAGES; +} + +void P_RandomSpawnPoint(int playerNum) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + int32_t i = playerNum; + + if ((g_netServer || ud.multimode > 1) && !(g_gametypeFlags[ud.coop] & GAMETYPE_FIXEDRESPAWN)) + { + i = krand2() % g_playerSpawnCnt; + + if (g_gametypeFlags[ud.coop] & GAMETYPE_TDMSPAWN) + { + uint32_t pdist = -1; + for (bssize_t j=0; jteam == pPlayer->team && sprite[g_player[j].ps->i].extra > 0) + { + for (bssize_t k=0; kpos.x - g_playerSpawnPoints[k].pos.x, + g_player[j].ps->pos.y - g_playerSpawnPoints[k].pos.y); + + if (dist < pdist) + i = k, pdist = dist; + } + break; + } + } + } + } + + pPlayer->pos = g_playerSpawnPoints[i].pos; + pPlayer->opos = pPlayer->pos; + pPlayer->bobpos = *(vec2_t *)&pPlayer->pos; + pPlayer->q16ang = fix16_from_int(g_playerSpawnPoints[i].ang); + pPlayer->cursectnum = g_playerSpawnPoints[i].sect; + + sprite[pPlayer->i].cstat = 1 + 256; +} + +static inline void P_ResetTintFade(DukePlayer_t *const pPlayer) +{ + pPlayer->pals.f = 0; +} + +void P_ResetPlayer(int playerNum) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + spritetype *const pSprite = &sprite[pPlayer->i]; + vec3_t tmpvect = pPlayer->pos; + + tmpvect.z += PHEIGHT; + + P_RandomSpawnPoint(playerNum); + + pPlayer->opos = pPlayer->pos; + pPlayer->bobpos = *(vec2_t *)&pPlayer->pos; + actor[pPlayer->i].bpos = pPlayer->pos; + *(vec3_t *)pSprite = pPlayer->pos; + + updatesector(pPlayer->pos.x, pPlayer->pos.y, &pPlayer->cursectnum); + setsprite(pPlayer->i, &tmpvect); + + pSprite->cstat = 257; + pSprite->shade = -12; + pSprite->clipdist = RR ? 32 : 64; + pSprite->xrepeat = RR ? 24 : 42; + pSprite->yrepeat = RR ? 17 : 36; + pSprite->owner = pPlayer->i; + pSprite->xoffset = 0; + pSprite->pal = pPlayer->palookup; + + pPlayer->last_extra = pSprite->extra = pPlayer->max_player_health; + + pPlayer->wantweaponfire = -1; + pPlayer->q16horiz = F16(100); + pPlayer->on_crane = -1; + pPlayer->frag_ps = playerNum; + pPlayer->q16horizoff = 0; + pPlayer->opyoff = 0; + pPlayer->wackedbyactor = -1; + pPlayer->inv_amount[GET_SHIELD] = g_startArmorAmount; + pPlayer->dead_flag = 0; + pPlayer->footprintcount = 0; + pPlayer->weapreccnt = 0; + pPlayer->fta = 0; + pPlayer->ftq = 0; + pPlayer->vel.x = pPlayer->vel.y = 0; + if (!RR) pPlayer->q16rotscrnang = 0; + pPlayer->runspeed = g_playerFriction; + pPlayer->falling_counter = 0; + + P_ResetTintFade(pPlayer); + + actor[pPlayer->i].extra = -1; + actor[pPlayer->i].owner = pPlayer->i; + actor[pPlayer->i].cgg = 0; + actor[pPlayer->i].movflag = 0; + actor[pPlayer->i].tempang = 0; + actor[pPlayer->i].actorstayput = -1; + actor[pPlayer->i].dispicnum = 0; + actor[pPlayer->i].owner = pPlayer->i; + actor[pPlayer->i].t_data[4] = 0; + + P_ResetInventory(playerNum); + P_ResetWeapons(playerNum); + + //pPlayer->reloading = 0; + pPlayer->movement_lock = 0; +} + +void P_ResetStatus(int playerNum) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + gFullMap = 0; + pPlayer->dead_flag = 0; + pPlayer->wackedbyactor = -1; + pPlayer->falling_counter = 0; + pPlayer->quick_kick = 0; + pPlayer->subweapon = 0; + pPlayer->last_full_weapon = 0; + pPlayer->ftq = 0; + pPlayer->fta = 0; + pPlayer->tipincs = 0; + pPlayer->buttonpalette = 0; + pPlayer->actorsqu = -1; + pPlayer->invdisptime = 0; + pPlayer->refresh_inventory = 0; + pPlayer->last_pissed_time = 0; + pPlayer->holster_weapon = 0; + pPlayer->pycount = 0; + pPlayer->pyoff = 0; + pPlayer->opyoff = 0; + pPlayer->loogcnt = 0; + pPlayer->q16angvel = 0; + pPlayer->weapon_sway = 0; + pPlayer->extra_extra8 = 0; + pPlayer->show_empty_weapon = 0; + pPlayer->dummyplayersprite = -1; + pPlayer->crack_time = 0; + pPlayer->hbomb_hold_delay = 0; + pPlayer->transporter_hold = 0; + //pPlayer->clipdist = 164; + pPlayer->wantweaponfire = -1; + pPlayer->hurt_delay = 0; + if (RRRA) + pPlayer->hurt_delay2 = 0; + pPlayer->footprintcount = 0; + pPlayer->footprintpal = 0; + pPlayer->footprintshade = 0; + pPlayer->jumping_toggle = 0; + pPlayer->oq16horiz = F16(140); + pPlayer->q16horiz = F16(140); + pPlayer->q16horizoff = 0; + pPlayer->bobcounter = 0; + pPlayer->on_ground = 0; + pPlayer->player_par = 0; + pPlayer->return_to_center = 9; + pPlayer->airleft = 15 * GAMETICSPERSEC; + pPlayer->rapid_fire_hold = 0; + pPlayer->toggle_key_flag = 0; + pPlayer->access_spritenum = -1; + pPlayer->got_access = ((g_netServer || ud.multimode > 1) && (g_gametypeFlags[ud.coop] & GAMETYPE_ACCESSATSTART)) ? 7 : 0; + pPlayer->random_club_frame = 0; + pus = 1; + pPlayer->on_warping_sector = 0; + pPlayer->spritebridge = 0; + //pPlayer->sbs = 0; + pPlayer->palette = BASEPAL; + + if (pPlayer->inv_amount[GET_STEROIDS] < 400) + { + pPlayer->inv_amount[GET_STEROIDS] = 0; + pPlayer->inven_icon = ICON_NONE; + } + + pPlayer->heat_on = 0; + pPlayer->jetpack_on = 0; + pPlayer->holoduke_on = -1; + pPlayer->q16look_ang = fix16_from_int(512 - ((ud.level_number & 1) << 10)); + pPlayer->q16rotscrnang = 0; + pPlayer->oq16rotscrnang = fix16_one; // JBF 20031220 + pPlayer->newowner = -1; + pPlayer->jumping_counter = 0; + pPlayer->hard_landing = 0; + pPlayer->vel.x = 0; + pPlayer->vel.y = 0; + pPlayer->vel.z = 0; + pPlayer->fric.x = 0; + pPlayer->fric.y = 0; + pPlayer->somethingonplayer = -1; + pPlayer->one_eighty_count = 0; + pPlayer->cheat_phase = 0; + pPlayer->on_crane = -1; + + pPlayer->kickback_pic = (pPlayer->curr_weapon == PISTOL_WEAPON) ? (RR ? 22 : 5) : 0; + + pPlayer->weapon_pos = WEAPON_POS_START; + pPlayer->walking_snd_toggle = 0; + pPlayer->weapon_ang = 0; + pPlayer->knuckle_incs = 1; + pPlayer->fist_incs = 0; + pPlayer->knee_incs = 0; + //pPlayer->reloading = 0; + pPlayer->movement_lock = 0; + pPlayer->frag_ps = playerNum; + + g_player[playerNum].horizRecenter = 0; + g_player[playerNum].horizSkew = 0; + g_player[playerNum].horizAngleAdjust = 0; + + P_UpdateScreenPal(pPlayer); + + if (RR) + { + pPlayer->stairs = 0; + pPlayer->noise_x = 0; + pPlayer->noise_y = 0; + pPlayer->make_noise = 0; + pPlayer->noise_radius = 0; + if ((g_netServer || ud.multimode > 1) && (g_gametypeFlags[ud.coop] & GAMETYPE_ACCESSATSTART)) + { + pPlayer->keys[0] = 1; + pPlayer->keys[1] = 1; + pPlayer->keys[2] = 1; + pPlayer->keys[3] = 1; + pPlayer->keys[4] = 1; + } + else + { + pPlayer->keys[0] = 0; + pPlayer->keys[1] = 0; + pPlayer->keys[2] = 0; + pPlayer->keys[3] = 0; + pPlayer->keys[4] = 0; + } + + g_wupass = 0; + pPlayer->drink_ang = pPlayer->eat_ang = 1647; + pPlayer->drink_amt = pPlayer->eat_amt = 0; + pPlayer->drink_timer = pPlayer->eat_timer = 4096; + pPlayer->shotgun_state[0] = pPlayer->shotgun_state[1] = 0; + pPlayer->hbomb_time = 0; + pPlayer->hbomb_offset = 0; + pPlayer->recoil = 0; + pPlayer->yehaa_timer = 0; + if (RRRA) + { + g_chickenWeaponTimer = 0; + if (pPlayer->on_motorcycle) + { + pPlayer->on_motorcycle = 0; + pPlayer->gotweapon &= ~(1 << MOTORCYCLE_WEAPON); + pPlayer->curr_weapon = SLINGBLADE_WEAPON; + } + pPlayer->lotag800kill = 0; + pPlayer->moto_do_bump = 0; + pPlayer->moto_on_ground = 1; + pPlayer->moto_underwater = 0; + pPlayer->moto_speed = 0; + pPlayer->tilt_status = 0; + pPlayer->moto_drink = 0; + pPlayer->moto_bump_target = 0; + pPlayer->moto_bump = 0; + pPlayer->moto_bump_fast = 0; + pPlayer->moto_turb = 0; + pPlayer->moto_on_mud = 0; + pPlayer->moto_on_oil = 0; + if (pPlayer->on_boat) + { + pPlayer->on_boat = 0; + pPlayer->gotweapon &= ~(1 << BOAT_WEAPON); + pPlayer->curr_weapon = SLINGBLADE_WEAPON; + } + pPlayer->not_on_water = 0; + pPlayer->sea_sick = 0; + pPlayer->nocheat = 0; + pPlayer->drug_mode = 0; + pPlayer->drug_stat[0] = 0; + pPlayer->drug_stat[1] = 0; + pPlayer->drug_stat[2] = 0; + pPlayer->drug_aspect = 0; + } + A_ResetLanePics(); + if (!g_netServer && numplayers < 2) + { + g_ufoSpawn = min(RRRA ? 3 : (ud.m_player_skill*4+1), 32); + g_ufoCnt = 0; + g_hulkSpawn = ud.m_player_skill + 1; + } + else + { + g_ufoSpawn = 32; + g_ufoCnt = 0; + g_hulkSpawn = 2; + } + } +} + +void P_ResetWeapons(int playerNum) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + for (bssize_t weaponNum = PISTOL_WEAPON; weaponNum < MAX_WEAPONS; weaponNum++) + pPlayer->ammo_amount[weaponNum] = 0; + + pPlayer->weapon_pos = WEAPON_POS_START; + pPlayer->curr_weapon = PISTOL_WEAPON; + pPlayer->kickback_pic = 5; + pPlayer->gotweapon = ((1 << PISTOL_WEAPON) | (1 << KNEE_WEAPON) | (1 << HANDREMOTE_WEAPON)); + pPlayer->ammo_amount[PISTOL_WEAPON] = min(pPlayer->max_ammo_amount[PISTOL_WEAPON], 48); + if (RRRA) + { + g_chickenWeaponTimer = 0; + pPlayer->gotweapon |= (1 << SLINGBLADE_WEAPON); + pPlayer->ammo_amount[KNEE_WEAPON] = 1; + pPlayer->ammo_amount[SLINGBLADE_WEAPON] = 1; + pPlayer->on_motorcycle = 0; + pPlayer->moto_underwater = 0; + pPlayer->on_boat = 0; + pPlayer->lotag800kill = 0; + } + pPlayer->last_weapon = -1; + pPlayer->show_empty_weapon = 0; + pPlayer->last_pissed_time = 0; + pPlayer->holster_weapon = 0; + pPlayer->last_used_weapon = -1; + + VM_OnEvent(EVENT_RESETWEAPONS, pPlayer->i, playerNum); +} + +void P_ResetInventory(int playerNum) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + Bmemset(pPlayer->inv_amount, 0, sizeof(pPlayer->inv_amount)); + + pPlayer->scuba_on = 0; + pPlayer->heat_on = 0; + pPlayer->jetpack_on = 0; + pPlayer->holoduke_on = -1; + pPlayer->inven_icon = ICON_NONE; + pPlayer->inv_amount[GET_SHIELD] = g_startArmorAmount; + + if (RR) + { + if ((g_netServer || ud.multimode > 1) && (g_gametypeFlags[ud.coop] & GAMETYPE_ACCESSATSTART)) + { + pPlayer->keys[0] = 1; + pPlayer->keys[1] = 1; + pPlayer->keys[2] = 1; + pPlayer->keys[3] = 1; + pPlayer->keys[4] = 1; + } + else + { + pPlayer->keys[0] = 0; + pPlayer->keys[1] = 0; + pPlayer->keys[2] = 0; + pPlayer->keys[3] = 0; + pPlayer->keys[4] = 0; + } + + pPlayer->drink_ang = pPlayer->eat_ang = 1647; + pPlayer->drink_amt = pPlayer->eat_amt = 0; + pPlayer->drink_timer = pPlayer->eat_timer = 4096; + pPlayer->shotgun_state[0] = pPlayer->shotgun_state[1] = 0; + pPlayer->hbomb_time = 0; + pPlayer->hbomb_offset = 0; + pPlayer->recoil = 0; + pPlayer->yehaa_timer = 0; + A_ResetLanePics(); + if (!g_netServer && numplayers < 2) + { + g_ufoSpawn = min(ud.m_player_skill*4+1, 32); + g_ufoCnt = 0; + g_hulkSpawn = ud.m_player_skill + 1; + } + else + { + g_ufoSpawn = 32; + g_ufoCnt = 0; + g_hulkSpawn = 2; + } + } + + VM_OnEvent(EVENT_RESETINVENTORY, pPlayer->i, playerNum); +} + +static void resetprestat(int playerNum, int gameMode) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + g_spriteDeleteQueuePos = 0; + for (bssize_t i = 0; i < g_deleteQueueSize; i++) SpriteDeletionQueue[i] = -1; + + pPlayer->hbomb_on = 0; + pPlayer->cheat_phase = 0; + pPlayer->toggle_key_flag = 0; + pPlayer->secret_rooms = 0; + pPlayer->max_secret_rooms = 0; + pPlayer->actors_killed = 0; + pPlayer->max_actors_killed = 0; + pPlayer->lastrandomspot = 0; + pPlayer->weapon_pos = WEAPON_POS_START; + + P_ResetTintFade(pPlayer); + + pPlayer->kickback_pic = 5; + + pPlayer->last_weapon = -1; + pPlayer->weapreccnt = 0; + pPlayer->interface_toggle_flag = 0; + pPlayer->show_empty_weapon = 0; + pPlayer->holster_weapon = 0; + pPlayer->last_pissed_time = 0; + pPlayer->one_parallax_sectnum = -1; + pPlayer->visibility = ud.const_visibility; + + screenpeek = myconnectindex; + g_animWallCnt = 0; + g_cyclerCnt = 0; + g_animateCnt = 0; + parallaxtype = 0; + randomseed = 17; + paused = 0; + ud.camerasprite = -1; + ud.eog = 0; + tempwallptr = 0; + g_curViewscreen = -1; + g_earthquakeTime = 0; + g_interpolationCnt = 0; + + if (RRRA) + { + g_windTime = 0; + g_windDir = 0; + g_fakeBubbaCnt = 0; + g_RAendLevel = 0; + g_bellTime = 0; + g_bellSprite = 0; + } + + if (((gameMode & MODE_EOL) != MODE_EOL && numplayers < 2 && !g_netServer) + || (!(g_gametypeFlags[ud.coop] & GAMETYPE_PRESERVEINVENTORYDEATH) && numplayers > 1)) + { + P_ResetWeapons(playerNum); + P_ResetInventory(playerNum); + } + else if (pPlayer->curr_weapon == HANDREMOTE_WEAPON) + { + pPlayer->ammo_amount[HANDBOMB_WEAPON]++; + pPlayer->curr_weapon = HANDBOMB_WEAPON; + } + + pPlayer->timebeforeexit = 0; + pPlayer->customexitsound = 0; + + if (RR) + { + pPlayer->stairs = 0; + pPlayer->noise_x = 131072; + pPlayer->noise_y = 131072; + pPlayer->make_noise = 0; + pPlayer->noise_radius = 0; + if ((g_netServer || ud.multimode > 1) && (g_gametypeFlags[ud.coop] & GAMETYPE_ACCESSATSTART)) + { + pPlayer->keys[0] = 1; + pPlayer->keys[1] = 1; + pPlayer->keys[2] = 1; + pPlayer->keys[3] = 1; + pPlayer->keys[4] = 1; + } + else + { + pPlayer->keys[0] = 0; + pPlayer->keys[1] = 0; + pPlayer->keys[2] = 0; + pPlayer->keys[3] = 0; + pPlayer->keys[4] = 0; + } + + pPlayer->drink_ang = pPlayer->eat_ang = 1647; + pPlayer->drink_amt = pPlayer->eat_amt = 0; + pPlayer->drink_timer = pPlayer->eat_timer = 4096; + pPlayer->shotgun_state[0] = pPlayer->shotgun_state[1] = 0; + pPlayer->hbomb_time = 0; + pPlayer->hbomb_offset = 0; + pPlayer->recoil = 0; + pPlayer->yehaa_timer = 0; + A_ResetLanePics(); + if (!g_netServer && numplayers < 2) + { + g_ufoSpawn = min(ud.m_player_skill*4+1, 32); + g_ufoCnt = 0; + g_hulkSpawn = ud.m_player_skill + 1; + } + else + { + g_ufoSpawn = 32; + g_ufoCnt = 0; + g_hulkSpawn = 2; + } + } +} + +static inline int G_CheckExitSprite(int spriteNum) { return ((uint16_t)sprite[spriteNum].lotag == UINT16_MAX && (sprite[spriteNum].cstat & 16)); } + +void G_InitRRRASkies(void) +{ + if (!RRRA) + return; + + for (bssize_t i = 0; i < MAXSECTORS; i++) + { + if (sector[i].ceilingpicnum != LA && sector[i].ceilingpicnum != MOONSKY1 && sector[i].ceilingpicnum != BIGORBIT1) + { + int const picnum = sector[i].ceilingpicnum; + if (tileWidth(picnum) == 512) + { + psky_t *sky = tileSetupSky(picnum); + sky->horizfrac = 32768; + sky->lognumtiles = 1; + sky->tileofs[0] = 0; + sky->tileofs[1] = 0; + } + else if (tileWidth(picnum) == 1024) + { + psky_t *sky = tileSetupSky(picnum); + sky->horizfrac = 32768; + sky->lognumtiles = 0; + sky->tileofs[0] = 0; + } + } + } +} + +static void prelevel(char g) +{ + uint8_t *tagbitmap = (uint8_t *)Xcalloc(65536>>3, 1); + int32_t p1 = 0, p2 = 0, p3 = 0; + //DukePlayer_t *ps = g_player[screenpeek].ps; + + if (RRRA) + { + G_SetFog(0); + g_fogType = 0; + g_ufoSpawnMinion = 0; + g_pistonSound = 0; + g_slotWin = 0; + g_changeEnemySize = 0; + g_player[myconnectindex].ps->level_end_timer = 0; + g_mamaSpawnCnt = 15; + g_banjoSong = 0; + g_RAendLevel = 0; + if (!DEER) + { + for (bssize_t TRAVERSE_CONNECT(playerNum)) + { + DukePlayer_t *ps = g_player[playerNum].ps; + ps->sea_sick_stat = 0; + if (ud.level_number == 4 && ud.volume_number == 1) + ps->inv_amount[GET_STEROIDS] = 0; + } + if (ud.level_number == 3 && ud.volume_number == 0) + g_mamaSpawnCnt = 5; + else if (ud.level_number == 2 && ud.volume_number == 1) + g_mamaSpawnCnt = 10; + else if (ud.level_number == 6 && ud.volume_number == 1) + g_mamaSpawnCnt = 15; + } + } + + Bmemset(g_spriteExtra, 0, sizeof(g_spriteExtra)); + Bmemset(g_sectorExtra, 0, sizeof(g_sectorExtra)); + Bmemset(g_shadedSector, 0, sizeof(g_shadedSector)); + Bmemset(g_geoSectorWarp, -1, sizeof(g_geoSectorWarp)); + Bmemset(g_geoSectorWarp2, -1, sizeof(g_geoSectorWarp2)); + Bmemset(g_ambientHitag, -1, sizeof(g_ambientHitag)); + Bmemset(g_ambientLotag, -1, sizeof(g_ambientLotag)); + show2dsector.Zero(); +#ifdef LEGACY_ROR + Bmemset(ror_protectedsectors, 0, MAXSECTORS); +#endif + resetprestat(0,g); + if (RR) + { + g_lightninCnt = 0; + g_torchCnt = 0; + g_geoSectorCnt = 0; + g_jailDoorCnt = 0; + g_mineCartCnt = 0; + g_ambientCnt = 0; + g_thunderOn = 0; + g_chickenPlant = 0; + if (RRRA) + { + g_windTime = 0; + g_windDir = 0; + g_fakeBubbaCnt = 0; + g_RAendLevel = 0; + g_mamaSpawnCnt = 15; // ??? + g_bellTime = 0; + g_bellSprite = 0; + + for (bssize_t spriteNum = 0; spriteNum < MAXSPRITES; spriteNum++) + { + if (sprite[spriteNum].pal == 100) + { + if (g_netServer || numplayers > 1) + A_DeleteSprite(spriteNum); + else + sprite[spriteNum].pal = 0; + } + else if (sprite[spriteNum].pal == 101) + { + sprite[spriteNum].extra = 0; + sprite[spriteNum].hitag = 1; + sprite[spriteNum].pal = 0; + changespritestat(spriteNum, 118); + } + } + } + } + g_cloudCnt = 0; + + int missedCloudSectors = 0; + + if (!DEER) + for (bssize_t i=0; i= 32) + G_GameExit("\nToo many jaildoor sectors"); + g_jailDoorDist[g_jailDoorCnt] = p1; + g_jailDoorSpeed[g_jailDoorCnt] = p2; + g_jailDoorSecHitag[g_jailDoorCnt] = sector[i].hitag; + g_jailDoorSect[g_jailDoorCnt] = j; + g_jailDoorDrag[g_jailDoorCnt] = 0; + g_jailDoorOpen[g_jailDoorCnt] = 0; + g_jailDoorDir[g_jailDoorCnt] = sector[j].lotag; + g_jailDoorSound[g_jailDoorCnt] = p3; + g_jailDoorCnt++; + } + } + break; + } + case 42: + { + if (!RR) break; + int k = headspritesect[i]; + while (k != -1) + { + int const nexti = nextspritesect[k]; + if (sprite[k].picnum == RRTILE64) + { + p1 = sprite[k].lotag << 4; + p2 = sprite[k].hitag; + for (bssize_t kk = 0; kk < MAXSPRITES; kk++) + { + if (sprite[kk].picnum == RRTILE66) + if (sprite[kk].lotag == sprite[k].sectnum) + { + g_mineCartChildSect[g_mineCartCnt] = sprite[kk].sectnum; + A_DeleteSprite(kk); + } + } + A_DeleteSprite(k); + } + if (sprite[k].picnum == RRTILE65) + { + p3 = sprite[k].lotag; + A_DeleteSprite(k); + } + k = nexti; + } + if (g_mineCartCnt >= 16) + G_GameExit("\nToo many minecart sectors"); + g_mineCartDist[g_mineCartCnt] = p1; + g_mineCartSpeed[g_mineCartCnt] = p2; + g_mineCartSect[g_mineCartCnt] = i; + g_mineCartDir[g_mineCartCnt] = sector[i].hitag; + g_mineCartDrag[g_mineCartCnt] = p1; + g_mineCartOpen[g_mineCartCnt] = 1; + g_mineCartSound[g_mineCartCnt] = p3; + g_mineCartCnt++; + break; + } + case ST_20_CEILING_DOOR: + case ST_22_SPLITTING_DOOR: + if (sector[i].floorz > sector[i].ceilingz) + sector[i].lotag |= 32768u; + continue; + } + + if (sector[i].ceilingstat&1) + { + if (tilePtr(sector[i].ceilingpicnum) == nullptr) + { + if (sector[i].ceilingpicnum == LA) + for (bsize_t j = 0; j < 5; j++) + tloadtile(sector[i].ceilingpicnum + j, 0); + } + + if (!RR && sector[i].ceilingpicnum == CLOUDYSKIES) + { + if (g_cloudCnt < ARRAY_SSIZE(g_cloudSect)) + g_cloudSect[g_cloudCnt++] = i; + else + missedCloudSectors++; + } + + if (g_player[0].ps->one_parallax_sectnum == -1) + g_player[0].ps->one_parallax_sectnum = i; + } + + if (sector[i].lotag == 32767) //Found a secret room + { + g_player[0].ps->max_secret_rooms++; + continue; + } + + if ((uint16_t)sector[i].lotag == UINT16_MAX) + { + g_player[0].ps->exitx = wall[sector[i].wallptr].x; + g_player[0].ps->exity = wall[sector[i].wallptr].y; + continue; + } + } + + if (missedCloudSectors > 0) + Printf(TEXTCOLOR_RED "Map warning: have %d unhandled CLOUDYSKIES ceilings.\n", missedCloudSectors); + + // NOTE: must be safe loop because callbacks could delete sprites. + if (!DEER) + for (bssize_t nextSprite, SPRITES_OF_STAT_SAFE(STAT_DEFAULT, i, nextSprite)) + { + //A_LoadActor(i); + if (G_CheckExitSprite(i)) + { + g_player[0].ps->exitx = SX(i); + g_player[0].ps->exity = SY(i); + } + else switch (DYNAMICTILEMAP(PN(i))) + { + case NUKEBUTTON__STATIC: + if (RR) g_chickenPlant = 1; + break; + case GPSPEED__STATIC: + // DELETE_AFTER_LOADACTOR. Must not change statnum. + sector[SECT(i)].extra = SLT(i); + A_DeleteSprite(i); + break; + + case CYCLER__STATIC: + // DELETE_AFTER_LOADACTOR. Must not change statnum. + if (g_cyclerCnt >= MAXCYCLERS) + { + Bsprintf(tempbuf,"\nToo many cycling sectors (%d max).",MAXCYCLERS); + G_GameExit(tempbuf); + } + g_cyclers[g_cyclerCnt][0] = SECT(i); + g_cyclers[g_cyclerCnt][1] = SLT(i); + g_cyclers[g_cyclerCnt][2] = SS(i); + g_cyclers[g_cyclerCnt][3] = sector[SECT(i)].floorshade; + g_cyclers[g_cyclerCnt][4] = SHT(i); + g_cyclers[g_cyclerCnt][5] = (SA(i) == 1536); + g_cyclerCnt++; + A_DeleteSprite(i); + break; + + case RRTILE18__STATICRR: + if (!RR) break; + if (g_torchCnt >= 64) + G_GameExit("\nToo many torch effects"); + g_torchSector[g_torchCnt] = SECT(i); + g_torchSectorShade[g_torchCnt] = sector[SECT(i)].floorshade; + g_torchType[g_torchCnt] = SLT(i); + g_torchCnt++; + A_DeleteSprite(i); + break; + + case RRTILE35__STATICRR: + if (g_lightninCnt >= 64) + G_GameExit("\nToo many lightnin effects"); + g_lightninSector[g_lightninCnt] = SECT(i); + g_lightninSectorShade[g_lightninCnt] = sector[SECT(i)].floorshade; + g_lightninCnt++; + A_DeleteSprite(i); + break; + + case RRTILE68__STATICRR: + g_shadedSector[SECT(i)] = 1; + A_DeleteSprite(i); + break; + + case RRTILE67__STATICRR: + sprite[i].cstat |= 32768; + break; + + case SOUNDFX__STATICRR: + if (g_ambientCnt >= 64) + G_GameExit("\nToo many ambient effects"); + else + { + g_ambientHitag[g_ambientCnt] = SHT(i); + g_ambientLotag[g_ambientCnt] = SLT(i); + sprite[i].ang = g_ambientCnt++; + sprite[i].lotag = 0; + sprite[i].hitag = 0; + } + break; + + //case SECTOREFFECTOR__STATIC: + //case ACTIVATOR__STATIC: + //case TOUCHPLATE__STATIC: + //case ACTIVATORLOCKED__STATIC: + //case MUSICANDSFX__STATIC: + //case LOCATORS__STATIC: + //case MASTERSWITCH__STATIC: + //case RESPAWN__STATIC: + // sprite[i].cstat &= ~(1|16|32|256); + // break; + } + } + if (RR && !DEER) + { + for (bssize_t i = 0; i < MAXSPRITES; i++) + { + if (sprite[i].picnum == RRTILE19) + { + if (sprite[i].hitag == 0) + { + if (g_geoSectorCnt >= MAXGEOSECTORS) + G_GameExit("\nToo many geometry effects"); + g_geoSector[g_geoSectorCnt] = sprite[i].sectnum; + for (bssize_t j = 0; j < MAXSPRITES; j++) + { + if (sprite[i].lotag == sprite[j].lotag && i != j && sprite[j].picnum == RRTILE19) + { + if (sprite[j].hitag == 1) + { + g_geoSectorWarp[g_geoSectorCnt] = sprite[j].sectnum; + g_geoSectorX[g_geoSectorCnt] = sprite[i].x - sprite[j].x; + g_geoSectorY[g_geoSectorCnt] = sprite[i].y - sprite[j].y; + } + if (sprite[j].hitag == 2) + { + g_geoSectorWarp2[g_geoSectorCnt] = sprite[j].sectnum; + g_geoSectorX2[g_geoSectorCnt] = sprite[i].x - sprite[j].x; + g_geoSectorY2[g_geoSectorCnt] = sprite[i].y - sprite[j].y; + } + } + } + g_geoSectorCnt++; + } + } + } + } + + for (size_t i = 0; i < MAXSPRITES; i++) + { + if (sprite[i].statnum < MAXSTATUS && (DEER || PN(i) != SECTOREFFECTOR || SLT(i) != SE_14_SUBWAY_CAR)) + A_Spawn(-1, i); + } + + if (!DEER) + for (size_t i = 0; i < MAXSPRITES; i++) + { + if (sprite[i].statnum < MAXSTATUS && PN(i) == SECTOREFFECTOR && SLT(i) == SE_14_SUBWAY_CAR) + A_Spawn(-1, i); + if (RR && sprite[i].picnum == RRTILE19) + A_DeleteSprite(i); + if (RR && sprite[i].picnum == RRTILE34) + { + g_sectorExtra[sprite[i].sectnum] = sprite[i].lotag; + A_DeleteSprite(i); + } + } + + //G_SetupRotfixedSprites(); + + if (!DEER) + for (bssize_t i=headspritestat[STAT_DEFAULT]; i>=0; i=nextspritestat[i]) + { + if (PN(i) <= 0) // oob safety for switch below + continue; + + for (bsize_t ii=0; ii<2; ii++) + { + switch (DYNAMICTILEMAP(PN(i)-1+ii)) + { + case DIPSWITCH__STATIC: + case DIPSWITCH2__STATIC: + case PULLSWITCH__STATIC: + case HANDSWITCH__STATIC: + case SLOTDOOR__STATIC: + case LIGHTSWITCH__STATIC: + case SPACELIGHTSWITCH__STATIC: + case SPACEDOORSWITCH__STATIC: + case FRANKENSTINESWITCH__STATIC: + case LIGHTSWITCH2__STATIC: + case POWERSWITCH1__STATIC: + case LOCKSWITCH1__STATIC: + case POWERSWITCH2__STATIC: + case RRTILE8464__STATICRR: + if (RR && !RRRA && PN(i)-1+ii == (uint32_t)RRTILE8464) break; + // the lower code only for the 'on' state (*) + if (ii==0) + { + uint16_t const tag = sprite[i].lotag; + tagbitmap[tag>>3] |= 1<<(tag&7); + } + + break; + } + } + } + + // initially 'on' SE 12 light (*) + if (!DEER) + for (bssize_t j=headspritestat[STAT_EFFECTOR]; j>=0; j=nextspritestat[j]) + { + uint16_t const tag = sprite[j].hitag; + + if (sprite[j].lotag == SE_12_LIGHT_SWITCH && tagbitmap[tag>>3]&(1<<(tag&7))) + actor[j].t_data[0] = 1; + } + + Xfree(tagbitmap); + + g_mirrorCount = 0; + + for (bssize_t i = 0; i < numwalls; i++) + { + walltype * const pWall = &wall[i]; + + if (!DEER && pWall->overpicnum == MIRROR && (pWall->cstat&32) != 0) + { + int const nextSectnum = pWall->nextsector; + + if ((nextSectnum >= 0) && sector[nextSectnum].ceilingpicnum != MIRROR) + { + if (g_mirrorCount > 63) + { + G_GameExit("\nToo many mirrors (64 max.)"); + } + + sector[nextSectnum].ceilingpicnum = MIRROR; + sector[nextSectnum].floorpicnum = MIRROR; + g_mirrorWall[g_mirrorCount] = i; + g_mirrorSector[g_mirrorCount] = nextSectnum; + g_mirrorCount++; + continue; + } + } + + if (g_animWallCnt >= MAXANIMWALLS) + { + Bsprintf(tempbuf,"\nToo many 'anim' walls (%d max).",MAXANIMWALLS); + G_GameExit(tempbuf); + } + + animwall[g_animWallCnt].tag = 0; + animwall[g_animWallCnt].wallnum = 0; + + if (DEER) + { + pWall->extra = -1; + continue; + } + + int const switchPic = G_GetForcefieldPicnum(i); + + if (switchPic >= 0) + { + switch (DYNAMICTILEMAP(switchPic)) + { + case FANSHADOW__STATIC: + if (RR) break; + fallthrough__; + case FANSPRITE__STATIC: + wall->cstat |= 65; + animwall[g_animWallCnt].wallnum = i; + g_animWallCnt++; + break; + + case W_FORCEFIELD__STATIC: + if (RR) break; + if (pWall->overpicnum == W_FORCEFIELD__STATIC) + for (bsize_t j = 0; j < 3; j++) tloadtile(W_FORCEFIELD + j, 0); + if (pWall->shade > 31) + pWall->cstat = 0; + else + pWall->cstat |= FORCEFIELD_CSTAT | 256; + + + if (pWall->lotag && pWall->nextwall >= 0) + wall[pWall->nextwall].lotag = pWall->lotag; + fallthrough__; + case BIGFORCE__STATIC: + animwall[g_animWallCnt].wallnum = i; + g_animWallCnt++; + + continue; + } + } + + pWall->extra = -1; + + switch (DYNAMICTILEMAP(pWall->picnum)) + { + case WATERTILE2__STATIC: + for (bsize_t j = 0; j < 3; j++) + tloadtile(pWall->picnum + j, 0); + break; + + case RRTILE1814__STATICRR: + case RRTILE1817__STATICRR: + tloadtile(pWall->picnum, 0); + break; + case RRTILE1939__STATICRR: + case RRTILE1986__STATICRR: + case RRTILE1987__STATICRR: + case RRTILE1988__STATICRR: + case RRTILE2004__STATICRR: + case RRTILE2005__STATICRR: + case RRTILE2123__STATICRR: + case RRTILE2124__STATICRR: + case RRTILE2125__STATICRR: + case RRTILE2126__STATICRR: + case RRTILE2636__STATICRR: + case RRTILE2637__STATICRR: + case RRTILE2878__STATICRR: + case RRTILE2879__STATICRR: + case RRTILE2898__STATICRR: + case RRTILE2899__STATICRR: + tloadtile(pWall->picnum, 0); + break; + + + case TECHLIGHT2__STATIC: + case TECHLIGHT4__STATIC: tloadtile(pWall->picnum, 0); break; + case W_TECHWALL1__STATIC: + case W_TECHWALL2__STATIC: + case W_TECHWALL3__STATIC: + case W_TECHWALL4__STATIC: + if (RR) break; + animwall[g_animWallCnt].wallnum = i; + // animwall[g_numAnimWalls].tag = -1; + g_animWallCnt++; + break; + case SCREENBREAK6__STATIC: + case SCREENBREAK7__STATIC: + case SCREENBREAK8__STATIC: + for (bssize_t j = SCREENBREAK6; j < SCREENBREAK9; j++) + tloadtile(j, 0); + + animwall[g_animWallCnt].wallnum = i; + animwall[g_animWallCnt].tag = -1; + g_animWallCnt++; + break; + + case FEMPIC1__STATIC: + case FEMPIC2__STATIC: + case FEMPIC3__STATIC: + if (RR) break; + pWall->extra = pWall->picnum; + animwall[g_animWallCnt].tag = -1; + + if (adult_lockout) + pWall->picnum = (pWall->picnum == FEMPIC1) ? BLANKSCREEN : SCREENBREAK6; + + animwall[g_animWallCnt].wallnum = i; + animwall[g_animWallCnt].tag = pWall->picnum; + g_animWallCnt++; + break; + + case SCREENBREAK1__STATIC: + case SCREENBREAK2__STATIC: + case SCREENBREAK3__STATIC: + case SCREENBREAK4__STATIC: + case SCREENBREAK5__STATIC: + // + case SCREENBREAK9__STATIC: + case SCREENBREAK10__STATIC: + case SCREENBREAK11__STATIC: + case SCREENBREAK12__STATIC: + case SCREENBREAK13__STATIC: + case SCREENBREAK14__STATIC: + case SCREENBREAK15__STATIC: + case SCREENBREAK16__STATIC: + case SCREENBREAK17__STATIC: + case SCREENBREAK18__STATIC: + case SCREENBREAK19__STATIC: + if (RR) break; + animwall[g_animWallCnt].wallnum = i; + animwall[g_animWallCnt].tag = pWall->picnum; + g_animWallCnt++; + break; + } + } + + //Invalidate textures in sector behind mirror + for (bssize_t i=0; ivisibility; + } + if (RR) + { + tileDelete(0); + } + + G_SetupGlobalPsky(); + + if (DEER) + sub_52BA8(); +} + + +void G_NewGame(int volumeNum, int levelNum, int skillNum) +{ + DukePlayer_t *const pPlayer = g_player[0].ps; + + G_HandleAsync(); + + g_skillSoundVoice = -1; + + ready2send = 0; + + if (m_recstat != 2 && ud.last_level >= 0 && + (g_netServer || ud.multimode > 1) && (ud.coop&GAMETYPE_SCORESHEET)) + { + if (!RRRA || g_mostConcurrentPlayers > 1 || g_netServer || numplayers > 1) + G_BonusScreen(1); + else + G_BonusScreenRRRA(1); + } + + if (RR && !RRRA && g_turdLevel && !g_lastLevel) + G_BonusScreen(0); + + g_showShareware = GAMETICSPERSEC*34; + + ud.level_number = levelNum; + ud.volume_number = volumeNum; + ud.player_skill = skillNum; + ud.secretlevel = 0; + ud.from_bonus = 0; + + ud.last_level = -1; + + int const UserMap = Menu_HaveUserMap(); + + // we don't want the intro to play after the multiplayer setup screen + if (!RR && (!g_netServer && ud.multimode < 2) && UserMap == 0 && + levelNum == 0 && volumeNum == 3 && adult_lockout == 0) + { + S_PlaySpecialMusicOrNothing(MUS_BRIEFING); + + renderFlushPerms(); + videoSetViewableArea(0,0,xdim-1,ydim-1); + twod->ClearScreen(); + videoNextPage(); + + int animReturn = Anim_Play("vol41a.anm"); + twod->ClearScreen(); + videoNextPage(); + if (animReturn) + goto end_vol4a; + + animReturn = Anim_Play("vol42a.anm"); + twod->ClearScreen(); + videoNextPage(); + if (animReturn) + goto end_vol4a; + + Anim_Play("vol43a.anm"); + twod->ClearScreen(); + videoNextPage(); + +end_vol4a: + FX_StopAllSounds(); + } + +#ifdef EDUKE32_TOUCH_DEVICES + pPlayer->zoom = 360; +#else + pPlayer->zoom = 768; +#endif + pPlayer->gm = 0; + M_ClearMenus(); + + Gv_ResetVars(); + Gv_InitWeaponPointers(); + Gv_RefreshPointers(); + Gv_ResetSystemDefaults(); + + //AddLog("Newgame"); + + for (bssize_t i=0; i<(MAXVOLUMES*MAXLEVELS); i++) + G_FreeMapState(i); + + if (m_coop != 1) + { + for (bssize_t weaponNum = 0; weaponNum < MAX_WEAPONS; weaponNum++) + { + auto const worksLike = WW2GI ? PWEAPON(0, weaponNum, WorksLike) : weaponNum; + if (worksLike == PISTOL_WEAPON) + { + pPlayer->curr_weapon = weaponNum; + pPlayer->gotweapon |= (1 << weaponNum); + pPlayer->ammo_amount[weaponNum] = min(pPlayer->max_ammo_amount[weaponNum], 48); + } + else if (worksLike == KNEE_WEAPON || (!RR && worksLike == HANDREMOTE_WEAPON) || (RRRA && worksLike == SLINGBLADE_WEAPON)) + { + pPlayer->gotweapon |= (1 << weaponNum); + if (RRRA) + pPlayer->ammo_amount[KNEE_WEAPON] = 1; + } + } + pPlayer->last_weapon = -1; + } + + display_mirror = 0; +} + +static void resetpspritevars(char gameMode) +{ + int16_t i, j; //circ; + + uint8_t aimmode[MAXPLAYERS],autoaim[MAXPLAYERS],weaponswitch[MAXPLAYERS]; + DukeStatus_t tsbar[MAXPLAYERS]; + + if (g_player[0].ps->cursectnum >= 0) // < 0 may happen if we start a map in void space (e.g. testing it) + { + A_InsertSprite(g_player[0].ps->cursectnum,g_player[0].ps->pos.x,g_player[0].ps->pos.y,g_player[0].ps->pos.z, + APLAYER,0,0,0,fix16_to_int(g_player[0].ps->q16ang),0,0,0,10); + } + + if (ud.recstat != 2) + for (TRAVERSE_CONNECT(i)) + { + aimmode[i] = g_player[i].ps->aim_mode; + autoaim[i] = g_player[i].ps->auto_aim; + weaponswitch[i] = g_player[i].ps->weaponswitch; + if ((g_netServer || ud.multimode > 1) && (g_gametypeFlags[ud.coop]&GAMETYPE_PRESERVEINVENTORYDEATH) && ud.last_level >= 0) + { + for (j=0; jammo_amount[j]; + + tsbar[i].gotweapon = g_player[i].ps->gotweapon; + Bmemcpy(tsbar[i].inv_amount, g_player[i].ps->inv_amount, sizeof(tsbar[i].inv_amount)); + tsbar[i].curr_weapon = g_player[i].ps->curr_weapon; + tsbar[i].inven_icon = g_player[i].ps->inven_icon; + } + } + + P_ResetStatus(0); + + for (TRAVERSE_CONNECT(i)) + if (i) Bmemcpy(g_player[i].ps,g_player[0].ps,sizeof(DukePlayer_t)); + + if (ud.recstat != 2) + for (TRAVERSE_CONNECT(i)) + { + g_player[i].ps->aim_mode = aimmode[i]; + g_player[i].ps->auto_aim = autoaim[i]; + g_player[i].ps->weaponswitch = weaponswitch[i]; + if ((g_netServer || ud.multimode > 1) && (g_gametypeFlags[ud.coop]&GAMETYPE_PRESERVEINVENTORYDEATH) && ud.last_level >= 0) + { + for (j=0; jammo_amount[j] = tsbar[i].ammo_amount[j]; + + g_player[i].ps->gotweapon = tsbar[i].gotweapon; + g_player[i].ps->curr_weapon = tsbar[i].curr_weapon; + g_player[i].ps->inven_icon = tsbar[i].inven_icon; + Bmemcpy(g_player[i].ps->inv_amount, tsbar[i].inv_amount, sizeof(tsbar[i].inv_amount)); + } + } + + g_playerSpawnCnt = 0; +// circ = 2048/ud.multimode; + + g_whichPalForPlayer = 9; + j = 0; + i = headspritestat[STAT_PLAYER]; + while (i >= 0) + { + const int32_t nexti = nextspritestat[i]; + spritetype *const s = &sprite[i]; + + if (g_playerSpawnCnt == MAXPLAYERS) + G_GameExit("\nToo many player sprites (max 16.)"); + + g_playerSpawnPoints[g_playerSpawnCnt].pos.x = s->x; + g_playerSpawnPoints[g_playerSpawnCnt].pos.y = s->y; + g_playerSpawnPoints[g_playerSpawnCnt].pos.z = s->z; + g_playerSpawnPoints[g_playerSpawnCnt].ang = s->ang; + g_playerSpawnPoints[g_playerSpawnCnt].sect = s->sectnum; + + g_playerSpawnCnt++; + + if (j < MAXPLAYERS) + { + s->owner = i; + s->shade = 0; + s->xrepeat = RR ? 24 : 42; + s->yrepeat = RR ? 17 : 36; + //s->xrepeat = 42; + //s->yrepeat = 36; + if (!g_fakeMultiMode) + s->cstat = j < numplayers ? 1+256 : 32768; + else + s->cstat = j < ud.multimode ? 1+256 : 32768; + s->xoffset = 0; + s->clipdist = 64; + + if (j < g_mostConcurrentPlayers) + { + if ((gameMode&MODE_EOL) != MODE_EOL || g_player[j].ps->last_extra == 0) + { + g_player[j].ps->last_extra = g_player[j].ps->max_player_health; + s->extra = g_player[j].ps->max_player_health; + g_player[j].ps->runspeed = g_playerFriction; + } + else s->extra = g_player[j].ps->last_extra; + + s->yvel = j; + + if (!g_player[j].pcolor && (g_netServer || ud.multimode > 1) && !(g_gametypeFlags[ud.coop] & GAMETYPE_TDM)) + { + if (s->pal == 0) + { + int32_t k = 0; + + for (; kpalookup) + { + g_whichPalForPlayer++; + if (g_whichPalForPlayer >= 17) + g_whichPalForPlayer = 9; + k=0; + } + } + g_player[j].pcolor = s->pal = g_player[j].ps->palookup = g_whichPalForPlayer++; + if (g_whichPalForPlayer >= 17) + g_whichPalForPlayer = 9; + } + else g_player[j].pcolor = g_player[j].ps->palookup = s->pal; + } + else + { + int32_t k = g_player[j].pcolor; + + if (g_gametypeFlags[ud.coop] & GAMETYPE_TDM) + { + k = G_GetTeamPalette(g_player[j].pteam); + g_player[j].ps->team = g_player[j].pteam; + } + s->pal = g_player[j].ps->palookup = k; + } + + g_player[j].ps->i = i; + g_player[j].ps->frag_ps = j; + actor[i].owner = i; + + g_player[j].ps->autostep = (20L<<8); + g_player[j].ps->autostep_sbw = (4L<<8); + + actor[i].bpos.x = g_player[j].ps->bobpos.x = g_player[j].ps->opos.x = g_player[j].ps->pos.x = s->x; + actor[i].bpos.y = g_player[j].ps->bobpos.y = g_player[j].ps->opos.y = g_player[j].ps->pos.y = s->y; + actor[i].bpos.z = g_player[j].ps->opos.z = g_player[j].ps->pos.z = s->z; + g_player[j].ps->oq16ang = g_player[j].ps->q16ang = fix16_from_int(s->ang); + + updatesector(s->x,s->y,&g_player[j].ps->cursectnum); + } + + j++; + } + else A_DeleteSprite(i); + + i = nexti; + } +} + +static inline void clearfrags(void) +{ + for (bssize_t i = 0; i < ud.multimode; i++) + { + playerdata_t *const pPlayerData = &g_player[i]; + pPlayerData->ps->frag = pPlayerData->ps->fraggedself = 0; + Bmemset(pPlayerData->frags, 0, sizeof(pPlayerData->frags)); + } +} + +void G_ResetTimers(uint8_t keepgtics) +{ + totalclock = g_cloudClock = ototalclock = lockclock = 0; + ready2send = 1; + g_levelTextTime = 85; + + if (!keepgtics) + g_moveThingsCount = 0; + + if (g_curViewscreen >= 0) + actor[g_curViewscreen].t_data[0] = 0; +} + +void G_ClearFIFO(void) +{ + Net_ClearFIFO(); + + memset(&localInput, 0, sizeof(input_t)); + memset(&inputfifo, 0, sizeof(input_t) * MOVEFIFOSIZ * MAXPLAYERS); + + for (bsize_t p = 0; p <= MAXPLAYERS - 1; ++p) + { + if (g_player[p].input != NULL) + Bmemset(g_player[p].input, 0, sizeof(input_t)); + g_player[p].vote = g_player[p].gotvote = 0; + } +} + +int G_FindLevelByFile(const char *fileName) +{ + for (bssize_t volumeNum = 0; volumeNum < MAXVOLUMES; volumeNum++) + { + int const volOffset = volumeNum * MAXLEVELS; + + for (bssize_t levelNum = 0; levelNum < MAXLEVELS; levelNum++) + { + if (!mapList[volOffset + levelNum].fileName.CompareNoCase(fileName)) + return volOffset + levelNum; + } + } + + return MAXLEVELS * MAXVOLUMES; +} + +#if 0 +static void G_FadeLoad(int32_t r, int32_t g, int32_t b, int32_t start, int32_t end, int32_t step, int32_t ticwait, int32_t tc) +{ + int32_t m = (step < 0) ? -1 : 1; + + int32_t nexttic = totalclock; + + for (; m*start <= m*end; start += step) + { + while (totalclock < nexttic) + sampletimer(); + nexttic += ticwait; + + if (inputState.GetKeyStatus(sc_Space)) + { + inputState.ClearKeyStatus(sc_Space); + return; + } + + setpalettefade(r,g,b,start); + flushperms(); + G_DoLoadScreen(" ", tc); + } +} +#endif + +static int G_TryMapHack(const char *mhkfile) +{ + int32_t failure = engineLoadMHK(mhkfile); + + if (!failure) + Printf("Loaded map hack file \"%s\"\n", mhkfile); + + return failure; +} + +static void G_LoadMapHack(char *outbuf, const char *filename) +{ + if (filename != NULL) + Bstrcpy(outbuf, filename); + + append_ext_UNSAFE(outbuf, ".mhk"); + + if (G_TryMapHack(outbuf) && usermaphacks != NULL) + { + usermaphack_t *pMapInfo = (usermaphack_t*)bsearch( + &g_loadedMapHack, usermaphacks, num_usermaphacks, sizeof(usermaphack_t), + compare_usermaphacks); + + if (pMapInfo) + G_TryMapHack(pMapInfo->mhkfile); + } +} + +int G_EnterLevel(int gameMode) +{ + int32_t i, mii; + char levelName[BMAX_PATH]; + +// flushpackets(); +// waitforeverybody(); + vote_map = vote_episode = voting = -1; + + ud.respawn_monsters = ud.m_respawn_monsters; + ud.respawn_items = ud.m_respawn_items; + ud.respawn_inventory = ud.m_respawn_inventory; + ud.monsters_off = ud.m_monsters_off; + ud.coop = m_coop; + ud.marker = m_marker; + ud.ffire = m_ffire; + ud.noexits = m_noexits; + + if ((gameMode & MODE_DEMO) != MODE_DEMO) + ud.recstat = m_recstat; + if ((gameMode & MODE_DEMO) == 0 && ud.recstat == 2) + ud.recstat = 0; + + VM_OnEvent(EVENT_ENTERLEVEL); + + //if (g_networkMode != NET_DEDICATED_SERVER) + { + S_ResumeSound(false); + FX_StopAllSounds(); + S_ClearSoundLocks(); + FX_SetReverb(0); + } + + if (Menu_HaveUserMap()) + { + int levelNum = G_FindLevelByFile(boardfilename); + + if (levelNum != MAXLEVELS*MAXVOLUMES) + { + int volumeNum = levelNum; + + levelNum &= MAXLEVELS-1; + volumeNum = (volumeNum - levelNum) / MAXLEVELS; + + ud.level_number = m_level_number = levelNum; + ud.volume_number = ud.m_volume_number = volumeNum; + + boardfilename[0] = 0; + } + } + + // Redirect the final RR level to a valid map record so that currentLevel can point to something. + mii = (RR && g_lastLevel)? 127 : (ud.volume_number*MAXLEVELS)+ud.level_number; + auto &mi = mapList[mii]; + + if (mi.fileName.IsEmpty() && !Menu_HaveUserMap()) + { + Printf(TEXTCOLOR_RED "Map E%dL%d not defined!\n", ud.volume_number+1, ud.level_number+1); + return 1; + } + + i = ud.screen_size; + ud.screen_size = 0; + + FStringf msg("%s . . .", GStrings("TXT_LOADMAP")); + G_DoLoadScreen(msg, -1); + G_UpdateScreenArea(); + + ud.screen_size = i; + + DukePlayer_t *const pPlayer = g_player[0].ps; + int16_t lbang; + + if (!VOLUMEONE && Menu_HaveUserMap()) + { + if (engineLoadBoard(boardfilename, 0, &pPlayer->pos, &lbang, &pPlayer->cursectnum) < 0) + { + Printf(TEXTCOLOR_RED "Map \"%s\" not found or invalid map version!\n", boardfilename); + return 1; + } + userMapRecord.name = ""; + userMapRecord.SetFileName(boardfilename); + currentLevel = &userMapRecord; + SECRET_SetMapName(currentLevel->DisplayName(), currentLevel->name); + STAT_NewLevel(boardfilename); + G_LoadMapHack(levelName, boardfilename); + userMapRecord.music = G_SetupFilenameBasedMusic(boardfilename, !RR? "dethtoll.mid" : nullptr); + } + else if (engineLoadBoard(mi.fileName, VOLUMEONE, &pPlayer->pos, &lbang, &pPlayer->cursectnum) < 0) + { + Printf(TEXTCOLOR_RED "Map \"%s\" not found or invalid map version!\n", mi.fileName.GetChars()); + return 1; + } + else + { + currentLevel = &mi; + SECRET_SetMapName(currentLevel->DisplayName(), currentLevel->name); + STAT_NewLevel(mi.fileName); + G_LoadMapHack(levelName, mi.fileName); + } + + if (RR && !RRRA && ud.volume_number == 1 && ud.level_number == 1) + { + for (bssize_t i = PISTOL_WEAPON; i < MAX_WEAPONS; i++) + g_player[0].ps->ammo_amount[i] = 0; + g_player[0].ps->gotweapon &= (1<q16ang = fix16_from_int(lbang); + + g_precacheCount = 0; + Bmemset(gotpic, 0, sizeof(gotpic)); + Bmemset(precachehightile, 0, sizeof(precachehightile)); + + prelevel(gameMode); + + G_InitRRRASkies(); + + if (RRRA && ud.level_number == 2 && ud.volume_number == 0) + { + for (bssize_t i = PISTOL_WEAPON; i < MAX_WEAPONS; i++) + g_player[0].ps->ammo_amount[i] = 0; + g_player[0].ps->gotweapon &= (1<gotweapon |= (1<ammo_amount[SLINGBLADE_WEAPON] = 1; + g_player[0].ps->curr_weapon = SLINGBLADE_WEAPON; + } + + G_AlignWarpElevators(); + resetpspritevars(gameMode); + + ud.playerbest = CONFIG_GetMapBestTime(Menu_HaveUserMap() ? boardfilename : mi.fileName.GetChars(), g_loadedMapHack.md4); + + // G_FadeLoad(0,0,0, 252,0, -28, 4, -1); + G_CacheMapData(); + // G_FadeLoad(0,0,0, 0,252, 28, 4, -2); + + // Try this first so that it can disable the CD player if no tracks are found. + if (RR && !(gameMode & MODE_DEMO)) + S_PlayRRMusic(); + + if (ud.recstat != 2) + { + if (Menu_HaveUserMap()) + { + S_PlayLevelMusicOrNothing(USERMAPMUSICFAKESLOT); + } + else S_PlayLevelMusicOrNothing(mii); + } + + if (gameMode & (MODE_GAME|MODE_EOL)) + { + for (TRAVERSE_CONNECT(i)) + { + g_player[i].ps->gm = MODE_GAME; + } + } + else if (gameMode & MODE_RESTART) + { + if (ud.recstat == 2) + g_player[myconnectindex].ps->gm = MODE_DEMO; + else g_player[myconnectindex].ps->gm = MODE_GAME; + } + + if ((ud.recstat == 1) && (gameMode&MODE_RESTART) != MODE_RESTART) + G_OpenDemoWrite(); + +#ifndef EDUKE32_TOUCH_DEVICES + if (VOLUMEONE && ud.level_number == 0 && ud.recstat != 2) + P_DoQuote(QUOTE_F1HELP,g_player[myconnectindex].ps); +#endif + + for (TRAVERSE_CONNECT(i)) + { + switch (DYNAMICTILEMAP(sector[sprite[g_player[i].ps->i].sectnum].floorpicnum)) + { + case HURTRAIL__STATIC: + case FLOORSLIME__STATIC: + case FLOORPLASMA__STATIC: + P_ResetWeapons(i); + P_ResetInventory(i); + + g_player[i].ps->gotweapon &= ~(1 << PISTOL_WEAPON); + g_player[i].ps->ammo_amount[PISTOL_WEAPON] = 0; + + g_player[i].ps->curr_weapon = KNEE_WEAPON; + g_player[i].ps->kickback_pic = 0; + break; + } + } + + //PREMAP.C - replace near the my's at the end of the file + + Net_NotifyNewGame(); + Net_ResetPrediction(); + + //g_player[myconnectindex].ps->palette = palette; + //G_FadePalette(0,0,0,0); + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + P_UpdateScreenPal(g_player[myconnectindex].ps); + renderFlushPerms(); + + // reset lastInputTicks. + g_player[myconnectindex].lastInputTicks = 0; + + everyothertime = 0; + g_globalRandom = 0; + + ud.last_level = ud.level_number+1; + + G_ClearFIFO(); + + for (i=g_interpolationCnt-1; i>=0; i--) bakipos[i] = *curipos[i]; + + g_player[myconnectindex].ps->over_shoulder_on = 0; + + clearfrags(); + + G_ResetTimers(0); // Here we go + + //Bsprintf(g_szBuf,"G_EnterLevel L=%d V=%d",ud.level_number, ud.volume_number); + //AddLog(g_szBuf); + // variables are set by pointer... + + + if (G_HaveUserMap()) + { + Printf(TEXTCOLOR_GOLD "%s: %s\n", GStrings("TXT_USERMAP"), boardfilename); + } + else + { + Printf(TEXTCOLOR_GOLD "E%dL%d: %s\n", ud.volume_number+1, ud.level_number+1, + mapList[mii].DisplayName()); + } + + g_restorePalette = -1; + + G_UpdateScreenArea(); + videoClearViewableArea(0L); + G_DrawBackground(); + G_DrawRooms(myconnectindex,65536); + + Net_WaitForEverybody(); + return 0; +} + +void G_FreeMapState(int levelNum) +{ + map_t *const pMapInfo = &g_mapInfo[levelNum]; + + if (pMapInfo->savedstate == NULL) + return; + + ALIGNED_FREE_AND_NULL(pMapInfo->savedstate); +} + +void G_SetFog(int fogtype) +{ + GLInterface.SetMapFog(fogtype != 0); +} + +END_DUKE_NS diff --git a/source/duke/src/premap.h b/source/duke/src/premap.h new file mode 100644 index 000000000..2c4a081b4 --- /dev/null +++ b/source/duke/src/premap.h @@ -0,0 +1,52 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef premap_h_ +#define premap_h_ + +BEGIN_DUKE_NS + +extern int16_t g_ambientLotag[64]; +extern int16_t g_ambientHitag[64]; +extern int32_t g_levelTextTime; +extern int32_t voting,vote_map,vote_episode; +int G_EnterLevel(int gameMode); +int G_FindLevelByFile(const char *fileName); +void G_CacheMapData(void); +void G_FreeMapState(int levelNum); +void G_NewGame(int volumeNum, int levelNum, int skillNum); +void G_ResetTimers(uint8_t keepgtics); +void G_UpdateScreenArea(void); +void P_RandomSpawnPoint(int playerNum); +void P_ResetInventory(int playerNum); +void P_ResetPlayer(int playerNum); +void P_ResetStatus(int playerNum); +void P_ResetWeapons(int playerNum); +void G_ClearFIFO(void); +void G_ResetInterpolations(void); +extern int32_t fragbarheight(void); +void G_SetFog(int fogtype); +void G_InitRRRASkies(void); + +END_DUKE_NS + +#endif diff --git a/source/duke/src/quotes.h b/source/duke/src/quotes.h new file mode 100644 index 000000000..46858c821 --- /dev/null +++ b/source/duke/src/quotes.h @@ -0,0 +1,97 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2011 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef quotes_h_ +#define quotes_h_ + +#include "quotemgr.h" + +#define OBITQUOTEINDEX (MAXQUOTES-128) +#define SUICIDEQUOTEINDEX (MAXQUOTES-32) + +#define QUOTE_SHOW_MAP_OFF 1 +#define QUOTE_ACTIVATED 2 +#define QUOTE_MEDKIT 3 +#define QUOTE_LOCKED 4 +#define QUOTE_CHEAT_EVERYTHING 5 +#define QUOTE_BOOTS 6 +#define QUOTE_WASTED 7 +#define QUOTE_UNLOCKED 8 +#define QUOTE_FOUND_SECRET 9 +#define QUOTE_SQUISHED 10 +#define QUOTE_USED_STEROIDS 12 +#define QUOTE_DEAD 13 +#define QUOTE_DEACTIVATED 15 +#define QUOTE_CHEAT_GODMODE_ON 17 +#define QUOTE_CHEAT_GODMODE_OFF 18 +#define QUOTE_CROSSHAIR_OFF 21 +#define QUOTE_CHEATS_DISABLED 22 +#define QUOTE_MESSAGES_ON 23 +#define QUOTE_MESSAGES_OFF 24 +#define QUOTE_MUSIC 26 +#define QUOTE_CHEAT_STEROIDS 37 +#define QUOTE_F1HELP 40 +#define QUOTE_MOUSE_AIMING_OFF 44 +#define QUOTE_HOLODUKE_ON 47 +#define QUOTE_HOLODUKE_OFF 48 +#define QUOTE_HOLODUKE_NOT_FOUND 49 +#define QUOTE_JETPACK_NOT_FOUND 50 +#define QUOTE_JETPACK_ON 52 +#define QUOTE_JETPACK_OFF 53 +#define QUOTE_NEED_BLUE_KEY 70 +#define QUOTE_NEED_RED_KEY 71 +#define QUOTE_NEED_YELLOW_KEY 72 +#define QUOTE_WEAPON_LOWERED 73 +#define QUOTE_WEAPON_RAISED 74 +#define QUOTE_BOOTS_ON 75 +#define QUOTE_SCUBA_ON 76 +#define QUOTE_CHEAT_ALLEN 79 +#define QUOTE_MIGHTY_FOOT 80 +#define QUOTE_WEAPON_MODE_OFF 82 +#define QUOTE_MAP_FOLLOW_OFF 83 +#define QUOTE_RUN_MODE_OFF 85 +#define QUOTE_JETPACK 88 +#define QUOTE_SCUBA 89 +#define QUOTE_STEROIDS 90 +#define QUOTE_HOLODUKE 91 +#define QUOTE_CHEAT_TODD 99 +#define QUOTE_CHEAT_UNLOCK 100 +#define QUOTE_NVG 101 +#define QUOTE_WEREGONNAFRYYOURASS 102 +#define QUOTE_SCREEN_SAVED 103 +#define QUOTE_CHEAT_BETA 105 +#define QUOTE_NVG_OFF 107 +#define QUOTE_VIEW_MODE_OFF 109 +#define QUOTE_SHOW_MAP_ON 111 +#define QUOTE_CHEAT_NOCLIP 113 +#define QUOTE_SAVE_BAD_VERSION 114 +#define QUOTE_RESERVED 115 +#define QUOTE_RESERVED2 116 +#define QUOTE_RESERVED3 117 +#define QUOTE_SAVE_DEAD 118 +#define QUOTE_CHEAT_ALL_WEAPONS 119 +#define QUOTE_CHEAT_ALL_INV 120 +#define QUOTE_CHEAT_ALL_KEYS 121 +#define QUOTE_RESERVED4 122 +#define QUOTE_SAVE_BAD_PLAYERS 124 + +#endif diff --git a/source/duke/src/rrdh.cpp b/source/duke/src/rrdh.cpp new file mode 100644 index 000000000..f5af1bfc2 --- /dev/null +++ b/source/duke/src/rrdh.cpp @@ -0,0 +1,4476 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors +Copyright (C) 2020 Nuke.YKT + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" + + +#include "compat.h" +#include "baselayer.h" +#include "duke3d.h" +#include "sounds.h" +#include "i_time.h" +#include "files.h" +#include "i_specialpaths.h" + +// Shut up the compiler. +#ifdef _MSC_VER +#pragma warning(disable:4101) +#endif +BEGIN_DUKE_NS + +inline bool KB_KeyPressed(int code) +{ + return inputState.GetKeyStatus(code); +} + +inline void KB_ClearKeyDown(int key) +{ + inputState.ClearKeyStatus(key); +} + +int rrdh_randseed = 1; + +int rrdh_random(void) +{ + static int seedinit = 0; + if (!seedinit) + { + rrdh_randseed = (int)I_nsTime(); + seedinit = 1; + } + rrdh_randseed = (rrdh_randseed*1103515245)+12345; + return (rrdh_randseed>>16)&0x7fff; +} + + +int sub_5151C(short a1) +{ + switch (a1) + { + case 26: + case 27: + case 29: + case 30: + case 31: + case 32: + case 33: + case 34: + case 35: + case 73: + case 74: + case 92: + case 93: + case 96: + case 97: + case 98: + case 103: + case 141: + case 142: + case 143: + case 144: + case 145: + case 146: + case 147: + case 148: + case 149: + case 150: + case 151: + case 152: + case 153: + case 154: + case 155: + case 156: + case 157: + case 158: + case 159: + case 160: + case 161: + case 162: + case 163: + case 164: + case 165: + return 1; + } + return 0; +} + +int rrgh_isatree(short s) +{ + switch (sprite[s].picnum) + { + case 984: + case 985: + case 986: + case 988: + case 989: + case 990: + case 991: + case 1028: + case 1029: + case 1030: + case 1040: + case 1041: + case 1050: + case 1051: + case 1052: + case 1053: + case 1054: + case 1055: + case 1056: + case 1057: + case 1058: + case 1059: + case 1093: + case 1094: + case 1095: + case 1096: + case 1097: + case 1098: + case 1099: + case 1100: + case 1113: + case 1114: + case 1115: + case 1116: + case 1117: + return 1; + } + return 0; +} + +void sub_51678(int a1, int a2, int a3, int a4, int a5, int a6) +{ +} + +int ghcons_isanimalescapewall(short w) +{ + walltype *wl = &wall[w]; + switch (wall[w].picnum) + { + case 1182: + case 1183: + case 1184: + case 1185: + case 2347: + case 3802: + case 3803: + case 7870: + case 7871: + case 7872: + return 1; + } + return 0; +} + +int ghcons_isanimalescapesect(short s) +{ + sectortype *sc = §or[s]; + return sector[s].hitag == 2001; +} + +int sub_517AC(int *a1, int *a2, short *a3) +{ + int i, x, y; + short j; + if (numsectors < 0 || numsectors >= MAXSECTORS) + return 0; + for (i = 0; i < 32; i++) + { + x = (((rrdh_random() & 2047) + 1) - 1024) * 100; + y = (((rrdh_random() & 2047) + 1) - 1024) * 100; + + for (j = 0; j < numsectors; j++) + { + if (inside(x, y, j)) + { + *a1 = x; + *a2 = y; + *a3 = j; + return 1; + } + } + } + return 0; +} + +int ghcons_findnewspot(short a1) +{ + int v20 = 0, v24 = 0; + short v18 = 0; + spritetype *spr; + sectortype *sec; + spr = &sprite[a1]; + if (sub_517AC(&v20, &v24, &v18)) + { + sec = §or[v18]; + switch (DYNAMICTILEMAP(spr->picnum)) + { + case PIG__STATICRR: + case VIXEN__STATICRR: + case CHEER__STATICRR: + if (sec->hitag) + return 0; + break; + case DOGRUN__STATICRR: + if (sec->hitag) + return 0; + break; + } + vec3_t pos = { v20, v24, v18 }; + setsprite(a1, &pos); + changespritesect(a1, v18); + if (spr->picnum == DOGRUN) + spr->z = -307200; + else + spr->z = sec->floorz; + return 1; + } + return 0; +} + +void sub_519E8(int a1) +{ + int vbx; + if ((rrdh_random() & 63) == 32) + { + if (sub_57A60(20)) + { + vbx = rrdh_random() % 5; + switch (a1) + { + case 0: + case 4: + vbx += 60; + break; + case 1: + case 5: + vbx += 65; + break; + case 2: + vbx += 70; + break; + case 3: + vbx += 75; + break; + } + S_PlaySound(vbx); + } + } +} + +int dword_AA25C; + +void ghsound_ambientlooppoll(void) +{ + if (dword_AA25C) + { + if (dword_AA25C < 0 || dword_AA25C >= MAXSOUNDS) + { + Printf("ghsound_ambientlooppoll bad index\n"); + return; + } + if (!A_CheckSoundPlaying(-1, dword_AA25C)) + { + A_PlaySound(dword_AA25C, g_player[screenpeek].ps->i); + } + } +} + +void ghsound_ambientloop(int a1) +{ + switch (a1) + { + case 0: + A_PlaySound(83, g_player[screenpeek].ps->i); + dword_AA25C = 83; + break; + case 1: + S_PlaySound(84); + dword_AA25C = 84; + break; + case 2: + S_PlaySound(85); + dword_AA25C = 85; + break; + default: + dword_AA25C = 0; + break; + } +} + + +int dword_AA260; + +int sub_51B68(void) +{ + int r; + if ((int)totalclock - dword_AA260 < 200) + return 0; + if ((rrdh_random() & 127) != 64) + return 0; + + dword_AA260 = (int)totalclock; + + r = 60 + (rrdh_random() % 15); + S_PlaySound(r); + return r; +} + +int ghsound_pmadecall(spritetype *a1, short a2) +{ + switch (DYNAMICTILEMAP(a1->picnum)) + { + case DOGRUN__STATICRR: + if (A_CheckSoundPlaying(-1, 41)) + return 1; + case VIXEN__STATICRR: + if (A_CheckSoundPlaying(-1, 40)) + return 1; + case PIG__STATICRR: + if (A_CheckSoundPlaying(-1, 42)) + return 1; + case CHEER__STATICRR: + if (A_CheckSoundPlaying(-1, 43)) + return 1; + } + return 0; +} + +int ghsound_pmadesound(spritetype *a1, short a2) +{ + int d = klabs(g_player[a2].ps->pos.x - a1->x) + klabs(g_player[a2].ps->pos.y - a1->y); + if (A_CheckSoundPlaying(-1, 1) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 2)) + return 1; + if (A_CheckSoundPlaying(-1, 3) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 4)) + return 1; + if (A_CheckSoundPlaying(-1, 5) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 6)) + return 1; + if (A_CheckSoundPlaying(-1, 7) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 8) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 56) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 57) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 58) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 59) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 25) && d < 21504) + return 1; + if (A_CheckSoundPlaying(-1, 11) && d < 10752) + return 1; + if (A_CheckSoundPlaying(-1, 9) && d < 15360) + return 1; + if (A_CheckSoundPlaying(-1, 10) && d < 30720) + return 1; + if (A_CheckSoundPlaying(-1, 12) && d < 19968) + return 1; + if (A_CheckSoundPlaying(-1, 15) && d < 10752) + return 1; + if (A_CheckSoundPlaying(-1, 13) && d < 15360) + return 1; + if (A_CheckSoundPlaying(-1, 14) && d < 30720) + return 1; + if (A_CheckSoundPlaying(-1, 16) && d < 19968) + return 1; + if (A_CheckSoundPlaying(-1, 19) && d < 10752) + return 1; + if (A_CheckSoundPlaying(-1, 17) && d < 15360) + return 1; + if (A_CheckSoundPlaying(-1, 18) && d < 30720) + return 1; + if (A_CheckSoundPlaying(-1, 20) && d < 19968) + return 1; + if (A_CheckSoundPlaying(-1, 23) && d < 10752) + return 1; + if (A_CheckSoundPlaying(-1, 21) && d < 15360) + return 1; + if (A_CheckSoundPlaying(-1, 22) && d < 30720) + return 1; + if (A_CheckSoundPlaying(-1, 24) && d < 19968) + return 1; + if (A_CheckSoundPlaying(-1, 81) && d < 15360) + return 1; + if (A_CheckSoundPlaying(-1, 80) && d < 30720) + return 1; + if (A_CheckSoundPlaying(-1, 41) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 40) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 42) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 43) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 88) && d < 10752) + return 1; + if (A_CheckSoundPlaying(-1, 89) && d < 15360) + return 1; + if (A_CheckSoundPlaying(-1, 90) && d < 23040) + return 1; + if (A_CheckSoundPlaying(-1, 27) && d < 30720) + return 1; + if (A_CheckSoundPlaying(-1, 36) && d < 30720) + return 1; + if (A_CheckSoundPlaying(-1, 30) && d < 30720) + return 1; + if (A_CheckSoundPlaying(-1, 33) && d < 30720) + return 1; + return 0; +} + +int ghsound_pfiredgunnear(spritetype *a1, short a2) +{ + if (A_CheckSoundPlaying(-1, 2)) + return 1; + if (A_CheckSoundPlaying(-1, 4)) + return 1; + if (A_CheckSoundPlaying(-1, 6)) + return 1; + if (A_CheckSoundPlaying(-1, 8) && klabs(g_player[a2].ps->pos.x - a1->x) + klabs(g_player[a2].ps->pos.y - a1->y) < 23040) + return 1; + return 0; +} + +int sub_5228C(short a1) +{ + switch (a1) + { + case 998: + case 999: + case 1007: + case 1008: + return 1; + } + return 0; +} + +int sub_522B8(short a1) +{ + switch (a1) + { + case 981: + case 982: + return 1; + } + return 0; +} + +int dword_AA264; + +void ghsound_footstepsound(short a1, int a2) +{ + DukePlayer_t *p; + int i, nexti, d; + spritetype *s; + if (sub_535EC()) + return; + + p = g_player[a1].ps; + if (sector[p->cursectnum].hitag == 2003) + { + if (a2 == 0) + { + if (sub_57A40(5) == 1) + A_PlaySound(81, p->i); + } + else if (a2 == 1) + { + if (sub_57A40(5) == 1) + A_PlaySound(80, p->i); + } + else + { + if (sub_57A40(5) == 1) + A_PlaySound(82, p->i); + } + } + else + { + if (a2 == 0) + { + if (sub_57A40(5) == 1) + { + switch (ud.level_number) + { + case 0: + A_PlaySound(9, p->i); + break; + case 1: + A_PlaySound(13, p->i); + break; + case 2: + A_PlaySound(17, p->i); + break; + case 3: + A_PlaySound(21, p->i); + break; + } + } + } + else if (a2 == 1) + { + if (sub_57A40(5) == 1) + { + switch (ud.level_number) + { + case 0: + A_PlaySound(10, p->i); + break; + case 1: + A_PlaySound(14, p->i); + break; + case 2: + A_PlaySound(18, p->i); + break; + case 3: + A_PlaySound(22, p->i); + break; + } + } + } + else + { + if (sub_57A40(5) == 1) + { + switch (ud.level_number) + { + case 0: + A_PlaySound(11, p->i); + break; + case 1: + A_PlaySound(15, p->i); + break; + case 2: + A_PlaySound(19, p->i); + break; + case 3: + A_PlaySound(23, p->i); + break; + } + } + } + } + i = headspritesect[p->cursectnum]; + while (i >= 0) + { + nexti = nextspritesect[i]; + s = &sprite[i]; + if (sub_5228C(s->picnum) && klabs(p->pos.x - s->x) + klabs(p->pos.y - s->y) < s->clipdist) + { + if (i != dword_AA264) + { + A_PlaySound(25, p->i); + sub_5A250(4096); + dword_AA264 = i; + } + return; + } + else if (sub_522B8(s->picnum) && klabs(p->pos.x - s->x) + klabs(p->pos.y - s->y) < 124) + { + sub_5A250(2048); + } + i = nexti; + } +} + +void ghsound_plrtouchedsprite(short a1, short a2) +{ + DukePlayer_t *p; + spritetype *s; + p = g_player[a2].ps; + + s = &sprite[a1]; + if (rrgh_isatree(a1)) + { + switch (ud.level_number) + { + case 0: + if (!A_CheckSoundPlaying(-1, 12)) + A_PlaySound(12, p->i); + break; + case 1: + if (!A_CheckSoundPlaying(-1, 16)) + A_PlaySound(16, p->i); + break; + case 2: + if (!A_CheckSoundPlaying(-1, 20)) + A_PlaySound(20, p->i); + break; + case 3: + if (!A_CheckSoundPlaying(-1, 24)) + A_PlaySound(24, p->i); + break; + } + } +} + +unsigned short word_AA268[] = { + 9, 10, 11, 12, 25, 35, 36, 37, 41, 60, 61, 62, 63, 64, 80, 81, 82 +}; + +unsigned short word_AA28A[] = { + 13, 14, 15, 16, 25, 26, 27, 28, 32, 33, 34, 40, 43, 65, 66, 67, 68, 69 +}; + +unsigned short word_AA2AE[] = { + 17, 18, 19, 20, 25, 26, 27, 28, 29, 30, 31, 40, 42, 70, 71, 72, 73, 74 +}; + +unsigned short word_AA2D2[] = { + 21, 22, 23, 24, 25, 26, 27, 28, 40, 75, 76, 77, 78, 79 +}; + +void ghsound_preload(int a1) +{ +#if 0 + unsigned short *vsi = NULL, snd; + int i, c; + switch (a1) + { + case 0: + vsi = word_AA268; + c = 17; + break; + case 1: + vsi = word_AA28A; + c = 18; + break; + case 2: + vsi = word_AA2AE; + c = 18; + break; + case 3: + vsi = word_AA2D2; + c = 14; + break; + } + if (vsi) + { + for (i = 0; i < c; i++) + { + snd = vsi[i]; + if (snd >= MAXSOUNDS) + { + Printf("ERROR: ghsound_preload: sndnum out of range\n"); + continue; + } + if (snd > 0 && g_sounds[snd].ptr == NULL) + { + S_LoadSound(snd); + } + } + } + switch (g_player[myconnectindex].ps->dhat61f) + { + case 0: + if (g_sounds[1].ptr == NULL) + { + S_LoadSound(1); + } + if (g_sounds[2].ptr == NULL) + { + S_LoadSound(2); + } + break; + case 1: + case 2: + if (g_sounds[5].ptr == NULL) + { + S_LoadSound(5); + } + if (g_sounds[6].ptr == NULL) + { + S_LoadSound(6); + } + break; + case 3: + if (g_sounds[3].ptr == NULL) + { + S_LoadSound(3); + } + if (g_sounds[4].ptr == NULL) + { + S_LoadSound(4); + } + break; + case 4: + if (g_sounds[7].ptr == NULL) + { + S_LoadSound(7); + } + if (g_sounds[8].ptr == NULL) + { + S_LoadSound(8); + } + break; + } + if (g_sounds[98].ptr == NULL) + { + S_LoadSound(98); + } + if (g_sounds[99].ptr == NULL) + { + S_LoadSound(99); + } + if (g_sounds[100].ptr == NULL) + { + S_LoadSound(100); + } + if (g_sounds[101].ptr == NULL) + { + S_LoadSound(101); + } +#endif +} + +void ghprelvl_randkeep(short a1, unsigned int a2) +{ + short vbx; + int v18 = 0; + unsigned int i, vcx; + while (1) + { + vcx = 0; + for (i = 0; i < MAXSPRITES; i++) + { + if (sprite[i].picnum == a1) + vcx++; + } + if (vcx <= a2) + return; + for (i = 0; i < MAXSPRITES; i++) + { + if (!v18) + vbx = MAXSPRITES - 1 - i; + else + vbx = i; + + if (a1 == sprite[vbx].picnum) + { + if ((rrdh_random() % 256) < 32) + { + sprite[vbx].picnum = 0; + deletesprite(vbx); + vcx--; + if (vcx <= a2) + return; + } + } + } + if (!v18) + v18 = 1; + else + v18 = 0; + } +} + +char sub_52AB8(int a1, int a2) +{ + int vbx = (a1 * a2) / 100; + return (rrdh_random() % vbx) % 256; +} + +int sub_52AF0(short a1) +{ + if (a1 < 0 || a1 >= MAXSPRITES) + return 0; + switch (DYNAMICTILEMAP(sprite[a1].picnum)) + { + case PIG__STATICRR: + case DOGRUN__STATICRR: + case VIXEN__STATICRR: + case CHEER__STATICRR: + case RRTILE1076__STATICRR: + return 1; + } + return 0; +} + +int sub_52B58(short a1) +{ + if (a1 < 0 || a1 >= MAXSPRITES) + return 0; + switch (sprite[a1].picnum) + { + case 976: + case 977: + case 2603: + case 2990: + return 1; + } + return 0; +} + +void sub_52BA8(void) +{ + int v1c, tl, tc; + int i; + short sect; + v1c = 0; + sub_59C20(); + sub_54A2C(); + for (i = 0; i < MAXSPRITES; i++) + { + sprite[i].cstat = 0; + sprite[i].pal = 0; + changespritestat(i, 0); + sect = sprite[i].sectnum; + if (sub_52AF0(i)) + { + if (sect >= 0 && sect < numsectors) + { + if (sector[sect].ceilingheinum == 0 && sector[sect].floorheinum == 0) + { + if (klabs(sprite[i].z - sector[sect].floorz) > 1024 && sprite[i].z < sector[sect].floorz) + { + Printf("NOTICE: deleting floating sprite %i: x=%i, y=%i, z=%i, sect=%i\n", i, sprite[i].pos.x, sprite[i].pos.y, sprite[i].pos.z, sect); + deletesprite(i); + sprite[i].picnum = 0; + sprite[i].cstat = 0; + } + } + } + } + if (sub_52B58(i)) + { + sprite[i].cstat = 1; + sprite[i].clipdist = 8; + } + if (rrgh_isatree(i)) + { + sprite[i].cstat = 1; + sprite[i].xoffset = 0; + sprite[i].yoffset = 0; + sprite[i].clipdist = 8; + } + if (sprite[i].picnum == 998 || sprite[i].picnum == 999 || sprite[i].picnum == 1007 || sprite[i].picnum == 1008) + { + sprite[i].cstat = 32; + sprite[i].clipdist = 127; + } + if (sprite[i].picnum) + { + v1c++; + } + } + ghprelvl_randkeep(PIG, 4); + ghprelvl_randkeep(VIXEN, 4); + ghprelvl_randkeep(DOGRUN, 4); + ghprelvl_randkeep(CHEER, 4); + ghprelvl_randkeep(7065, 64); + + for (i = 0; i < MAXSPRITES; i++) + { + if (sprite[i].picnum == PIG) + { + sprite[i].cstat = 257; + changespritestat(i, 1); + sprite[i].xrepeat = 10 + sub_52AB8(5, 125); + sprite[i].yrepeat = 10 + sub_52AB8(5, 125); + sprite[i].clipdist = mulscale7(sprite[i].xrepeat, tilesiz[sprite[i].picnum].x); + } + if (sprite[i].picnum == VIXEN) + { + sprite[i].cstat = 257; + changespritestat(i, 1); + sprite[i].xrepeat = 14 + sub_52AB8(7, 100); + sprite[i].yrepeat = 14 + sub_52AB8(7, 100); + sprite[i].clipdist = mulscale7(sprite[i].xrepeat, tilesiz[sprite[i].picnum].x); + } + if (sprite[i].picnum == DOGRUN) + { + sprite[i].cstat = 257; + changespritestat(i, 1); + sprite[i].xrepeat = 8 + sub_52AB8(4, 100); + sprite[i].yrepeat = 8 + sub_52AB8(4, 100); + sprite[i].clipdist = mulscale7(sprite[i].xrepeat, tilesiz[sprite[i].picnum].x); + } + if (sprite[i].picnum == CHEER) + { + sprite[i].cstat = 257; + changespritestat(i, 1); + sprite[i].xrepeat = 8 + sub_52AB8(4, 100); + sprite[i].yrepeat = 8 + sub_52AB8(4, 100); + sprite[i].clipdist = mulscale7(sprite[i].xrepeat, tilesiz[sprite[i].picnum].x); + } + if (sprite[i].picnum == 7065) + { + sprite[i].cstat = 0; + sprite[i].z -= rrdh_random() << 3; + changespritestat(i, 801); + } + } + + for (i = 0; i < numwalls; i++) + { + if (wall[i].nextsector != -1) + { + wall[i].cstat &= ~64; + } + } + sub_55F8C(); + sub_566F0(); + sub_558F4(); + sub_56AB8(); + sub_573C0(); + sub_59314(); + ghsound_preload(ud.level_number); + sub_55184(); + sub_57B24(); + sub_58388(); + sub_59B50(); + sub_59F80(ud.level_number); + sub_299C0(); +} + +void sub_53154(int a1) +{ + ghsound_ambientloop(a1); +} + +int dword_AA2F0, dword_AA2F4, dword_AA2F8, dword_AA2FC; + +void sub_53160(int a1) +{ + dword_AA2FC = a1; + dword_AA2F8 = 1; +} + +void sub_53194(void) +{ + switch (dword_AA2F0) + { + case 0: + if (KB_KeyPressed(sc_S)) + { + KB_ClearKeyDown(sc_S); + dword_AA2F0++; + } + break; + case 1: + if (KB_KeyPressed(sc_P)) + { + KB_ClearKeyDown(sc_P); + dword_AA2F0++; + } + break; + case 2: + if (KB_KeyPressed(sc_O)) + { + KB_ClearKeyDown(sc_O); + dword_AA2F0++; + } + break; + case 3: + if (KB_KeyPressed(sc_R)) + { + KB_ClearKeyDown(sc_R); + dword_AA2F0++; + } + break; + case 4: + if (KB_KeyPressed(sc_K)) + { + KB_ClearKeyDown(sc_K); + dword_AA2F0++; + } + break; + case 5: + if (KB_KeyPressed(sc_1)) + { + KB_ClearKeyDown(sc_1); + dword_AA2F0 = 0; + sub_535DC(); + } + if (KB_KeyPressed(sc_2)) + { + KB_ClearKeyDown(sc_2); + dword_AA2F0 = 0; + sub_57AC0(); + } + if (KB_KeyPressed(sc_3)) + { + KB_ClearKeyDown(sc_3); + dword_AA2F0 = 0; + //sub_15224(); + } + break; + } +} + +void sub_53304(void) +{ + //ControlInfo info; + //CONTROL_GetInput(&info); + + if (KB_KeyPressed(sc_RightAlt) || KB_KeyPressed(sc_LeftAlt) || KB_KeyPressed(sc_RightShift) || KB_KeyPressed(sc_LeftShift)) + return; + + sub_53194(); + if (KB_KeyPressed(sc_F1)) + { + KB_ClearKeyDown(sc_F1); + switch (g_player[myconnectindex].ps->dhat61f) + { + case 0: + sub_566E8(); + break; + case 1: + case 2: + sub_55F68(); + break; + case 3: + sub_558D0(); + break; + case 4: + sub_56AB0(); + break; + } + } + if (KB_KeyPressed(sc_F2)) + { + KB_ClearKeyDown(sc_F2); + switch (g_player[myconnectindex].ps->dhat61f) + { + case 0: + sub_56780(); + break; + case 1: + case 2: + sub_56020(); + break; + case 3: + sub_55988(); + break; + case 4: + sub_56B3C(); + break; + } + } + if (KB_KeyPressed(sc_F3)) + { + KB_ClearKeyDown(sc_F3); + switch (g_player[myconnectindex].ps->dhat61f) + { + case 0: + sub_56724(); + break; + case 1: + case 2: + sub_55FCC(); + break; + case 3: + sub_55934(); + break; + case 4: + sub_56AE4(); + break; + } + } + if (KB_KeyPressed(sc_F4)) + { + KB_ClearKeyDown(sc_F4); + ghdeploy_drop(myconnectindex, ud.level_number); + } + if (KB_KeyPressed(sc_F5)) + { + KB_ClearKeyDown(sc_F5); + A_PlaySound(40, g_player[myconnectindex].ps->i); + } + if (KB_KeyPressed(sc_F6)) + { + KB_ClearKeyDown(sc_F6); + A_PlaySound(42, g_player[myconnectindex].ps->i); + } + if (KB_KeyPressed(sc_F7)) + { + KB_ClearKeyDown(sc_F7); + A_PlaySound(41, g_player[myconnectindex].ps->i); + } + if (KB_KeyPressed(sc_F8)) + { + KB_ClearKeyDown(sc_F8); + A_PlaySound(43, g_player[myconnectindex].ps->i); + } + //if (KB_KeyPressed(sc_S)) + //{ + // KB_ClearKeyDown(sc_S); + //} +} + +void sub_535DC(void) +{ + dword_AA2F4 ^= 1; +} + +int sub_535EC(void) +{ + return dword_AA2F4; +} + +int dword_AA300; +int dword_AA304 = 1731; +int dword_AA308, dword_AA30C; + +struct struct2B80E0 { + short f_0; + short f_2; + int f_4; + int f_8; + int f_c; + int f_10; +}; + +struct2B80E0 f2B80E0[20]; + +#pragma pack(push, 1) +typedef struct _scoretype2 { + int f_0; + char f_4; + char f_5; + char f_6; + int f_7; + int f_b; +} scoretype2; + +typedef struct _scoretype { + int f_0; + int f_4; + int f_8; + int f_c; + scoretype2 f_10[5]; +} scoretype; +#pragma pack(pop) + + +scoretype bestscore = { + 0, 0, 0, 0, + 0, 65, 65, 65, 0, 0, + 0, 65, 65, 65, 0, 0, + 0, 65, 65, 65, 0, 0, + 0, 65, 65, 65, 0, 0, + 0, 65, 65, 65, 0, 0, +}; + +unsigned int dword_AA36C, dword_AA370, dword_AA374, dword_AA378, dword_AA37C, dword_AA380; +int dword_AA384; +char byte_AA388 = 65, byte_AA389 = 65, byte_AA38A = 65; +unsigned int dword_AA38C; + +char dword_AA390[43] = " "; + +void ghtrophy_savebestscores(void) +{ + FileWriter *handle; + + FString filename = M_GetDocumentsPath() + "scores"; + + handle = FileWriter::Open(filename); + if (!handle) + { + Printf("ghtrophy_savebestscores: cannot open scores\n"); // this is not an error! + return; + } + if (dword_AA36C > bestscore.f_0) + bestscore.f_0 = dword_AA36C; + if (dword_AA370 > bestscore.f_4) + bestscore.f_4 = dword_AA370; + if (dword_AA374 > bestscore.f_8) + bestscore.f_8 = dword_AA374; + if (dword_AA378 > bestscore.f_c) + bestscore.f_c = dword_AA378; + + if (handle->Write(&bestscore, sizeof(bestscore)) != sizeof(bestscore)) + { + Printf("ghtrophy_savebestscores: error writing scores\n"); + delete handle; + return; + } + delete handle; + dword_AA380 = 0; +} + +void ghtrophy_loadbestscores(void) +{ + FileReader handle; + FString filename = M_GetDocumentsPath() + "scores"; + if (!handle.OpenFile(filename)) + { + // This is not an error. + return; + } + if (handle.Read(&bestscore, sizeof(bestscore)) != sizeof(bestscore)) + { + Printf("ghtrophy_loadbestscores err read scores\n"); + memset(&bestscore, 0, sizeof(bestscore)); + } +} + +int ghtrophy_isakill(short a1) +{ + spritetype *spr = &sprite[a1]; + for (int i = 0; i < dword_AA300; i++) + { + if (f2B80E0[i].f_0 == a1) + return 1; + } + return 0; +} + +int sub_537A8(short a1, int a2) +{ + char va = rrdh_random() & 255; + switch (DYNAMICTILEMAP(a1)) + { + case PIG__STATICRR: + if (a2 == 0 && va > 64) + break; + if (a2 == 6 && va > 80) + break; + if (a2 == 2 && va > 128) + break; + return 1; + case VIXEN__STATICRR: + if (a2 == 6 && va > 128) + break; + return 1; + case CHEER__STATICRR: + return 1; + case DOGRUN__STATICRR: + return 1; + } + return 0; +} + +int sub_5381C(int a1, int a2) +{ + int vbx = (a1 * a2) / 100; + return rrdh_random() % vbx; +} + +void sub_53848(int a1) +{ + dword_AA37C = a1; +} + +void ghtrophy_addkill(int a1) +{ + int v18 = 0, vdi = 0; + spritetype *spr = &sprite[a1]; + + if (ud.level_number > 3) + return; + + if (sprite[a1].cstat & 32768) + return; + + switch (DYNAMICTILEMAP(sprite[a1].picnum)) + { + default: + sub_5A250(4); + break; + case PIG__STATICRR: + case DOGRUN__STATICRR: + case VIXEN__STATICRR: + case CHEER__STATICRR: + if (!ghtrophy_isakill(a1) && sub_537A8(sprite[a1].picnum, v18)) + { + if (dword_AA300 < 20) + { + f2B80E0[dword_AA300].f_0 = a1; + f2B80E0[dword_AA300].f_2 = sprite[a1].picnum; + switch (DYNAMICTILEMAP(sprite[a1].picnum)) + { + case VIXEN__STATICRR: + f2B80E0[dword_AA300].f_4 = (sprite[a1].xrepeat * sprite[a1].yrepeat) / 40; + f2B80E0[dword_AA300].f_4 -= 2; + if (f2B80E0[dword_AA300].f_4 < 2) + f2B80E0[dword_AA300].f_4 = 2; + f2B80E0[dword_AA300].f_4 += 2; + if (f2B80E0[dword_AA300].f_4 > dword_AA36C) + dword_AA36C = f2B80E0[dword_AA300].f_4; + dword_AA308++; + vdi = dword_AA308; + break; + case PIG__STATICRR: + f2B80E0[dword_AA300].f_4 = sprite[a1].xrepeat * sprite[a1].yrepeat; + f2B80E0[dword_AA300].f_4 += sub_5381C(30, 125); + f2B80E0[dword_AA300].f_4 += sub_5381C(10, 100); + if (f2B80E0[dword_AA300].f_4 > 350) + f2B80E0[dword_AA300].f_4 = 350; + if (f2B80E0[dword_AA300].f_4 > dword_AA370) + dword_AA370 = f2B80E0[dword_AA300].f_4; + dword_AA30C++; + vdi = dword_AA30C; + break; + case DOGRUN__STATICRR: + f2B80E0[dword_AA300].f_4 = (sprite[a1].xrepeat * sprite[a1].yrepeat) / 40; + f2B80E0[dword_AA300].f_4 += sub_5381C(4, 125); + f2B80E0[dword_AA300].f_4 -= 3; + if (f2B80E0[dword_AA300].f_4 < 2) + f2B80E0[dword_AA300].f_4 = 2; + dword_AA378++; + vdi = dword_AA378; + break; + case CHEER__STATICRR: + f2B80E0[dword_AA300].f_4 = (sprite[a1].xrepeat * sprite[a1].yrepeat) / 16; + f2B80E0[dword_AA300].f_4 += sub_5381C(10, 125); + if (f2B80E0[dword_AA300].f_4 < 8) + f2B80E0[dword_AA300].f_4 = 8; + dword_AA374++; + vdi = dword_AA374; + break; + } + ghstatbr_registerkillinfo(f2B80E0[dword_AA300].f_2, f2B80E0[dword_AA300].f_4, vdi); + dword_AA300++; + } + sub_5A250(8); + } + break; + } +} + +void ghtrophy_rscopysrcdest(scoretype2 *a1, scoretype2 *a2) +{ + if (!a1 || !a2) + { + Printf("ghtrophy_rscopysrcdest null ptr\n"); + return; + } + a2->f_0 = a1->f_0; + a2->f_4 = a1->f_4; + a2->f_5 = a1->f_5; + a2->f_6 = a1->f_6; +} + +void sub_53C04(void) +{ + scoretype2 v60, v50, v40, v30, v20; + dword_AA380 = 0; + dword_AA384 = 0; + dword_AA38C = (int)totalclock; + if (dword_AA37C > bestscore.f_10[0].f_0) + { + v20.f_0 = dword_AA37C; + ghtrophy_rscopysrcdest(&bestscore.f_10[0], &v50); + ghtrophy_rscopysrcdest(&bestscore.f_10[1], &v30); + ghtrophy_rscopysrcdest(&bestscore.f_10[2], &v40); + ghtrophy_rscopysrcdest(&bestscore.f_10[3], &v60); + dword_AA380 = 1; + } + else if (dword_AA37C > bestscore.f_10[1].f_0) + { + ghtrophy_rscopysrcdest(&bestscore.f_10[0], &v20); + v50.f_0 = dword_AA37C; + ghtrophy_rscopysrcdest(&bestscore.f_10[1], &v30); + ghtrophy_rscopysrcdest(&bestscore.f_10[2], &v40); + ghtrophy_rscopysrcdest(&bestscore.f_10[3], &v60); + dword_AA380 = 2; + } + else if (dword_AA37C > bestscore.f_10[2].f_0) + { + ghtrophy_rscopysrcdest(&bestscore.f_10[0], &v20); + ghtrophy_rscopysrcdest(&bestscore.f_10[1], &v50); + v30.f_0 = dword_AA37C; + ghtrophy_rscopysrcdest(&bestscore.f_10[2], &v40); + ghtrophy_rscopysrcdest(&bestscore.f_10[3], &v60); + dword_AA380 = 3; + } + else if (dword_AA37C > bestscore.f_10[3].f_0) + { + ghtrophy_rscopysrcdest(&bestscore.f_10[0], &v20); + ghtrophy_rscopysrcdest(&bestscore.f_10[1], &v50); + ghtrophy_rscopysrcdest(&bestscore.f_10[2], &v30); + v40.f_0 = dword_AA37C; + ghtrophy_rscopysrcdest(&bestscore.f_10[3], &v60); + dword_AA380 = 4; + } + else if (dword_AA37C > bestscore.f_10[4].f_0) + { + ghtrophy_rscopysrcdest(&bestscore.f_10[0], &v20); + ghtrophy_rscopysrcdest(&bestscore.f_10[1], &v50); + ghtrophy_rscopysrcdest(&bestscore.f_10[2], &v30); + ghtrophy_rscopysrcdest(&bestscore.f_10[3], &v40); + v60.f_0 = dword_AA37C; + dword_AA380 = 5; + } + if (dword_AA380) + { + ghtrophy_rscopysrcdest(&v20, &bestscore.f_10[0]); + ghtrophy_rscopysrcdest(&v50, &bestscore.f_10[1]); + ghtrophy_rscopysrcdest(&v30, &bestscore.f_10[2]); + ghtrophy_rscopysrcdest(&v40, &bestscore.f_10[3]); + ghtrophy_rscopysrcdest(&v60, &bestscore.f_10[4]); + } +} + +void sub_53E18(void) +{ + sub_53C04(); + if (dword_AA380) + { + sub_53160(300); + } +} + +void sub_53E4C(vec2_t const origin) +{ + int v20 = 0, v1c, v18, vsi, vdi; + char val; + val = sub_54B80(); + if (val & 32) + { + v20 = 1; + switch (dword_AA384) + { + case 0: + byte_AA388 = val; + break; + case 1: + byte_AA389 = val; + break; + case 2: + byte_AA38A = val; + break; + } + } + + v1c = 0; + if ((int)totalclock - dword_AA38C > 30) + { + v1c = 1; + dword_AA38C = (int)totalclock; + } + + v18 = 18; + vsi = 100; + vdi = 44; + + menutext_(origin.x+(160<<16), origin.y+(22<<16), 0, "TOP FIVE", 10|16, TEXT_XCENTER); + + if (dword_AA380) + { + if (!v1c || dword_AA384 != 0) + { + sprintf(dword_AA390, "%c", byte_AA388); + gametext_simple(origin.x+(vsi<<16), origin.y+((vdi+v18*(dword_AA380-1))<<16), dword_AA390); + } + if (!v1c || dword_AA384 != 1) + { + sprintf(dword_AA390, "%c", byte_AA389); + gametext_simple(origin.x+((vsi+14)<<16), origin.y+((vdi+v18*(dword_AA380-1))<<16), dword_AA390); + } + if (!v1c || dword_AA384 != 2) + { + sprintf(dword_AA390, "%c", byte_AA38A); + gametext_simple(origin.x+((vsi+28)<<16), origin.y+((vdi+v18*(dword_AA380-1))<<16), dword_AA390); + } + switch (dword_AA380) + { + case 1: + bestscore.f_10[0].f_4 = byte_AA388; + bestscore.f_10[0].f_5 = byte_AA389; + bestscore.f_10[0].f_6 = byte_AA38A; + break; + case 2: + bestscore.f_10[1].f_4 = byte_AA388; + bestscore.f_10[1].f_5 = byte_AA389; + bestscore.f_10[1].f_6 = byte_AA38A; + break; + case 3: + bestscore.f_10[2].f_4 = byte_AA388; + bestscore.f_10[2].f_5 = byte_AA389; + bestscore.f_10[2].f_6 = byte_AA38A; + break; + case 4: + bestscore.f_10[3].f_4 = byte_AA388; + bestscore.f_10[3].f_5 = byte_AA389; + bestscore.f_10[3].f_6 = byte_AA38A; + break; + case 5: + bestscore.f_10[4].f_4 = byte_AA388; + bestscore.f_10[4].f_5 = byte_AA389; + bestscore.f_10[4].f_6 = byte_AA38A; + break; + } + } + if (dword_AA380 != 1) + { + sprintf(dword_AA390, "%c", bestscore.f_10[0].f_4); + gametext_simple(origin.x+(vsi<<16), origin.y+(vdi<<16), dword_AA390); + sprintf(dword_AA390, "%c", bestscore.f_10[0].f_5); + gametext_simple(origin.x+((vsi+14)<<16), origin.y+(vdi<<16), dword_AA390); + sprintf(dword_AA390, "%c", bestscore.f_10[0].f_6); + gametext_simple(origin.x+((vsi+28)<<16), origin.y+(vdi<<16), dword_AA390); + } + sprintf(dword_AA390, "%5d", bestscore.f_10[0].f_0); + gametext_simple(origin.x+((vsi+74)<<16), origin.y+(vdi<<16), dword_AA390); + if (dword_AA380 != 2) + { + sprintf(dword_AA390, "%c", bestscore.f_10[1].f_4); + gametext_simple(origin.x+(vsi<<16), origin.y+((vdi+v18)<<16), dword_AA390); + sprintf(dword_AA390, "%c", bestscore.f_10[1].f_5); + gametext_simple(origin.x+((vsi+14)<<16), origin.y+((vdi+v18)<<16), dword_AA390); + sprintf(dword_AA390, "%c", bestscore.f_10[1].f_6); + gametext_simple(origin.x+((vsi+28)<<16), origin.y+((vdi+v18)<<16), dword_AA390); + } + sprintf(dword_AA390, "%5d", bestscore.f_10[1].f_0); + gametext_simple(origin.x+((vsi+74)<<16), origin.y+((vdi+v18)<<16), dword_AA390); + if (dword_AA380 != 3) + { + sprintf(dword_AA390, "%c", bestscore.f_10[2].f_4); + gametext_simple(origin.x+(vsi<<16), origin.y+((vdi+v18*2)<<16), dword_AA390); + sprintf(dword_AA390, "%c", bestscore.f_10[2].f_5); + gametext_simple(origin.x+((vsi+14)<<16), origin.y+((vdi+v18*2)<<16), dword_AA390); + sprintf(dword_AA390, "%c", bestscore.f_10[2].f_6); + gametext_simple(origin.x+((vsi+28)<<16), origin.y+((vdi+v18*2)<<16), dword_AA390); + } + sprintf(dword_AA390, "%5d", bestscore.f_10[2].f_0); + gametext_simple(origin.x+((vsi+74)<<16), origin.y+((vdi+v18*2)<<16), dword_AA390); + if (dword_AA380 != 4) + { + sprintf(dword_AA390, "%c", bestscore.f_10[3].f_4); + gametext_simple(origin.x+(vsi<<16), origin.y+((vdi+v18*3)<<16), dword_AA390); + sprintf(dword_AA390, "%c", bestscore.f_10[3].f_5); + gametext_simple(origin.x+((vsi+14)<<16), origin.y+((vdi+v18*3)<<16), dword_AA390); + sprintf(dword_AA390, "%c", bestscore.f_10[3].f_6); + gametext_simple(origin.x+((vsi+28)<<16), origin.y+((vdi+v18*3)<<16), dword_AA390); + } + sprintf(dword_AA390, "%5d", bestscore.f_10[3].f_0); + gametext_simple(origin.x+((vsi+74)<<16), origin.y+((vdi+v18*3)<<16), dword_AA390); + if (dword_AA380 != 5) + { + sprintf(dword_AA390, "%c", bestscore.f_10[4].f_4); + gametext_simple(origin.x+(vsi<<16), origin.y+((vdi+v18*4)<<16), dword_AA390); + sprintf(dword_AA390, "%c", bestscore.f_10[4].f_5); + gametext_simple(origin.x+((vsi+14)<<16), origin.y+((vdi+v18*4)<<16), dword_AA390); + sprintf(dword_AA390, "%c", bestscore.f_10[4].f_6); + gametext_simple(origin.x+((vsi+28)<<16), origin.y+((vdi+v18*4)<<16), dword_AA390); + } + sprintf(dword_AA390, "%5d", bestscore.f_10[4].f_0); + gametext_simple(origin.x+((vsi+74)<<16), origin.y+((vdi+v18*4)<<16), dword_AA390); + + if (KB_KeyPressed(sc_LeftArrow) || KB_KeyPressed(sc_kpad_4)) + { + KB_ClearKeyDown(sc_LeftArrow); + KB_ClearKeyDown(sc_kpad_4); + dword_AA384--; + } + else if (v20 || KB_KeyPressed(sc_RightArrow) || KB_KeyPressed(sc_kpad_6)) + { + KB_ClearKeyDown(sc_RightArrow); + KB_ClearKeyDown(sc_kpad_6); + dword_AA384++; + } + if (dword_AA384 < 0) + dword_AA384 = 0; + if (dword_AA384 > 2) + dword_AA384 = 0; + if (dword_AA380) + { + gametext_simple(origin.x+(86<<16), origin.y+(146<<16), "PRESS ESC WHEN DONE"); + } +} + +void sub_5469C(vec2_t const origin, int a1) +{ + unsigned int v20, v1c, v18, v24, vdi, t; + if (a1 == 2) + { + sub_53E4C(origin); + return; + } + rotatesprite_fs(origin.x+(160<<16), origin.y, 65536, 0, dword_AA304, 0, 0, 64+16+10); + if (a1 == 1) + { + v20 = bestscore.f_0; + v1c = bestscore.f_4; + v18 = bestscore.f_c; + v24 = bestscore.f_10[0].f_0; + vdi = bestscore.f_8; + } + else + { + v20 = dword_AA36C; + v1c = dword_AA370; + v18 = dword_AA378; + v24 = dword_AA37C; + vdi = dword_AA374; + } + if (v20 > 0) + { + rotatesprite_fs(origin.x+(4<<16), origin.y, 36864, 0, 1741, 0, 0, 16+10); + } + if (v1c > 0) + { + rotatesprite_fs(origin.x+(98<<16), origin.y+(6<<16), 36864, 0, 1740, 0, 0, 16+10); + } + if (vdi > 0) + { + rotatesprite_fs(origin.x+(172<<16), origin.y+(128<<16), 28576, 0, 1743, 0, 0, 16+10); + } + if (v18 > 0) + { + rotatesprite_fs(origin.x+(232<<16), origin.y+(128<<16), 28576, 0, 1742, 0, 0, 16+10); + } + if (a1 == 0) + gametext_simple(origin.x+(4<<16), origin.y+(104<<16), "SO FAR IN THIS HUNTIN' TRIP..."); + else + gametext_simple(origin.x+(4<<16), origin.y+(104<<16), "YOUR BEST TOTALS TO DATE..."); + + sprintf(dword_AA390, "BEST DEER: %2d PTS", v20); + gametext_simple(origin.x+(8<<16), origin.y+(122<<16), dword_AA390); + sprintf(dword_AA390, "BEST BOAR: %3d LB", v1c); + gametext_simple(origin.x+(8<<16), origin.y+(136<<16), dword_AA390); + sprintf(dword_AA390, "MOST TURKEYS: %2d ", vdi); + gametext_simple(origin.x+(8<<16), origin.y+(150<<16), dword_AA390); + sprintf(dword_AA390, "MOST DUCKS: %2d ", v18); + gametext_simple(origin.x+(8<<16), origin.y+(164<<16), dword_AA390); + if (a1 == 0) + { + t = dword_AA308 + dword_AA30C + v18; + if (t > 6) + gametext_simple(origin.x+(8<<16), origin.y+(182<<16), "YEAH BABY !"); + else if (t > 4) + gametext_simple(origin.x+(8<<16), origin.y+(182<<16), "NICE WORK !"); + else if (t > 1) + gametext_simple(origin.x+(8<<16), origin.y+(182<<16), "GOOD JOB !"); + else + gametext_simple(origin.x+(8<<16), origin.y+(182<<16), "KEEP TRYIN' !"); + } + else + { + sprintf(dword_AA390, "BEST RANGE SCORE: %5d", v24); + gametext_simple(origin.x+(8<<16), origin.y+(182<<16), dword_AA390); + } +} + +void sub_54A2C(void) +{ + int i; + dword_AA300 = 0; + dword_AA304 = 1731+(rrdh_random()%6); + dword_AA308 = 0; + dword_AA30C = 0; + for (i = 0; i < 20; i++) + { + f2B80E0[i].f_0 = -1; + f2B80E0[i].f_2 = 0; + f2B80E0[i].f_4 = 0; + f2B80E0[i].f_8 = 0; + f2B80E0[i].f_c = 0; + f2B80E0[i].f_10 = 0; + } + dword_AA36C = 0; + dword_AA370 = 0; + dword_AA374 = 0; + dword_AA378 = 0; + dword_AA37C = 0; + dword_AA380 = 0; + dword_AA384 = 0; + byte_AA388 = 65; + byte_AA389 = 65; + byte_AA38A = 65; + dword_AA38C = 0; + ghtrophy_loadbestscores(); +} + +char sub_54B80(void) +{ +#if 0 + switch (KB_GetLastScanCode()) + { + case sc_A: + KB_SetLastScanCode(sc_None); + return 'A'; + case sc_B: + KB_SetLastScanCode(sc_None); + return 'B'; + case sc_C: + KB_SetLastScanCode(sc_None); + return 'C'; + case sc_D: + KB_SetLastScanCode(sc_None); + return 'D'; + case sc_E: + KB_SetLastScanCode(sc_None); + return 'E'; + case sc_F: + KB_SetLastScanCode(sc_None); + return 'F'; + case sc_G: + KB_SetLastScanCode(sc_None); + return 'G'; + case sc_H: + KB_SetLastScanCode(sc_None); + return 'H'; + case sc_I: + KB_SetLastScanCode(sc_None); + return 'I'; + case sc_J: + KB_SetLastScanCode(sc_None); + return 'J'; + case sc_K: + KB_SetLastScanCode(sc_None); + return 'K'; + case sc_L: + KB_SetLastScanCode(sc_None); + return 'L'; + case sc_M: + KB_SetLastScanCode(sc_None); + return 'M'; + case sc_N: + KB_SetLastScanCode(sc_None); + return 'N'; + case sc_O: + KB_SetLastScanCode(sc_None); + return 'O'; + case sc_P: + KB_SetLastScanCode(sc_None); + return 'P'; + case sc_Q: + KB_SetLastScanCode(sc_None); + return 'Q'; + case sc_R: + KB_SetLastScanCode(sc_None); + return 'R'; + case sc_S: + KB_SetLastScanCode(sc_None); + return 'S'; + case sc_T: + KB_SetLastScanCode(sc_None); + return 'T'; + case sc_U: + KB_SetLastScanCode(sc_None); + return 'U'; + case sc_V: + KB_SetLastScanCode(sc_None); + return 'V'; + case sc_W: + KB_SetLastScanCode(sc_None); + return 'W'; + case sc_X: + KB_SetLastScanCode(sc_None); + return 'X'; + case sc_Y: + KB_SetLastScanCode(sc_None); + return 'Y'; + case sc_Z: + KB_SetLastScanCode(sc_None); + return 'Z'; + default: + KB_SetLastScanCode(sc_None); + return ' '; + } +#endif + return 0; +} + +char byte_AA394[6] = { 0, 1, 2, 3, 2, 1 }; + +int dword_AA39C, dword_AA3A0, dword_AA3A4, dword_AA3A8, dword_AA3AC, dword_AA3B0, dword_AA3B4, dword_AA3B8, dword_AA3BC, dword_AA3C0, dword_AA3C4; + +void sub_54D90(void) +{ + rotatesprite(160<<16, 100<<16, 32768, 0, 7063, -24, 0, 32+2+1, windowxy1.x, windowxy1.y, windowxy2.x, windowxy2.y); +} + +void sub_54DE0(void) +{ + dword_AA3A8 = tilesiz[7050].x; + dword_AA3AC = tilesiz[7050].y; +#if 0 + tileCreate(7050, dword_AA3A8, dword_AA3AC); +#endif +} + +void ghrender_preparescope(void) +{ +#if 0 + int delta, i, j; + char *ptr; + dword_AA3A4 = 0; + if (!waloff[7050]) + return; + dword_AA3B4 = windowxy2.x - windowxy1.x + 1; + dword_AA3B8 = windowxy2.y - windowxy1.y + 1; + if (dword_AA3B4 <= dword_AA3A8 || dword_AA3B8 <= dword_AA3AC) + return; + delta = bytesperline - dword_AA3B4; + if (delta < 0) + G_GameExit("ghrender_preparescope: delta < 0"); + delta /= 2; + + dword_AA3B0 = (dword_AA3B8 * bytesperline) / 2; + dword_AA3B0 -= (bytesperline >> 1); + dword_AA3B0 -= delta; + dword_AA3B0 -= (dword_AA3AC >> 1) * bytesperline; + dword_AA3B0 -= (dword_AA3A8 >> 1); + tileCopySection(7051, 0, 0, tilesiz[7051].x, tilesiz[7051].y, 7050, 0, 0); + ptr = (char*)waloff[7050]; + if (ptr) + { + for (i = 0; i < dword_AA3A8; i++) + { + for (j = 0; j < dword_AA3AC; j++) + { + if (*ptr == 0) + *ptr = 255; + ptr++; + } + } + dword_AA3A4 = 1; + } +#endif +} + +void sub_54FA4(int a1, int a2) +{ + int i, j; + char *ptr1, *ptr2; + if (videoGetRenderMode() >= REND_POLYMOST) + return; +#if 0 + if (!dword_AA3A4) + ghrender_preparescope(); + ptr1 = (char*)waloff[7050]; + if (!ptr1) + return; + ptr2 = (char*)frameplace; + if (!ptr2) + return; + for (i = 0; i < dword_AA3A8; i++) + { + for (j = 0; j < dword_AA3AC; j++) + { + if (*ptr1 != TRANSPARENT_INDEX) + { + *ptr1 = ptr2[i*bytesperline+dword_AA3B0+j]; + } + ptr1++; + } + } + rotatesprite(a1<<16, a2<<16, 57344, 512, 7050, 0, 0, 4+2, windowxy1.x, windowxy1.y, windowxy2.x, windowxy2.y); + rotatesprite(a1<<16, a2<<16, 57344, 512, 7050, -8, 0, 4+2+1, windowxy1.x, windowxy1.y, windowxy2.x, windowxy2.y); + rotatesprite(a1<<16, a2<<16, 32768, 0, 7063, -24, 0, 32+2+1, windowxy1.x, windowxy1.y, windowxy2.x, windowxy2.y); +#endif +} + +typedef struct _struct2B8280 { + short f_0; + char f_2; +} struct2B8280; + +struct2B8280 f2B8280[MAXSPRITES]; + +void sub_550F0(void) +{ + int i, sect; + dword_AA3A0 = 0; + for (i = 0; i < MAXSPRITES; i++) + { + f2B8280[i].f_0 = -1; + sect = sprite[i].sectnum; + if (sect >= 0 && sect < numsectors) + { + if (sprite[i].cstat & 2) + { + if (sector[sect].floorstat & 1) + { + f2B8280[dword_AA3A0].f_2 = sprite[i].xrepeat; + f2B8280[dword_AA3A0].f_0 = i; + dword_AA3A0++; + } + } + } + } + dword_AA39C = 0; +} + +void ghrender_movewatersprites(void) +{ + int i, spr; + if (!sub_57AA0(2)) + return; + for (i = 0; i < dword_AA3A0; i++) + { + spr = f2B8280[i].f_0; + if (spr < 0 || spr >= MAXSPRITES) + { + Printf("ghrender_movewatersprites: bad watersprite sprnum\n"); + continue; + } + if (dword_AA39C < 0 || dword_AA39C >= 6) + { + Printf("ghrender_movewatersprites: currepeat out of range\n"); + continue; + } + sprite[spr].xrepeat = f2B8280[i].f_2 + byte_AA394[dword_AA39C]; + } + dword_AA39C++; + if (dword_AA39C >= 6) + dword_AA39C = 0; +} + +typedef struct _structAA3D0 { + unsigned int f_0; + int f_4; + int f_8; + int f_c; + int f_10; +} structAA3D0; + +void sub_55244(void) +{ +} + +void sub_5524C(void) +{ +} + +void sub_55184(void) +{ + sub_550F0(); +} + +structAA3D0 fAA3D0[15] = { + 1, 2860, 136, 152, 0, + 10, 2861, 136, 142, 2, + 10, 2862, 136, 142, 5, + 10, 2862, 136, 142, 4, + 10, 2861, 136, 142, 0, + 4, 2863, 144, 162, 5, + 16, 2864, 204, 160, 5, + 22, 2865, 136, 142, 8, + 22, 2869, 136, 142, 9, + 22, 2868, 136, 142, 10, + 18, 2865, 136, 142, 5, + 22, 2865, 136, 142, 12, + 22, 2866, 136, 142, 13, + 22, 2867, 136, 142, 14, + 18, 2865, 136, 142, 5 +}; + +int ghshtgn_setmode(int a1) +{ + if (a1 < 0 || a1 >= 15) + return -1; + if (dword_AA3BC != a1) + { + if ((int)totalclock - dword_AA3C4 > fAA3D0[dword_AA3BC].f_0) + { + switch (dword_AA3BC) + { + case 7: + case 11: + A_PlaySound(3, g_player[myconnectindex].ps->i); + break; + case 10: + case 14: + dword_AA3C0 = 1; + break; + case 6: + dword_AA3C0 = 0; + break; + } + dword_AA3C4 = (int)totalclock; + dword_AA3BC = a1; + } + } + return dword_AA3BC; +} + +int dword_2BB290[MAXSECTORS]; + +int dword_AA3C8, dword_AA3CC; + +int hitscan_old(int xs, int ys, int zs, int16_t sectnum, int xv, int yv, int zv, int16_t *hitsect, int16_t *hitwall, int16_t *hitsprite, + int *xh, int *yh, int *zh, int cm) +{ + vec3_t s = { xs, ys, zs }; + hitdata_t h = { *xh, *yh, *zh, *hitsprite, *hitwall, *hitsect }; + int ret = hitscan(&s, sectnum, xv, yv, zv, &h, cm); + *xh = h.pos.x; + *yh = h.pos.y; + *zh = h.pos.z; + *hitsprite = h.sprite; + *hitwall = h.wall; + *hitsect = h.sect; + return ret; +} + +void ghshtgn_fire(short snum) +{ + DukePlayer_t *p; + short v20 = 0; + short v1c = 0; + short v18 = 0; + int v44 = 0; + int v48 = 0; + int v4c = 0; + int v34, v28, v40, v2c, v24, v38, vdx, vax, vbx, vdi, v3c, v30, i; + short sect; + if (!dword_AA3C0 && dword_AA3BC == 5) + sub_5A250(0x10); + + if (dword_AA3BC == 5 && dword_AA3C0 && ghshtgn_setmode(6) == 6) + { + p = g_player[snum].ps; + A_PlaySound(4, p->i); + v34 = 9; + while (v34 > 0) + { + v28 = p->pos.x; + v40 = p->pos.y; + v2c = p->pos.z + p->pyoff; + if (dword_AA3C8 == 7) + { + vax = 2; + vbx = 4; + v24 = 8; + vdx = 2048; + v38 = 4096; + } + else + { + vax = 2; + vbx = 2; + v24 = 4; + vdx = 512; + v38 = 1024; + } + vdi = (100 - fix16_to_int(p->q16horiz)) * 2048; + switch (v34) + { + default: + return; + case 9: + v3c = sintable[(fix16_to_int(p->q16ang) + vax - vbx + 512) & 2047]; + v30 = sintable[(fix16_to_int(p->q16ang) + vax - vbx) & 2047]; + vdi += vdx; + break; + case 8: + v3c = sintable[(fix16_to_int(p->q16ang) + vax + vbx + 512) & 2047]; + v30 = sintable[(fix16_to_int(p->q16ang) + vax + vbx) & 2047]; + vdi += vdx; + break; + case 7: + v3c = sintable[(fix16_to_int(p->q16ang) + vax - vbx + 512) & 2047]; + v30 = sintable[(fix16_to_int(p->q16ang) + vax - vbx) & 2047]; + vdi -= vdx; + break; + case 6: + v3c = sintable[(fix16_to_int(p->q16ang) + vax + vbx + 512) & 2047]; + v30 = sintable[(fix16_to_int(p->q16ang) + vax + vbx) & 2047]; + vdi -= vdx; + break; + case 5: + v3c = sintable[(fix16_to_int(p->q16ang) + vax + 512) & 2047]; + v30 = sintable[(fix16_to_int(p->q16ang) + vax) & 2047]; + vdi -= v38; + break; + case 4: + v3c = sintable[(fix16_to_int(p->q16ang) + vax + 512) & 2047]; + v30 = sintable[(fix16_to_int(p->q16ang) + vax) & 2047]; + vdi += v38; + break; + case 3: + v3c = sintable[(fix16_to_int(p->q16ang) + vax - v24 + 512) & 2047]; + v30 = sintable[(fix16_to_int(p->q16ang) + vax - v24) & 2047]; + break; + case 2: + v3c = sintable[(fix16_to_int(p->q16ang) + vax + v24 + 512) & 2047]; + v30 = sintable[(fix16_to_int(p->q16ang) + vax + v24) & 2047]; + break; + case 1: + v3c = sintable[(fix16_to_int(p->q16ang) + vax + 512) & 2047]; + v30 = sintable[(fix16_to_int(p->q16ang) + vax) & 2047]; + break; + } + for (i = 0; i < numsectors; i++) + { + dword_2BB290[i] = sector[i].ceilingz; + sector[i].ceilingz = -0x64000; + } + hitscan_old(v28, v40, v2c, p->cursectnum, v3c, v30, vdi, &v20, &v18, &v1c, &v44, &v48, &v4c, CLIPMASK1); + for (i = 0; i < numsectors; i++) + { + sector[i].ceilingz = dword_2BB290[i]; + } + v34--; + if (v20 < 0) + { + Printf("WARNING: ghshtgn_fire hitsect < 0\n"); + return; + } + sub_51678(v18, v1c, v20, v44, v48, v4c); + if (v1c >= 0) + { + if (sprite[v1c].cstat == 32768) + { + Printf("ERROR: hit spr with cstat 32768\n"); + return; + } + sect = sprite[v1c].sectnum; + if (sector[sect].hitag == 2000) + { + Printf("ERROR: hit spr in REST_AREA sector\n"); + return; + } + ghtrophy_addkill(v1c); + ghtarget_hit(v1c, dword_AA3C8); + } + else + sub_5A250(4); + } + } +} + +void sub_558D0(void) +{ + if (!dword_AA3BC) + ghshtgn_setmode(1); + else + ghshtgn_setmode(3); +} + +void sub_558F4(void) +{ + dword_AA3CC = 1; + ghshtgn_setmode(0); + dword_AA3C8 = 6; + dword_AA3C0 = 0; +} + +int sub_55928(void) +{ + return dword_AA3C8; +} + +void sub_55934(void) +{ + if (dword_AA3BC == 0 || dword_AA3BC == 5) + { + sub_5A250(0x4000); + dword_AA3C0 = 0; + sub_55988(); + dword_AA3C8 = 6 + (dword_AA3C8 == 6); + } +} + +void sub_55988(void) +{ + int pframe; + if (dword_AA3BC == 0 || dword_AA3BC == 5) + { + pframe = dword_AA3BC; + if (dword_AA3CC) + { + if (ghshtgn_setmode(7) == 7) + fAA3D0[10].f_10 = pframe; + dword_AA3CC = 0; + } + else + { + if (ghshtgn_setmode(11) == 11) + fAA3D0[14].f_10 = pframe; + } + } +} + +unsigned int dword_AA53C; +int dword_AA540; + +int dword_AA4FC[] = { + 0, -1, -2, -3, -4, -3, -2, -1 +}; + +int dword_AA51C[] = { + 0, -1, -2, -2, -1, -2, -2, -1 +}; + +void ghshtgn_render(short snum) +{ + int vdx; + if (dword_AA3BC < 0 || dword_AA3BC >= 15) + { + Printf("ERROR: ghshtgn_draw bad index\n"); + return; + } + if (snum < 0 || snum >= numplayers) + { + Printf("ERROR: ghshtgn_render bad index\n"); + return; + } + DukePlayer_t* p = g_player[snum].ps; + if (p->dhat613 || p->dhat617) + { + vdx = 10; + if (p->dhat617) + vdx = 5; + if ((int)totalclock - dword_AA53C > vdx) + { + dword_AA540++; + if (dword_AA540 >= 8) + dword_AA540 = 0; + dword_AA53C = (int)totalclock; + } + } + else + { + if (dword_AA540) + dword_AA540++; + if (dword_AA540 >= 8) + dword_AA540 = 0; + } + if (dword_AA540 >= 8) + { + Printf("ERROR: ghshtgn_render bobcnt out of bounds\n"); + return; + } + sub_54D90(); + rotatesprite_win((fAA3D0[dword_AA3BC].f_8+dword_AA4FC[dword_AA540])<<16, + (fAA3D0[dword_AA3BC].f_c+dword_AA51C[dword_AA540]+17)<<16, 40960, + 0, fAA3D0[dword_AA3BC].f_4, 0, 0, 2); + if (dword_AA3BC == 5 && p->dhat617) + ghshtgn_setmode(3); + else + ghshtgn_setmode(fAA3D0[dword_AA3BC].f_10); +} + +int dword_AA544, dword_AA548; +unsigned int dword_AA54C; + +structAA3D0 fAA558[17] = { + 1, 2816, 135, 152, 0, + 10, 2822, 135, 132, 2, + 10, 2817, 135, 132, 5, + 10, 2817, 135, 132, 4, + 10, 2822, 135, 132, 0, + 4, 2818, 144, 130, 5, + 16, 2819, 144, 130, 5, + 28, 2817, 135, 132, 8, + 28, 2823, 135, 132, 9, + 28, 2824, 135, 132, 10, + 28, 2823, 135, 132, 11, + 28, 2817, 135, 132, 5, + 28, 2817, 135, 132, 13, + 28, 2820, 135, 132, 14, + 28, 2821, 135, 132, 15, + 28, 2823, 135, 132, 16, + 28, 2817, 135, 132, 5 +}; + +structAA3D0 fAA6AC[17] = { + 1, 2830, 135, 152, 0, + 10, 2831, 135, 132, 2, + 10, 2832, 135, 132, 5, + 10, 2832, 135, 132, 4, + 10, 2831, 135, 132, 0, + 4, 2833, 146, 136, 5, + 16, 2834, 146, 136, 5, + 28, 2832, 135, 132, 8, + 28, 2837, 135, 132, 9, + 28, 2838, 135, 132, 10, + 28, 2837, 135, 132, 11, + 28, 2832, 135, 132, 5, + 28, 2832, 135, 132, 13, + 28, 2836, 135, 132, 14, + 28, 2835, 135, 132, 15, + 28, 2837, 135, 132, 16, + 28, 2832, 135, 132, 5 +}; + +int ghrifle_setmode(int a1) +{ + if (a1 < 0 || a1 >= 17) + return -1; + if (dword_AA544 != a1) + { + if ((int)totalclock - dword_AA54C > fAA558[dword_AA544].f_0) + { + switch (dword_AA544) + { + case 7: + case 12: + A_PlaySound(5, g_player[myconnectindex].ps->i); + break; + case 11: + case 16: + dword_AA548 = 1; + break; + case 6: + dword_AA548 = 0; + break; + } + dword_AA54C = (int)totalclock; + dword_AA544 = a1; + } + } + return dword_AA544; +} + +int dword_2BC2A0[MAXSECTORS]; +int dword_AA550, dword_AA554; + +void ghrifle_fire(short snum) +{ + DukePlayer_t *p; + short v20 = 0; + short v1c = 0; + short v18 = 0; + int v44 = 0; + int v48 = 0; + int v4c = 0; + int v28, v40, v2c, vdi, v3c, v30, i; + short sect; + if (!dword_AA548 && dword_AA544 == 5) + sub_5A250(0x10); + + if (dword_AA548 && dword_AA544 == 5 && ghrifle_setmode(6) == 6) + { + p = g_player[snum].ps; + A_PlaySound(6, p->i); + v28 = p->pos.x; + v40 = p->pos.y; + v2c = p->pos.z + p->pyoff; + v3c = sintable[(fix16_to_int(p->q16ang) + 512) & 2047]; + v30 = sintable[(fix16_to_int(p->q16ang)) & 2047]; + vdi = (100 - fix16_to_int(p->q16horiz)) * 2048; + for (i = 0; i < numsectors; i++) + { + dword_2BC2A0[i] = sector[i].ceilingz; + sector[i].ceilingz = -0x64000; + } + hitscan_old(v28, v40, v2c, p->cursectnum, v3c, v30, vdi, &v20, &v18, &v1c, &v44, &v48, &v4c, CLIPMASK1); + for (i = 0; i < numsectors; i++) + { + sector[i].ceilingz = dword_2BC2A0[i]; + } + if (v20 < 0) + { + Printf("WARNING: ghrifle_fire hitsect < 0\n"); + return; + } + sub_51678(v18, v1c, v20, v44, v48, v4c); + if (v1c >= 0) + { + if (sprite[v1c].cstat == 32768) + { + Printf("ERROR: hit spr with cstat 32768\n"); + return; + } + sect = sprite[v1c].sectnum; + if (sector[sect].hitag == 2000) + { + Printf("ERROR: hit spr in REST_AREA sector\n"); + return; + } + ghtrophy_addkill(v1c); + ghtarget_hit(v1c, dword_AA550); + } + else + sub_5A250(4); + } +} + +void sub_55F68(void) +{ + if (dword_AA544 == 0) + ghrifle_setmode(1); + else + ghrifle_setmode(3); +} + +void sub_55F8C(void) +{ + dword_AA554 = 1; + ghrifle_setmode(0); + dword_AA550 = 4; + dword_AA548 = 0; +} + +int sub_55FC0(void) +{ + return dword_AA550; +} + +void sub_55FCC(void) +{ + if (dword_AA544 == 0 || dword_AA544 == 5) + { + sub_5A250(0x4000); + dword_AA548 = 0; + sub_56020(); + dword_AA550 = 4 + (dword_AA550 == 4); + } +} + +void sub_56020(void) +{ + int pframe; + if (dword_AA544 == 0 || dword_AA544 == 5) + { + pframe = dword_AA544; + if (dword_AA554) + { + if (ghrifle_setmode(7) == 7) + fAA558[11].f_10 = pframe; + dword_AA554 = 0; + } + else + { + if (ghrifle_setmode(12) == 12) + fAA558[16].f_10 = pframe; + } + } +} + +unsigned int dword_AA840; +int dword_AA844; + +int dword_AA800[] = { + 0, -1, -2, -3, -4, -3, -2, -1 +}; + +int dword_AA820[] = { + 0, -1, -2, -2, -1, -2, -2, -1 +}; + +void ghrifle_render(short snum, int a2) +{ + int vdx, tile, x, y; + if (dword_AA544 < 0 || dword_AA544 >= 17) + { + Printf("ERROR: ghrifle_draw bad index\n"); + return; + } + if (snum < 0 || snum >= numplayers) + { + Printf("ERROR: ghrifle_render bad index\n"); + return; + } + DukePlayer_t* p = g_player[snum].ps; + if (p->dhat613 || p->dhat617) + { + vdx = 10; + if (p->dhat617) + vdx = 5; + if ((int)totalclock - dword_AA840 > vdx) + { + dword_AA844++; + if (dword_AA844 >= 8) + dword_AA844 = 0; + dword_AA840 = (int)totalclock; + } + } + else + { + if (dword_AA844) + dword_AA844++; + if (dword_AA844 >= 8) + dword_AA844 = 0; + } + if (dword_AA844 >= 8) + { + Printf("ERROR: ghrifle_render bobcnt out of bounds\n"); + return; + } + + if (a2 == 1) + { + x = fAA558[dword_AA544].f_8 + dword_AA800[dword_AA844]; + y = fAA558[dword_AA544].f_c + dword_AA820[dword_AA844] + 17; + tile = fAA558[dword_AA544].f_4; + } + else + { + x = fAA6AC[dword_AA544].f_8 + dword_AA800[dword_AA844]; + y = fAA6AC[dword_AA544].f_c + dword_AA820[dword_AA844] + 17; + tile = fAA6AC[dword_AA544].f_4; + } + + if (dword_AA544 == 5 && a2 == 1) + sub_54FA4(160+dword_AA800[dword_AA844], 100+dword_AA820[dword_AA844]); + else + sub_54D90(); + + rotatesprite_win(x<<16, y<<16, 32768, 0, tile, 0, 0, 2); + + if (a2 == 1 && dword_AA544 == 5 && (p->dhat613 || p->dhat617)) + { + ghrifle_setmode(3); + } + else + { + if (dword_AA544 == 5 && p->dhat617) + ghrifle_setmode(3); + else + ghrifle_setmode(fAA558[dword_AA544].f_10); + } +} + +int dword_AA848; +int dword_AA84C; +unsigned int dword_AA850; +int dword_AA854; + +structAA3D0 fAA858[15] = { + 1, 3328, 198, 152, 0, + 4, 3329, 198, 132, 2, + 4, 3330, 198, 132, 3, + 4, 3331, 198, 136, 4, + 4, 3332, 198, 136, 5, + 4, 3333, 198, 132, 6, + 4, 3334, 198, 132, 7, + 4, 3333, 198, 132, 8, + 4, 3332, 198, 132, 9, + 4, 3331, 198, 132, 0, + 12, 3336, 198, 132, 11, + 12, 3337, 198, 132, 12, + 12, 3338, 198, 132, 13, + 12, 3337, 198, 132, 14, + 12, 3336, 198, 132, 0 +}; + +int dword_AA984[] = { + 0, -1, -2, -3, -4, -3, -2, -1 +}; +int dword_AA9A4[] = { + 0, -1, -2, -2, -1, -2, -2, -1 +}; + +int ghpistol_setmode(int a1) +{ + if (a1 < 0 || a1 >= 15) + return 0; + if (a1 != dword_AA848) + { + if ((int)totalclock - dword_AA850 > fAA858[dword_AA848].f_0) + { + switch (dword_AA848) + { + case 10: + A_PlaySound(1, g_player[myconnectindex].ps->i); + break; + case 14: + dword_AA84C = 6; + break; + case 2: + if (!dword_AA84C) + { + Printf("ghpistol_setmode: pistolloaded at 0\n"); + } + else + dword_AA84C--; + break; + } + dword_AA850 = (int)totalclock; + dword_AA848 = a1; + } + + } + return dword_AA848; +} + +int dword_2BD2B0[MAXSECTORS]; + +void ghpistol_fire(short snum) +{ + DukePlayer_t *p; + short v18 = 0; + short v1c = 0; + short v20 = 0; + int v38 = 0; + int v3c = 0; + int v40 = 0; + int v30, v34, v2c, vdx, vbx, v28, v24, vsi, i; + if (dword_AA84C == 0 && dword_AA848 == 0) + sub_5A250(16); + if (dword_AA84C && dword_AA848 == 0 && ghpistol_setmode(1) == 1) + { + p = g_player[snum].ps; + A_PlaySound(2, p->i); + v30 = p->pos.x; + v34 = p->pos.y; + v2c = p->pos.z + p->pyoff; + if (dword_AA854 == 3) + { + vdx = 4 - (rrdh_random() & 7); + vbx = 2047 - (rrdh_random() & 2047); + } + else + { + vdx = 8 - (rrdh_random() & 15); + vbx = 2048 - (rrdh_random() & 2048); + } + vdx += 2; + v24 = sintable[(fix16_to_int(p->q16ang) + vdx + 512) & 2047]; + v28 = sintable[(fix16_to_int(p->q16ang) + vdx) & 2047]; + vsi = ((100 - fix16_to_int(p->q16horiz)) << 11) + vbx; + + for (i = 0; i < MAXSECTORS; i++) + { + dword_2BD2B0[i] = sector[i].ceilingz; + sector[i].ceilingz = -0x64000; + } + hitscan_old(v30, v34, v2c, p->cursectnum, v24, v28, vsi, &v18, &v20, &v1c, &v38, &v3c, &v40, CLIPMASK1); + for (i = 0; i < MAXSECTORS; i++) + { + sector[i].ceilingz = dword_2BD2B0[i]; + } + if (v18 < 0) + { + Printf("WARNING: ghpistol_fire hitsect < 0\n"); + return; + } + sub_51678(v28, v1c, v18, v38, v3c, v40); + if (v1c >= 0) + { + if (sprite[v1c].cstat == 32768) + { + Printf("ERROR: hit spr with cstat 32768\n"); + return; + } + if (sector[sprite[v1c].sectnum].hitag == 2000) + { + Printf("ERROR: hit spr in REST_AREA sector\n"); + return; + } + ghtrophy_addkill(v1c); + ghtarget_hit(v1c, dword_AA854); + } + else + sub_5A250(4); + } + +} + +void sub_566E8(void) +{ +} + +void sub_566F0(void) +{ + ghpistol_setmode(0); + dword_AA854 = 2; + dword_AA84C = 0; +} + +int sub_56718(void) +{ + return dword_AA854; +} + +void sub_56724(void) +{ + if (dword_AA848 == 0) + { + sub_5A250(0x4000); + dword_AA84C = 0; + if (dword_AA848 == 0) + ghpistol_setmode(10); + dword_AA854 = 2 + (dword_AA854 == 2); + } +} + +void sub_56780(void) +{ + if (dword_AA848 == 0 && dword_AA84C != 6) + ghpistol_setmode(10); +} + +unsigned int dword_AA9C4; + +int dword_AA9C8; + +void ghpistol_render(short snum) +{ + int vdx; + if (dword_AA848 < 0 || dword_AA848 >= 15) + { + Printf("ERROR: ghpistol_draw bad index\n"); + return; + } + if (snum < 0 || snum >= numplayers) + { + Printf("ERROR: ghpistol_render bad index\n"); + return; + } + DukePlayer_t *p = g_player[snum].ps; + if (p->dhat613 || p->dhat617) + { + vdx = 10; + if (p->dhat617) + vdx = 5; + + if ((int)totalclock - dword_AA9C4 > vdx) + { + dword_AA9C8++; + if (dword_AA9C8 >= 8) + dword_AA9C8 = 0; + dword_AA9C4 = (int)totalclock; + } + } + else + { + if (dword_AA9C8) + dword_AA9C8++; + if (dword_AA9C8 >= 8) + dword_AA9C8 = 0; + } + if (dword_AA9C8 >= 8) + { + Printf("ERROR: ghpistol_render bobcnt out of bounds\n"); + return; + } + sub_54D90(); + rotatesprite_win((fAA858[dword_AA848].f_8+dword_AA984[dword_AA9C8])<<16, + (fAA858[dword_AA848].f_c+dword_AA9A4[dword_AA9C8]+17)<<16, 40960, + 0, fAA858[dword_AA848].f_4, 0, 0, 2); + ghpistol_setmode(fAA858[dword_AA848].f_10); +} + +int dword_AA9CC; +unsigned int dword_AA9D4; + +structAA3D0 fAA9DC[7] = { + 1, 3454, 216, 158, 0, + 4, 3452, 216, 162, 1, + 4, 3453, 216, 158, 3, + 12, 3455, 216, 158, 0, + 12, 3456, 216, 132, 5, + 12, 3457, 216, 132, 6, + 12, 3458, 216, 132, 1 +}; + +int dword_AAA68[] = { + 0, -1, -2, -3, -4, -3, -2, -1 +}; + +int dword_AAA88[] = { + 0, -1, -2, -2, -1, -2, -2, -1 +}; + +int dword_AA9D0; + +int ghbow_setmode(int a1) +{ + if (a1 < 0 || a1 >= 7) + { + Printf("ERROR: ghbow_setmode %i\n", a1); + return 0; + } + if (dword_AA9CC != a1) + { + if ((int)totalclock - dword_AA9D4 > fAA9DC[dword_AA9CC].f_0) + { + switch (dword_AA9CC) + { + case 4: + A_PlaySound(7, g_player[myconnectindex].ps->i); + break; + case 6: + dword_AA9D0 = 1; + break; + case 2: + dword_AA9D0 = 0; + break; + } + dword_AA9D4 = (int)totalclock; + dword_AA9CC = a1; + } + } + return dword_AA9CC; +} + +void ghbow_fire(short snum) +{ + struct player_struct *p; + if (!dword_AA9D0) + { + if (dword_AA9CC == 1 || dword_AA9CC == 0) + sub_5A250(0x10); + } + if (dword_AA9D0 && dword_AA9CC == 1 && ghbow_setmode(2) == 2) + { + A_PlaySound(8, g_player[myconnectindex].ps->i); + gharrow_spawnarrow(snum); + } +} + +void sub_56AB0(void) +{ +} + +int dword_AA9D8; + +void sub_56AB8(void) +{ + ghbow_setmode(0); + dword_AA9D8 = 0; + dword_AA9D0 = 0; +} + +int sub_56AD8(void) +{ + return dword_AA9D8; +} + +void sub_56AE4(void) +{ + if (dword_AA9CC == 0) + { + sub_5A250(0x4000); + dword_AA9D0 = 0; + if (dword_AA9CC == 0) + ghbow_setmode(4); + dword_AA9D8 = (dword_AA9D8 == 0); + } +} + +void sub_56B3C(void) +{ + if (dword_AA9CC == 0 && dword_AA9D0 != 1) + ghbow_setmode(4); +} + +unsigned int dword_AAAA8; +int dword_AAAAC; + +void ghbow_render(short snum) +{ + int vdx; + if (dword_AA9CC < 0 || dword_AA9CC >= 7) + { + Printf("ERROR: ghbow_draw bad index\n"); + return; + } + if (snum < 0 || snum >= numplayers) + { + Printf("ERROR: ghbow_render bad index\n"); + return; + } + DukePlayer_t *p = g_player[snum].ps; + if (p->dhat613 || p->dhat617) + { + vdx = 10; + if (p->dhat617) + vdx = 5; + + if ((int)totalclock - dword_AAAA8 > vdx) + { + dword_AAAAC++; + if (dword_AAAAC >= 8) + dword_AAAAC = 0; + dword_AAAA8 = (int)totalclock; + } + } + else + { + if (dword_AAAAC) + dword_AAAAC++; + if (dword_AAAAC >= 8) + dword_AAAAC = 0; + } + if (dword_AAAAC >= 8) + { + Printf("ERROR: ghbow_render bobcnt out of bounds\n"); + return; + } + sub_54D90(); + rotatesprite_win((fAA9DC[dword_AA9CC].f_8+dword_AAA68[dword_AAAAC])<<16, + (fAA9DC[dword_AA9CC].f_c+dword_AAA88[dword_AAAAC]+17)<<16, 40960, + 0, fAA9DC[dword_AA9CC].f_4, 0, 0, 2); + ghbow_setmode(fAA9DC[dword_AA9CC].f_10); +} + +int sub_56CF0(int a1) +{ + if (a1 < 0 || a1 >= numsectors) + return 0; + return 1; +} + +void ghprecip_snowfall(void) +{ + DukePlayer_t *p; + int i, nexti, j; + spritetype *s; + short sect, v18; + int vdi, vsi, v28; + p = g_player[screenpeek].ps; + + i = headspritestat[801]; + while (i >= 0) + { + nexti = nextspritestat[i]; + s = &sprite[i]; + s->z += 0x300; + sect = s->sectnum; + if (sect < 0 || sect >= numsectors) + { + Printf("ghprecip_snowfall: bad sectnum\n"); + goto BOLT; + } + if (s->z > sector[sect].floorz) + { + vdi = p->pos.x + (rrdh_random() & 0x3fff) - 0x2000; + vsi = p->pos.y + (rrdh_random() & 0x3fff) - 0x2000; + v28 = -0x19000; + v18 = -1; + for (j = 0; j < numsectors; j++) + { + if (inside(vdi, vsi, j)) + { + if (sub_56CF0(j)) + { + v18 = j; + break; + } + } + } + if (v18 >= 0 && v18 < numsectors) + { + s->x = vdi; + s->y = vsi; + s->z = v28; + changespritestat(i, v18); + if (v18 != s->sectnum) + { + Printf("changespritesect failed\n"); + } + } + } +BOLT: + i = nexti; + } +} + +void sub_56EA8(void) +{ + ghprecip_snowfall(); +} + + +void sub_56EC0(void) +{ + short i; + i = headspritestat[802]; + while (i >= 0) + { + sprite[i].extra++; + i = nextspritestat[i]; + } +} + +int dword_AAAB8 = 0x180; +int dword_AAAB0; + +short ghtrax_getoldestdeertrax(void) +{ + short i, nexti, vcx, vsi; + vcx = -1; + vsi = 0; + i = headspritestat[802]; + while (i >= 0) + { + nexti = nextspritestat[i]; + if (vcx < sprite[i].extra) + { + vcx = sprite[i].extra; + vsi = i; + } + if (sprite[i].extra > dword_AAAB8) + { + Printf("ghtrax_getoldestdeertrax: oldest trax at %i\n", sprite[i].extra.cast()); + } + i = nexti; + } + return vsi; +} + +void ghtrax_deertrax(short a1) +{ + spritetype *s, *s2; + int v24 = 0; + int v28 = 0; + int v2c = 0; + int v30 = 0; + short v18, i, nexti; + s = &sprite[a1]; + if (dword_AAAB8 > dword_AAAB0) + { + v18 = insertsprite(s->sectnum, 0); + if (v18 < 0 || v18 >= MAXSPRITES) + { + Printf("ghtrax_deertrax: insertsprite failed\n"); + dword_AAAB8 = dword_AAAB0; + Printf(" set maxtraxdeer to %i\n", dword_AAAB8); + } + else + dword_AAAB0++; + } + else + { + v18 = ghtrax_getoldestdeertrax(); + if (v18 < 0 || v18 >= MAXSPRITES) + { + Printf("ghtrax_deertrax: invalid oldest trax sprite\n"); + return; + } + } + sub_56EC0(); + s2 = &sprite[v18]; + getzrange_old(s->x, s->y, s->z, s->sectnum, &v24, &v28, &v2c, &v30, 128, CLIPMASK0); + if (v2c < sector[s->sectnum].floorz) + v2c = sector[s->sectnum].floorz - 8; + vec3_t pos = { s->x, s->y, v2c }; + setsprite(a1, &pos); + changespritestat(a1, 802); + s2->cstat = 0x20; + s2->extra = 0; + s2->ang = s->ang; + s2->owner = a1; + s2->pal = 0; + s2->xoffset = 0; + s2->yoffset = 0; + s2->xvel = 0; + s2->yvel = 0; + s2->zvel = 0; + s2->shade = -28; + s2->xrepeat = 14; + s2->yrepeat = 18; + s2->clipdist = 32; + s2->picnum = 7080 + (ud.level_number != 3); +} + +void sub_57140(void) +{ + short i, nexti; + i = headspritestat[804]; + while (i >= 0) + { + nexti = nextspritestat[i]; + sprite[i].extra++; + i = nexti; + } +} + +int dword_AAAC4 = 0x100; + +short ghtrax_getoldestboartrax(void) +{ + short i, nexti, vcx, vsi; + vcx = -1; + vsi = 0; + i = headspritestat[804]; + while (i >= 0) + { + nexti = nextspritestat[i]; + if (vcx < sprite[i].extra) + { + vcx = sprite[i].extra; + vsi = i; + } + if (sprite[i].extra > dword_AAAC4) + { + Printf("ghtrax_getoldestdeertrax: oldest trax at %i\n", sprite[i].extra.cast()); + } + i = nexti; + } + return vsi; +} + +int dword_AAABC; + +void ghtrax_boartrax(short a1) +{ + spritetype* s, * s2; + int v24 = 0; + int v28 = 0; + int v2c = 0; + int v30 = 0; + short v18, i, nexti; + s = &sprite[a1]; + if (dword_AAAC4 > dword_AAABC) + { + v18 = insertsprite(s->sectnum, 0); + if (v18 < 0 || v18 >= MAXSPRITES) + { + Printf("ghtrax_boartrax: insertsprite failed\n"); + dword_AAAC4 = dword_AAABC; + Printf(" set maxtraxboar to %d\n", dword_AAAC4); + } + else + dword_AAABC++; + } + else + { + v18 = ghtrax_getoldestboartrax(); + if (v18 < 0 || v18 >= MAXSPRITES) + { + Printf("ghtrax_boartrax: invalid oldest trax sprite\n"); + return; + } + } + sub_57140(); + s2 = &sprite[v18]; + getzrange_old(s->x, s->y, s->z, s->sectnum, &v24, &v28, &v2c, &v30, 128, CLIPMASK0); + if (v2c < sector[s->sectnum].floorz) + v2c = sector[s->sectnum].floorz - 8; + vec3_t pos = { s->x, s->y, v2c }; + setsprite(a1, &pos); + changespritestat(a1, 804); + s2->cstat = 0x20; + s2->extra = 0; + s2->ang = s->ang; + s2->owner = a1; + s2->pal = 0; + s2->xoffset = 0; + s2->yoffset = 0; + s2->xvel = 0; + s2->yvel = 0; + s2->zvel = 0; + s2->shade = -28; + s2->xrepeat = 14; + s2->yrepeat = 18; + s2->clipdist = 32; + s2->picnum = 7084 + (ud.level_number != 3); +} + +int dword_AAAB4, dword_AAAC0; + +short word_AAAC8; + +void sub_573C0(void) +{ + int vdx = 0; + int i; + for (i = 0; i < MAXSPRITES; i++) + if (sprite[i].picnum) + vdx++; + + vdx = MAXSPRITES - vdx; + if (vdx <= 640) + Printf("not enuff sprites left for deer and boar trax\n"); + dword_AAAB0 = 0; + dword_AAAB4 = 0; + dword_AAAB8 = 0x180; + dword_AAABC = 0; + dword_AAAC0 = 0; + dword_AAAC4 = 0x100; + word_AAAC8 = (rrdh_random() & 2047); +} + +short sub_5743C(void) +{ + return word_AAAC8; +} + +int ghtrax_isplrupwind(short a1, short a2) +{ + spritetype *s; + DukePlayer_t *p; + s = &sprite[a1]; + p = g_player[a2].ps; + + return klabs(word_AAAC8 - (getangle(s->x -p->pos.x, s->y - p->pos.y) & 2047)) < 256; +} + +void ghtrax_leavetrax(short a1) +{ + spritetype *s; + sectortype *sc; + short sect; + s = &sprite[a1]; + sect = s->sectnum; + sc = §or[sect]; + + if (klabs(sector[sect].ceilingheinum - sector[sect].floorheinum) <= 576) + { + switch (DYNAMICTILEMAP(sprite[a1].picnum)) + { + case VIXEN__STATICRR: + if (sector[sect].hitag == 0) + ghtrax_deertrax(a1); + break; + case PIG__STATICRR: + if (sector[sect].hitag == 0) + ghtrax_boartrax(a1); + break; + } + } +} + +void ghtrax_deerdroppings(short a1) +{ + spritetype* s, * s2; + int v24 = 0; + int v28 = 0; + int v2c = 0; + int v30 = 0; + short v18, i, nexti; + s = &sprite[a1]; + if (dword_AAAB4 >= 24) + return; + v18 = insertsprite(s->sectnum, 0); + if (v18 < 0 || v18 >= MAXSPRITES) + { + Printf("ghtrax_deerdroppings: insertsprite failed\n"); + return; + } + s2 = &sprite[v18]; + getzrange_old(s->x, s->y, s->z, s->sectnum, &v24, &v28, &v2c, &v30, 128, CLIPMASK0); + if (v2c < sector[s->sectnum].floorz) + v2c = sector[s->sectnum].floorz - 8; + vec3_t pos = { s->x, s->y, v2c }; + setsprite(a1, &pos); + changespritestat(a1, 803); + s2->cstat = 0; + s2->ang = s->ang; + s2->owner = a1; + s2->pal = 0; + s2->xoffset = 0; + s2->yoffset = 0; + s2->xvel = 0; + s2->yvel = 0; + s2->zvel = 0; + s2->shade = 8; + s2->xrepeat = 8; + s2->yrepeat = 5; + s2->clipdist = 32; + s2->extra = 0; + s2->picnum = 981 + (ud.level_number != 3); + dword_AAAB4++; +} + +void ghtrax_boardroppings(short a1) +{ + spritetype* s, * s2; + int v24 = 0; + int v28 = 0; + int v2c = 0; + int v30 = 0; + short v18, i, nexti; + s = &sprite[a1]; + if (dword_AAAC0 >= 24) + return; + v18 = insertsprite(s->sectnum, 0); + if (v18 < 0 || v18 >= MAXSPRITES) + { + Printf("ghtrax_boardroppings: insertsprite failed\n"); + return; + } + s2 = &sprite[v18]; + getzrange_old(s->x, s->y, s->z, s->sectnum, &v24, &v28, &v2c, &v30, 128, CLIPMASK0); + if (v2c < sector[s->sectnum].floorz) + v2c = sector[s->sectnum].floorz - 8; + vec3_t pos = { s->x, s->y, v2c }; + setsprite(a1, &pos); + changespritestat(a1, 805); + s2->cstat = 0; + s2->ang = s->ang; + s2->owner = a1; + s2->picnum = 983; + s2->pal = 0; + s2->xoffset = 0; + s2->yoffset = 0; + s2->xvel = 0; + s2->yvel = 0; + s2->zvel = 0; + s2->shade = 8; + s2->xrepeat = 8; + s2->yrepeat = 5; + s2->clipdist = 32; + s2->extra = 0; + dword_AAAC0++; +} + +void ghtrax_leavedroppings(short a1) +{ + spritetype *s; + sectortype *sc; + short sect; + s = &sprite[a1]; + sect = s->sectnum; + sc = §or[sect]; + + if (klabs(sector[sect].ceilingheinum - sector[sect].floorheinum) <= 576) + { + switch (DYNAMICTILEMAP(sprite[a1].picnum)) + { + case VIXEN__STATICRR: + if (sector[sect].hitag == 0) + ghtrax_deerdroppings(a1); + break; + case PIG__STATICRR: + if (sector[sect].hitag == 0) + ghtrax_boardroppings(a1); + break; + } + } +} + +int dword_AAAD0, dword_AAAD4, dword_AAAD8, dword_AAACC; +unsigned int dword_AAADC, dword_AAAE0, dword_AAAE4, dword_AAAE8; + +void sub_579A0(void) +{ + dword_AAAD0++; + dword_AAACC++; + if (dword_AAAD0 == 4) + { + if (dword_AAADC > 0) + dword_AAADC--; + if (dword_AAAE0 > 0) + dword_AAAE0--; + if (dword_AAAE4 > 0) + dword_AAAE4--; + if (dword_AAAE8 > 0) + dword_AAAE8--; + dword_AAAD0 = 0; + dword_AAAD4++; + if (dword_AAAD4 == 10) + { + dword_AAAD8++; + dword_AAAD4 = 0; + } + } +} + +int sub_57A40(int a1) +{ + if (dword_AAADC) + return 0; + dword_AAADC = a1; + return 1; +} + +int sub_57A60(int a2) +{ + if (dword_AAAE0) + return 0; + dword_AAAE0 = a2; + return 1; +} + +int sub_57A80(int a2) +{ + if (dword_AAAE4) + return 0; + dword_AAAE4 = a2; + return 1; +} + +int sub_57AA0(int a2) +{ + if (dword_AAAE8) + return 0; + dword_AAAE8 = a2; + return 1; +} + +int dword_AAAEC; + +void sub_57AC0(void) +{ + int i; + show2dsector.SetAll(1); + for (i = 0; i < MAXWALLS; i++) + show2dwall[i>>3] |= 1<<(i&7); + dword_AAAEC ^= 1; +} + +void sub_57B24(void) +{ + dword_AAAEC = 0; +} + +void sub_57B38(long cposx, long cposy, long czoom, short cang) +{ + long i, j, k, l, x1, y1, x2, y2, x3, y3, x4, y4, ox, oy, xoff, yoff; + long dax, day, cosang, sinang, xspan, yspan, sprx, spry; + long xrepeat, yrepeat, z1, z2, startwall, endwall, tilenum, daang; + long xvect, yvect, xvect2, yvect2, xc, yc, xc2, yc2; + short p; + char col; + walltype *wal, *wal2; + spritetype *spr; + + if (!dword_AAAEC) + return; + + xvect = sintable[(-cang)&2047] * czoom; + yvect = sintable[(1536-cang)&2047] * czoom; + xvect2 = mulscale16(xvect,yxaspect); + yvect2 = mulscale16(yvect,yxaspect); + xc = windowxy2.x - windowxy1.x; + yc = windowxy2.y - windowxy1.y; + xc2 = 0; + yc2 = 0; + + //Draw white lines + for(i=0;inextwall >= 0) continue; + + if ((show2dwall[j>>3]&(1<<(j&7))) == 0) continue; + + if (tilesiz[wal->picnum].x == 0) continue; + if (tilesiz[wal->picnum].y == 0) continue; + + if (j == k) + { x1 = x2; y1 = y2; } + else + { + ox = wal->x; oy = wal->y; + x1 = dmulscale16(ox,xvect,-oy,yvect)+(xc<<11); + y1 = dmulscale16(oy,xvect2,ox,yvect2)+(yc<<11); + } + + k = wal->point2; wal2 = &wall[k]; + ox = wal2->x; oy = wal2->y; + x2 = dmulscale16(ox,xvect,-oy,yvect)+(xc<<11); + y2 = dmulscale16(oy,xvect2,ox,yvect2)+(yc<<11); + + renderDrawLine(x1,y1,x2,y2,74); + } + } + + for(k=0;kq16ang)+512)&2047, 7060, 0, 0, 0); +} + +int sub_57FB0(void) +{ + return 64 + (rrdh_random() % 224); +} + +unsigned int dword_AAAF0; +unsigned int dword_AAAF4, dword_AAAF8; +int dword_AAAFC, dword_AAB00, dword_AAB04; + +void ghtarget_runningclock(void) +{ + if (dword_AAAFC != 2) + { + if (dword_AAAFC == 1) + { + if ((int)totalclock - dword_AAB04 >= 240) + { + sub_53E18(); + dword_AAAFC = 2; + } + } + else + { + if ((int)totalclock - dword_AAAF8 >= 120) + { + if (dword_AAAF4 > 0) + dword_AAAF4--; + else if (dword_AAAF0 > 0) + { + dword_AAAF4 = 50; + dword_AAAF0--; + } + else + { + dword_AAAFC = 1; + dword_AAB04 = (int)totalclock; + P_DoQuote(145, g_player[myconnectindex].ps); + } + dword_AAAF8 = (int)totalclock; + } + } + } +} + +void sub_580C8(void) +{ + int vsi = dword_AAAF0 % 10; + int vd = dword_AAAF0 / 10; + rotatesprite(292<<16, 184<<16, 17408, 0, DIGITALNUM+vd, 0, 0, 128+10, 0, 0, xdim-1, ydim-1); + rotatesprite(296<<16, 184<<16, 17408, 0, DIGITALNUM+vsi, 0, 0, 128+10, 0, 0, xdim-1, ydim-1); + vsi = dword_AAAF4 % 10; + vd = dword_AAAF4 / 10; + rotatesprite(302<<16, 184<<16, 17408, 0, DIGITALNUM+vd, 0, 0, 128+10, 0, 0, xdim-1, ydim-1); + rotatesprite(306<<16, 184<<16, 17408, 0, DIGITALNUM+vsi, 0, 0, 128+10, 0, 0, xdim-1, ydim-1); +} + +void ghtarget_move(void) +{ + int v2c = 0; + int v28 = 0; + int v24 = 0; + short v18 = 0; + int i, nexti; + short mv; + spritetype *s; + i = headspritestat[808]; + while (i >= 0) + { + nexti = nextspritestat[i]; + s = &sprite[i]; + if (dword_AAAFC) + mv = 0; + else + { + v2c = s->x; + v28 = s->y; + v24 = s->z; + v18 = s->sectnum; + vec3_t vect = { (sintable[1536]*s->xvel)>>14, 0, 0 }; + mv = A_MoveSprite(i, &vect, CLIPMASK1); + } + if (mv || v18 != s->sectnum) + { + s->x = v2c; + s->y = v28; + s->z = v24; + changespritesect(i, v18); + s->yvel = -s->yvel; + s->xvel = sub_57FB0(); + if (s->yvel == -1) + s->xvel = -s->xvel; + s->cstat ^= 4; + ghtarget_setanimal(i); + if (s->extra) + { + s->cstat |= 256; + s->cstat &= ~32768; + s->extra = 0; + s->xvel = sub_57FB0(); + if (s->yvel == -1) + s->xvel = -s->xvel; + } + } + i = nexti; + } + if (ud.level_number > 3) + ghtarget_runningclock(); +} + +void sub_58364(int a1) +{ + dword_AAAF0 = a1; + dword_AAAF8 = 0; + dword_AAAF4 = 0; + dword_AAAFC = 0; +} + +void sub_58388(void) +{ + int i, vdx; + sub_58364(0); + dword_AAB00 = 0; + if (ud.level_number < 4) + return; + for (i = 0; i < MAXSPRITES; i++) + { + vdx = 0; + switch (sprite[i].picnum) + { + case 7110: + sprite[i].xrepeat = 18; + sprite[i].yrepeat = 24; + vdx = 1; + break; + case 7111: + sprite[i].xrepeat = 13; + sprite[i].yrepeat = 14; + vdx = 1; + break; + case 7112: + sprite[i].xrepeat = 22; + sprite[i].yrepeat = 16; + vdx = 1; + break; + case 1076: + sprite[i].cstat = 257; + break; + } + if (vdx) + { + changespritestat(i, 808); + sprite[i].cstat = 273; + sprite[i].xvel = sub_57FB0(); + sprite[i].yvel = 1; + sprite[i].extra = 0; + } + } + sub_58364(3); +} + +void ghtarget_setanimal(short a1) +{ + int vdx; + vdx = rrdh_random() % 5; + switch (vdx) + { + case 0: + sprite[a1].picnum = 7110; + sprite[a1].xrepeat = 18; + sprite[a1].yrepeat = 24; + break; + case 1: + sprite[a1].picnum = 7111; + sprite[a1].xrepeat = 13; + sprite[a1].yrepeat = 14; + break; + case 2: + sprite[a1].picnum = 7112; + sprite[a1].xrepeat = 22; + sprite[a1].yrepeat = 16; + break; + } +} + +void ghtarget_hit(short a1, int a2) +{ + unsigned short vc; + if (dword_AAAFC) + return; + if (sprite[a1].picnum == 1076) + { + dword_AAB00++; + sub_58A30(1); + sub_53848(dword_AAB00); + } + else if (sprite[a1].statnum == 808) + { + vc = sprite[a1].picnum; + switch (sprite[a1].picnum) + { + case 7110: + case 7111: + vc = 1; + break; + case 7112: + vc = 4; + break; + } + ghstatbr_registerkillinfo(sprite[a1].picnum, 0, 0); + vc += klabs(sprite[a1].xvel) / 32; + switch (sector[sprite[a1].sectnum].hitag) + { + case 2004: + vc++; + break; + case 2005: + vc += 2; + break; + case 2006: + vc += 4; + break; + case 2007: + vc += 8; + break; + case 2008: + vc += 16; + break; + default: + Printf("WARNING: ghtarget_hit: spr not in track\n"); + break; + } + switch (g_player[myconnectindex].ps->dhat61f) + { + case 0: + vc++; + break; + case 1: + vc += 2; + break; + case 3: + vc += 2; + break; + case 4: + vc += 3; + break; + } + sprite[a1].cstat |= 32768; + sprite[a1].cstat &= ~256; + A_PlaySound(87, g_player[myconnectindex].ps->i); + ghtarget_setanimal(a1); + sprite[a1].extra = 1; + if (vc > 18) + sub_5A250(0x200); + dword_AAB00 += vc; + sub_58A30(vc); + sub_53848(dword_AAB00); + } +} + +void gharrow_move(void) +{ + int i, nexti; + short mv; + int v24, v28, v20, vdx; + short v18; + spritetype *s; + i = headspritestat[809]; + while (i >= 0) + { + nexti = nextspritestat[i]; + s = &sprite[i]; + if (s->sectnum < 0 || s->sectnum >= numsectors) + { + deletesprite(i); + } + else + { + A_GetZLimits(i); + v24 = s->x; + v28 = s->y; + v20 = s->y; + v18 = s->sectnum; + vec3_t vec = { s->xvel, s->yvel, s->zvel }; + mv = A_MoveSprite(i, &vec, CLIPMASK1); + if (mv) + { + s->x = v24; + s->y = v28; + s->z = v20; + changespritesect(i, v18); + if ((mv & 49152) == 49152) + { + mv &= MAXSPRITES - 1; + A_PlaySound(59, mv); + vdx = sub_56AD8(); + ghtrophy_addkill(mv); + ghtarget_hit(mv, vdx); + } + else + { + if ((mv & 49152) == 32768 && ud.level_number > 3) + A_PlaySound(59, i); + sub_5A250(4); + } + deletesprite(i); + } + } + i = nexti; + } +} + +void gharrow_spawnarrow(short snum) +{ + short s; + spritetype *spr; + DukePlayer_t *p; + p = g_player[snum].ps; + s = insertsprite(p->cursectnum, 809); + if (s < 0 || s >= MAXSPRITES) + { + Printf("gharrow_spawnarrow: insertsprite failed\n"); + return; + } + spr = &sprite[s]; + if (!spr) + { + Printf("gharrow_spawnarrow: null sprptr\n"); + return; + } + spr->x = p->pos.x; + spr->y = p->pos.y; + spr->z = p->pos.z; + spr->ang = (fix16_to_int(p->q16ang) + 3) & 2047; + spr->xvel = sintable[(spr->ang + 512) & 2047]; + spr->yvel = sintable[(spr->ang) & 2047]; + spr->picnum = 3450; + spr->cstat = 1; + spr->owner = 0; + spr->xrepeat = 14; + spr->yrepeat = 14; + spr->pal = 0; + spr->xoffset = 0; + spr->yoffset = 0; + spr->lotag = 0; + spr->hitag = 0; + spr->extra = 0; + spr->shade = 0; + spr->zvel = (100 - fix16_to_int(p->q16horiz) + 1) << 9; + spr->cstat |= 0x8001; +} + +int dword_AAB08 = 1; +unsigned int dword_AAB0C; + +void sub_58A30(int a1) +{ + dword_AAB0C += a1; + if (dword_AAB0C > 99999) + dword_AAB0C = 0; + dword_AAB08 = 128; +} + +void sub_58A5C(unsigned int a1) +{ + int t1 = a1 % 10; + int t2 = (a1 % 100) / 10; + int t3 = (a1 % 1000) / 100; + int t4 = (a1 % 10000) / 1000; + int t5 = (a1 % 100000) / 10000; + rotatesprite(243<<16, 185<<16, 22528, 0, DIGITALNUM+t1, 0, 0, 128+64+10, 0, 0, xdim-1, ydim-1); + rotatesprite(235<<16, 185<<16, 22528, 0, DIGITALNUM+t2, 0, 0, 128+64+10, 0, 0, xdim-1, ydim-1); + rotatesprite(227<<16, 185<<16, 22528, 0, DIGITALNUM+t3, 0, 0, 128+64+10, 0, 0, xdim-1, ydim-1); + rotatesprite(219<<16, 185<<16, 22528, 0, DIGITALNUM+t4, 0, 0, 128+64+10, 0, 0, xdim-1, ydim-1); + rotatesprite(211<<16, 185<<16, 22528, 0, DIGITALNUM+t5, 0, 0, 128+64+10, 0, 0, xdim-1, ydim-1); +} + +short word_AAB10; +int dword_AAB14, dword_AAB18; + +void ghstatbr_registerkillinfo(short a1, int a2, int a3) +{ + if (a1 < 0 || a1 >= MAXTILES) + { + Printf("ERROR: ghstatbr_registerkillinfo bad pic range\n"); + return; + } + if (a2 < 0) + { + Printf("ERROR: ghstatbr_registerkillinfo neg points\n"); + return; + } + switch (DYNAMICTILEMAP(a1)) + { + case VIXEN__STATICRR: + word_AAB10 = 1720; + break; + case RRTILE7110__STATICRR: + word_AAB10 = 7114; + break; + case PIG__STATICRR: + word_AAB10 = 1719; + break; + case RRTILE7111__STATICRR: + word_AAB10 = 7115; + break; + case DOGRUN__STATICRR: + word_AAB10 = 1721; + break; + case RRTILE7113__STATICRR: + word_AAB10 = 7116; + break; + case CHEER__STATICRR: + word_AAB10 = 1722; + break; + case RRTILE7112__STATICRR: + word_AAB10 = 7117; + break; + default: + word_AAB10 = 0; + dword_AAB14 = 0; + return; + } + dword_AAB14 = a2; + dword_AAB18 = a3; + dword_AAB08 |= 8; +} + +void sub_58D14(void) +{ + if (word_AAB10 > 0 && dword_AAB14 >= 0 && dword_AAB18 >= 0) + { + rotatesprite(39<<16, 185<<16, 32768, 0, word_AAB10, 0, 0, 128+64+10, 0, 0, xdim-1, ydim-1); + if (ud.level_number < 4) + { + unsigned int t1 = dword_AAB14 % 10; + unsigned int t2 = (dword_AAB14 % 100) / 10; + unsigned int t3 = (dword_AAB14 % 1000) / 100; + rotatesprite(64<<16, 180<<16, 18432, 0, DIGITALNUM+t1, 0, 0, 128+64+10, 0, 0, xdim-1, ydim-1); + if (t3 || t2 > 0) + { + rotatesprite(58<<16, 180<<16, 18432, 0, DIGITALNUM+t2, 0, 0, 128+64+10, 0, 0, xdim-1, ydim-1); + } + if (t3 > 0) + { + rotatesprite(52<<16, 180<<16, 18432, 0, DIGITALNUM+t3, 0, 0, 128+64+10, 0, 0, xdim-1, ydim-1); + } + t1 = dword_AAB18 % 10; + t2 = (dword_AAB18 % 100) / 10; + rotatesprite(64<<16, 190<<16, 18432, 0, DIGITALNUM+t1, 0, 0, 128+64+10, 0, 0, xdim-1, ydim-1); + if (t2 > 0) + { + rotatesprite(58<<16, 190<<16, 18432, 0, DIGITALNUM+t2, 0, 0, 128+64+10, 0, 0, xdim-1, ydim-1); + } + } + } +} + + +void sub_58F40(int a1) +{ + int v18 = sub_59B44(); + int v1c, v20, i; + switch (a1) + { + case 0: + v20 = 1723; + v1c = 24576; + break; + case 1: + case 2: + case 3: + v20 = 1724; + v1c = 24576; + break; + default: + return; + } + for (i = 0; i < v18; i++) + { + rotatesprite((216+13*i)<<16, 184<<16, v1c, 0, v20, 0, 0, 128+10, 0, 0, xdim-1, ydim-1); + } +} + +void ghstatbr_drawammotype(void) +{ + int vbx = 0; + switch (g_player[myconnectindex].ps->dhat61f) + { + case 0: + vbx = sub_56718(); + break; + case 1: + case 2: + vbx = sub_55FC0(); + break; + case 3: + vbx = sub_55928(); + break; + case 4: + vbx = sub_56AD8(); + break; + } + rotatesprite(97<<16, 187<<16, 32768, 0, 1711+vbx, 0, 0, 128+10, 0, 0, xdim-1, ydim-1); +} + +int dword_AAB1C; + +void ghstatbr_render(void) +{ + int r; + short v18; + + if (klabs(fix16_to_int(g_player[myconnectindex].ps->q16ang) - fix16_to_int(g_player[myconnectindex].ps->oq16ang)) > 16) + dword_AAB08 = 2; + + v18 = sub_5743C(); + r = rrdh_random() & 1023; + if (r < 64) + { + v18 += r - 32; + dword_AAB08 = 4; + v18 &= 2047; + } + if (dword_AAB08) + { + //sub_51028(3, dword_AAB1C++); + if (ud.level_number < 4) + { + rotatesprite(0<<16, 166<<16, 32768, 0, 1647, 4, 0, 128+64+16+10, 0, 0, xdim-1, ydim-1); + } + else + { + rotatesprite(0<<16, 166<<16, 32768, 0, 1710, 4, 0, 128+64+16+10, 0, 0, xdim-1, ydim-1); + } + sub_58D14(); + if (ud.level_number > 0 && ud.level_number < 4) + { + rotatesprite(216<<16, 166<<16, 32768, 0, 1725, 4, 0, 128+64+16+10, 0, 0, xdim-1, ydim-1); + } + ghstatbr_drawammotype(); + rotatesprite(155<<16, 185<<16, 32768, v18, 1637, 0, 0, 128+10, 0, 0, xdim-1, ydim-1); + if (ud.level_number < 4) + rotatesprite(301<<16, 183<<16, 32768, fix16_to_int(g_player[screenpeek].ps->q16ang), 1638, 0, 0, 128+10, 0, 0, xdim-1, ydim-1); + if (ud.level_number > 3) + sub_580C8(); + sub_58F40(ud.level_number); + if (ud.level_number > 3) + sub_58A5C(dword_AAB0C); + dword_AAB08 = 0; + } +} + +//void sub_592F0(void) +//{ +// dword_AAB08 = 1; +//} +// +//void sub_59304(int a1) +//{ +// dword_AAB08 |= a1; +//} + +void sub_59314(void) +{ + dword_AAB0C = 0; + dword_AAB14 = 0; + dword_AAB08 = 1; + word_AAB10 = 0; +} + +int ghdeploy_isdownwind(short a1, short a2) +{ + short ang; + ang = getangle(sprite[a1].x - sprite[a2].x, sprite[a1].y - sprite[a2].y) & 2047; + return klabs(sub_5743C() - ang) < 512; +} + +void ghdeploy_bias(short a1) +{ + spritetype *s; + int i, nexti, vcx, d; + short v1c; + s = &sprite[a1]; + vcx = 76800; + v1c = -1; + i = headspritestat[811]; + while (i >= 0) + { + nexti = nextspritestat[i]; + if (sprite[i].extra > 0) + { + if (sprite[i].picnum == 7073 && ghdeploy_isdownwind(a1, i)) + { + d = klabs(sprite[a1].x-sprite[i].x) + klabs(sprite[a1].y-sprite[i].y); + if (d < vcx) + { + vcx = d; + v1c = i; + } + } + else if (sprite[i].picnum == 7072) + { + if ((rrdh_random() & 255) > 32) + { + d = klabs(sprite[a1].x-sprite[i].x) + klabs(sprite[a1].y-sprite[i].y); + if (d < vcx) + { + vcx = d; + v1c = i; + } + } + } + else + { + d = klabs(sprite[a1].x-sprite[i].x) + klabs(sprite[a1].y-sprite[i].y); + if (d < vcx) + { + vcx = d; + v1c = i; + } + } + } + i = nexti; + } + if (vcx < 76800 && v1c != -1) + { + sprite[a1].ang = getangle(sprite[v1c].x-sprite[a1].x,sprite[v1c].y-sprite[a1].y) & 2047; + } + else + { + sprite[a1].ang = rrdh_random() & 2047; + } +} + +int dword_AAB24[] = { + 0, 16, 32, 48, 64, 80, 96, 112, 128, 144, 160, 176, + 192, 208, 224, 240, 256, 240, 224, 208, 192, 176, 160, + 144, 128, 112, 96, 80, 64, 48, 32, 16 +}; + +void ghdeploy_move(void) +{ + int v1c = 0; + int v20 = 0; + int v24 = 0; + int v28 = 0; + int i, nexti; + spritetype *s; + + i = headspritestat[811]; + while (i >= 0) + { + nexti = nextspritestat[i]; + s = &sprite[i]; + if (s->sectnum < 0 || s->sectnum >= numsectors) + { + Printf("ghdeploy_move DEPLOYED bad sect %i\n", s->sectnum.cast()); + deletesprite(i); + } + else if (sector[s->sectnum].hitag == 2003) + { + if (s->zvel < 0 || s->zvel >= 32) + s->zvel = 0; + else + { + s->z = sector[s->sectnum].floorz + 256 + dword_AAB24[s->zvel]; + s->zvel++; + } + } + if (s->picnum == 7073 && s->extra > 0) + { + s->extra--; + } + i = nexti; + } + i = headspritestat[810]; + while (i >= 0) + { + nexti = nextspritestat[i]; + s = &sprite[i]; + if (s->sectnum < 0 || s->sectnum >= numsectors) + { + Printf("ghdeploy_move TOSS bad sect %i\n", s->sectnum.cast()); + deletesprite(i); + } + vec3_t vec = { s->xvel, s->yvel, 0 }; + A_MoveSprite(i, &vec, CLIPMASK1); + getzrange_old(s->x, s->y, s->z, s->sectnum, &v1c, &v20, &v24, &v28, 32, CLIPMASK0); + if (v24 - 2048 < sprite[i].z) + { + changespritestat(i, 811); + s->extra = 9600; + s->z = v24; + s->zvel = 0; + if (s->picnum == 7072) + { + s->cstat = 1; + if (sector[s->sectnum].hitag == 2003) + A_PlaySound(90, g_player[myconnectindex].ps->i); + if (sector[s->sectnum].hitag == 2003) + A_PlaySound(89, g_player[myconnectindex].ps->i); + } + } + else + { + sprite[i].z += sprite[i].zvel; + sprite[i].zvel += 0x200; + } + i = nexti; + } +} + +unsigned int dword_AAB20; +int dword_AABA4 = 4; + +void ghdeploy_drop(int a1, int a2) +{ + DukePlayer_t *p; + short va; + spritetype *s; + if ((int)totalclock - dword_AAB20 < 120) + return; + if (!dword_AABA4) + { + P_DoQuote(149, g_player[a1].ps); + return; + } + if (a2 > 3) + return; + p = g_player[a1].ps; + if (p->cursectnum < 0 || p->cursectnum >= numsectors) + { + Printf("ERROR: ghdeploy_drop bad plrsectr %i\n", p->cursectnum); + return; + } + va = insertsprite(p->cursectnum, 810); + if (va < 0 || va >= MAXSPRITES) + { + Printf("ghdeploy_drop: insertsprite failed\n"); + return; + } + s = &sprite[va]; + if (!s) + { + Printf("ghdeploy_drop: null sprptr\n"); + return; + } + s->x = p->pos.x + (sintable[(fix16_to_int(p->q16ang) + 512) & 2047] >> 7); + s->y = p->pos.y + (sintable[(fix16_to_int(p->q16ang)) & 2047] >> 7); + s->z = p->pos.z + 0x1000; + s->ang = fix16_to_int(fix16_to_int(p->q16ang)) & 2047; + s->xvel = (sintable[(fix16_to_int(p->q16ang) + 512) & 2047] * 5) >> 8; + s->yvel = (sintable[(fix16_to_int(p->q16ang)) & 2047] * 5) >> 8; + s->zvel = (80 - fix16_to_int(p->q16horiz)) << 6; + if (a2 == 0) + { + s->picnum = 7072; + s->cstat = 0; + P_DoQuote(146, p); + } + else + { + s->cstat = 0; + s->cstat |= 32768; + s->picnum = 7073; + P_DoQuote(148, p); + A_PlaySound(88, p->i); + } + s->owner = 0; + s->clipdist = 4; + s->xrepeat = 10; + s->yrepeat = 10; + s->pal = 0; + s->xoffset = 0; + s->yoffset = 0; + s->lotag = 0; + s->hitag = 0; + s->extra = 0; + s->shade = 0; + dword_AABA4--; + //sub_592F0(); + dword_AAB20 = (int)totalclock; +} + +int sub_59B44(void) +{ + return dword_AABA4; +} + +void sub_59B50(void) +{ + dword_AABA4 = 4; + dword_AAB20 = 0; +} + +void ghdeploy_plrtouchedsprite(short a1, short a2) +{ + DukePlayer_t *p; + spritetype *s; + p = g_player[a2].ps; + s = &sprite[a1]; + + if (sprite[a1].statnum == 811 && sprite[a1].picnum != 7073) + { + deletesprite(a1); + dword_AABA4++; + P_DoQuote(147, p); + } +} + +short word_2BE990[68]; +short word_2BEA18; + +void sub_59C20(void) +{ + uint8_t table[256]; + int i; + word_2BEA18 = 0; + tileDelete(7059); + for (i = 0; i < numsectors; i++) + { + sector[i].extra = 256; + if (sector[i].floorpicnum == 7059) + word_2BE990[word_2BEA18++] = i; + } + for (i = 0; i < 256; i++) + table[i] = i; + lookups.makeTable(2, table, 10*4, 10*4, 24*4, 0); +} + +int dword_2BEA20, dword_2BEA24; +int dword_AABA8, dword_AABAC, dword_AABB0; + +void sub_59F80(int a1) +{ + dword_2BEA20 = 0; + dword_AABA8 = (int)totalclock; + dword_AABAC = (int)totalclock; + dword_2BEA24 = a1; + dword_AABB0 = 0; +} + +void ghmumble_randomsayit(int a1, int a2) +{ + if (a1 < 0 || a1 >= MAXSOUNDS) + { + Printf("ghmumble_randomsayit bad sndnum\n"); + return; + } + if (g_player[myconnectindex].ps->gm == MODE_GAME) + { + if ((rrdh_random() & 255) <= a2) + { + S_PlaySound(a1); + dword_AABB0 = (int)totalclock; + } + } +} + +void sub_5A02C(void) +{ + int t; + if (dword_2BEA24 > 3) + { + if (dword_2BEA20 == 512) + { + ghmumble_randomsayit(105+(rrdh_random()%2), 164); + } + dword_2BEA20 = 0; + return; + } + if ((int)totalclock - dword_AABB0 < 480) + { + dword_2BEA20 = 0; + return; + } + if (dword_2BEA20 == 0) + { + if ((int)totalclock - dword_AABA8 > 2400) + { + ghmumble_randomsayit(91 + (rrdh_random() % 4), 200); + dword_AABA8 = (int)totalclock; + dword_AABAC = (int)totalclock; + } + } + else if (dword_2BEA20 & 8) + { + ghmumble_randomsayit(100 + (rrdh_random() % 2), 200); + dword_AABA8 = (int)totalclock; + dword_AABAC = (int)totalclock; + } + else if (dword_2BEA20 & 4) + { + if (dword_2BEA20 & 32) + ghmumble_randomsayit(98 + (rrdh_random() % 2), 216); + dword_AABA8 = (int)totalclock; + dword_AABAC = (int)totalclock; + } + else if (dword_2BEA20 & 16) + { + if (dword_2BEA20 & 32) + ghmumble_randomsayit(102, 216); + dword_AABA8 = (int)totalclock; + dword_AABAC = (int)totalclock; + } + else if (dword_2BEA20 & 2048) + { + ghmumble_randomsayit(108, 250); + dword_AABA8 = (int)totalclock; + } + else if (dword_2BEA20 & 4096) + { + ghmumble_randomsayit(109, 80); + dword_AABA8 = (int)totalclock; + } + else if (dword_2BEA20 & 16384) + { + ghmumble_randomsayit(107, 255); + dword_AABA8 = (int)totalclock; + } + else if (dword_2BEA20 & 256) + { + if ((dword_2BEA20 & 64) == 0) + { + if ((int)totalclock - dword_AABAC > 7200) + { + Printf("nosightings mumble\n"); + t = rrdh_random() % 3; + if (t == 2 && dword_2BEA24 != 3) + t = 1; + ghmumble_randomsayit(95+t, 200); + dword_AABA8 = (int)totalclock; + dword_AABAC = (int)totalclock; + } + } + } + dword_2BEA20 = 0; +} + +void sub_5A250(int a1) +{ + if (a1 >= 0x10000) + return; + switch (a1) + { + case 1: + dword_2BEA20 = 0; + return; + case 2: + dword_AABA8 = (int)totalclock; + dword_AABAC = (int)totalclock; + dword_2BEA20 = 0; + return; + case 0x100: + dword_AABA8 = (int)totalclock; + break; + case 0x10: + break; + case 0x20: + case 0x40: + dword_AABAC = (int)totalclock; + break; + } + dword_2BEA20 |= a1; +} +END_DUKE_NS diff --git a/source/duke/src/rrdh.h b/source/duke/src/rrdh.h new file mode 100644 index 000000000..fae9a9075 --- /dev/null +++ b/source/duke/src/rrdh.h @@ -0,0 +1,110 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors +Copyright (C) 2020 Nuke.YKT + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#pragma once + +BEGIN_DUKE_NS + +int rrdh_random(void); +int ghcons_isanimalescapewall(short w); +int ghcons_isanimalescapesect(short s); +int ghtrophy_isakill(short a1); +int sub_535EC(void); +void ghdeploy_bias(short a1); +int ghcons_findnewspot(short a1); +void ghtrax_leavedroppings(short a1); +void ghtrax_leavetrax(short a1); +int ghtrax_isplrupwind(short a1, short a2); +int ghsound_pfiredgunnear(spritetype* a1, short a2); +int ghsound_pmadesound(spritetype* a1, short a2); +int ghsound_pmadecall(spritetype* a1, short a2); +void sub_5A250(int a1); +void sub_53304(void); +void sub_54DE0(void); +void ghtrophy_loadbestscores(void); +void sub_5A02C(void); +void sub_579A0(void); +void ghsound_ambientlooppoll(void); +int sub_51B68(void); +void sub_5469C(vec2_t const origin, int a1); +void ghstatbr_registerkillinfo(short a1, int a2, int a3); +char sub_54B80(void); +void ghpistol_fire(short snum); +void ghbow_fire(short snum); +void ghrifle_fire(short snum); +void ghshtgn_fire(short snum); +void ghsound_footstepsound(short a1, int a2); +void ghsound_plrtouchedsprite(short a1, short a2); +void ghdeploy_plrtouchedsprite(short a1, short a2); +int sub_57A40(int a1); +void sub_59C20(void); +void sub_52BA8(void); +int sub_57A60(int a1); +void sub_54A2C(void); +void sub_55F8C(void); +void sub_566F0(void); +void sub_558F4(void); +void sub_56AB8(void); +void sub_573C0(void); +void sub_59314(void); +void sub_55184(void); +void sub_57B24(void); +void sub_58388(void); +void sub_59B50(void); +void sub_59F80(int a1); +void sub_535DC(void); +void sub_57AC0(void); +void sub_566E8(void); +void sub_55F68(void); +void sub_558D0(void); +void sub_56AB0(void); +void sub_56780(void); +void sub_56020(void); +void sub_55988(void); +void sub_56B3C(void); +void sub_56724(void); +void sub_55FCC(void); +void sub_55934(void); +void sub_56AE4(void); +void ghdeploy_drop(int a1, int a2); +int sub_57AA0(int a1); +void ghtarget_hit(short a1, int a2); +void gharrow_spawnarrow(short snum); +void sub_58A30(int a1); +int sub_59B44(void); +void ghtarget_setanimal(short a1); + +void ghpistol_render(short); +void ghrifle_render(short, int); +void ghshtgn_render(short); +void ghbow_render(short); +void sub_56EA8(void); +void ghtarget_move(void); +void gharrow_move(void); +void ghdeploy_move(void); +void sub_5524C(void); +void sub_519E8(int a1); +void sub_57B38(long cposx, long cposy, long czoom, short cang); + + +END_DUKE_NS diff --git a/source/duke/src/savegame.cpp b/source/duke/src/savegame.cpp new file mode 100644 index 000000000..3e90e1b8b --- /dev/null +++ b/source/duke/src/savegame.cpp @@ -0,0 +1,1633 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- +#include "ns.h" // Must come before everything else! + +#include "duke3d.h" +#include "premap.h" +#include "prlights.h" +#include "savegame.h" +#include "i_specialpaths.h" +#include "gamecontrol.h" +#include "version.h" +#include "raze_music.h" +#include "mapinfo.h" + +#include "savegamehelp.h" +BEGIN_DUKE_NS + + +// For storing pointers in files. +// back_p==0: ptr -> "small int" +// back_p==1: "small int" -> ptr +// +// mode: see enum in savegame.h +void G_Util_PtrToIdx(void *ptr, int32_t const count, const void *base, int32_t const mode) +{ + intptr_t *iptr = (intptr_t *)ptr; + intptr_t const ibase = (intptr_t)base; + int32_t const onlynon0_p = mode&P2I_ONLYNON0_BIT; + + // TODO: convert to proper offsets/indices for (a step towards) cross- + // compatibility between 32- and 64-bit systems in the netplay. + // REMEMBER to bump BYTEVERSION then. + + // WARNING: C std doesn't say that bit pattern of NULL is necessarily 0! + if ((mode & P2I_BACK_BIT) == 0) + { + for (bssize_t i = 0; i < count; i++) + if (!onlynon0_p || iptr[i]) + iptr[i] -= ibase; + } + else + { + for (bssize_t i = 0; i < count; i++) + if (!onlynon0_p || iptr[i]) + iptr[i] += ibase; + } +} + +void G_Util_PtrToIdx2(void *ptr, int32_t const count, size_t const stride, const void *base, int32_t const mode) +{ + uint8_t *iptr = (uint8_t *)ptr; + intptr_t const ibase = (intptr_t)base; + int32_t const onlynon0_p = mode&P2I_ONLYNON0_BIT; + + if ((mode & P2I_BACK_BIT) == 0) + { + for (bssize_t i = 0; i < count; ++i) + { + if (!onlynon0_p || *(intptr_t *)iptr) + *(intptr_t *)iptr -= ibase; + + iptr += stride; + } + } + else + { + for (bssize_t i = 0; i < count; ++i) + { + if (!onlynon0_p || *(intptr_t *)iptr) + *(intptr_t *)iptr += ibase; + + iptr += stride; + } + } +} + +// TODO: sync with TROR special interpolations? (e.g. upper floor of subway) +void G_ResetInterpolations(void) +{ + int32_t k, i; + + g_interpolationCnt = 0; + + k = headspritestat[STAT_EFFECTOR]; + while (k >= 0) + { + switch (sprite[k].lotag) + { + case SE_31_FLOOR_RISE_FALL: + G_SetInterpolation(§or[sprite[k].sectnum].floorz); + break; + case SE_32_CEILING_RISE_FALL: + G_SetInterpolation(§or[sprite[k].sectnum].ceilingz); + break; + case SE_17_WARP_ELEVATOR: + case SE_25_PISTON: + G_SetInterpolation(§or[sprite[k].sectnum].floorz); + G_SetInterpolation(§or[sprite[k].sectnum].ceilingz); + break; + case SE_0_ROTATING_SECTOR: + case SE_5: + case SE_6_SUBWAY: + case SE_11_SWINGING_DOOR: + case SE_14_SUBWAY_CAR: + case SE_15_SLIDING_DOOR: + case SE_16_REACTOR: + case SE_26: + case SE_30_TWO_WAY_TRAIN: + Sect_SetInterpolation(sprite[k].sectnum); + break; + } + + k = nextspritestat[k]; + } + + for (i=g_interpolationCnt-1; i>=0; i--) bakipos[i] = *curipos[i]; + for (i = g_animateCnt-1; i>=0; i--) + G_SetInterpolation(g_animatePtr[i]); +} + + +static FileReader *OpenSavegame() +{ + auto file = ReadSavegameChunk("snapshot.dat"); + if (!file.isOpen()) + { + FinishSavegameRead(); + return nullptr; + } + return new FileReader(std::move(file)); +} + + +static void sv_postudload(); + + +// XXX: keyboard input 'blocked' after load fail? (at least ESC?) +int32_t G_LoadPlayer(const char *path) +{ + auto fil = OpenSavegame(); + + if (!fil) + return -1; + + ready2send = 0; + + savehead_t h; + int status = sv_loadheader(*fil, 0, &h); + + if (status < 0 || h.numplayers != ud.multimode) + { + if (status == -4 || status == -3 || status == 1) + P_DoQuote(QUOTE_SAVE_BAD_VERSION, g_player[myconnectindex].ps); + else if (h.numplayers != ud.multimode) + P_DoQuote(QUOTE_SAVE_BAD_PLAYERS, g_player[myconnectindex].ps); + + ototalclock = totalclock; + ready2send = 1; + + delete fil; + FinishSavegameRead(); + return 1; + } + + // some setup first + ud.multimode = h.numplayers; + S_PauseSound(true, false); + + if (numplayers > 1) + { + pub = NUMPAGES; + pus = NUMPAGES; + G_UpdateScreenArea(); + G_DrawBackground(); + menutext_center(100, "Loading..."); + videoNextPage(); + } + + Net_WaitForEverybody(); + + FX_StopAllSounds(); + S_ClearSoundLocks(); + + // non-"m_" fields will be loaded from svgm_udnetw + ud.m_volume_number = h.volnum; + m_level_number = h.levnum; + ud.m_player_skill = h.skill; + + // NOTE: Bmemcpy needed for SAVEGAME_MUSIC. + strcpy(boardfilename, currentLevel->fileName); + + char workbuffer[BMAX_PATH]; + Bstrcpy(workbuffer, currentLevel->fileName); + + if (workbuffer[0]) + { + artSetupMapArt(workbuffer); + append_ext_UNSAFE(workbuffer, ".mhk"); + engineLoadMHK(workbuffer); + } + + if ((status = sv_loadsnapshot(*fil, 0, &h))) // read the rest... + { + // in theory, we could load into an initial dump first and trivially + // recover if things go wrong... + Bsprintf(tempbuf, "Loading save game file \"%s\" failed (code %d), cannot recover.", path, status); + G_GameExit(tempbuf); + } + + sv_postudload(); // ud.m_XXX = ud.XXX + + delete fil; + FinishSavegameRead(); + return 0; +} + +////////// TIMER SAVING/RESTORING ////////// + +static struct { + int32_t totalclock, totalclocklock; // engine + int32_t ototalclock, lockclock; // game +} g_timers; + +static void G_SaveTimers(void) +{ + g_timers.totalclock = (int32_t) totalclock; + g_timers.totalclocklock = (int32_t) totalclocklock; + g_timers.ototalclock = (int32_t) ototalclock; + g_timers.lockclock = (int32_t) lockclock; +} + +static void G_RestoreTimers(void) +{ + totalclock = g_timers.totalclock; + totalclocklock = g_timers.totalclocklock; + ototalclock = g_timers.ototalclock; + lockclock = g_timers.lockclock; +} + +bool G_SavePlayer(FSaveGameNode *sv) +{ + G_SaveTimers(); + + Net_WaitForEverybody(); + ready2send = 0; + + FString fn; + + errno = 0; + FileWriter *fil; + + fil = WriteSavegameChunk("snapshot.dat"); + // The above call cannot fail. + { + auto& fw = *fil; + + // temporary hack + ud.user_map = G_HaveUserMap(); + + + // SAVE! + sv_saveandmakesnapshot(fw, 0, 0); + + + fw.Close(); + bool res = FinishSavegameWrite(); + + if (!g_netServer && ud.multimode < 2) + { + Printf("Saved: %s\n", fn.GetChars()); + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Game Saved"); + P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); + } + + ready2send = 1; + Net_WaitForEverybody(); + + G_RestoreTimers(); + ototalclock = totalclock; + + return res; + } +} + +bool GameInterface::LoadGame(FSaveGameNode* sv) +{ + if (g_netServer || ud.multimode > 1) + { + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Multiplayer Loading Not Yet Supported"); + P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); + +// g_player[myconnectindex].ps->gm = MODE_GAME; + return false; + } + else + { + int32_t c = G_LoadPlayer(sv->Filename); + if (c == 0) + g_player[myconnectindex].ps->gm = MODE_GAME; + return !c; + } +} + +bool GameInterface::SaveGame(FSaveGameNode* sv) +{ + if (g_netServer || ud.multimode > 1) + { + quoteMgr.InitializeQuote(QUOTE_RESERVED4, "Multiplayer Saving Not Yet Supported"); + P_DoQuote(QUOTE_RESERVED4, g_player[myconnectindex].ps); + return false; + } + else + { + + videoNextPage(); // no idea if this is needed here. + return G_SavePlayer(sv); + } +} + +////////// GENERIC SAVING/LOADING SYSTEM ////////// + +typedef struct dataspec_ +{ + uint32_t flags; + void * const ptr; + uint32_t size; + intptr_t cnt; +} dataspec_t; + +typedef struct dataspec_gv_ +{ + uint32_t flags; + void * ptr; + uint32_t size; + intptr_t cnt; +} dataspec_gv_t; + +#define SV_DEFAULTCOMPRTHRES 8 +static uint8_t savegame_diffcompress; // 0:none, 1:Ken's LZW in cache1d.c +static uint8_t savegame_comprthres; + + +#define DS_DYNAMIC 1 // dereference .ptr one more time +#define DS_STRING 2 +#define DS_CMP 4 +// 8 +#define DS_CNT(x) ((sizeof(x))<<3) // .cnt is pointer to... +#define DS_CNT16 16 +#define DS_CNT32 32 +#define DS_CNTMASK (8|DS_CNT16|DS_CNT32|64) +// 64 +#define DS_LOADFN 128 // .ptr is function that is run when loading +#define DS_SAVEFN 256 // .ptr is function that is run when saving +#define DS_NOCHK 1024 // don't check for diffs (and don't write out in dump) since assumed constant throughout demo +#define DS_PROTECTFN 512 +#define DS_END (0x70000000) + +static int32_t ds_getcnt(const dataspec_t *spec) +{ + int cnt = -1; + + switch (spec->flags & DS_CNTMASK) + { + case 0: cnt = spec->cnt; break; + case DS_CNT16: cnt = *((int16_t *)spec->cnt); break; + case DS_CNT32: cnt = *((int32_t *)spec->cnt); break; + } + + return cnt; +} + +static inline void ds_get(const dataspec_t *spec, void **ptr, int32_t *cnt) +{ + *cnt = ds_getcnt(spec); + *ptr = (spec->flags & DS_DYNAMIC) ? *((void **)spec->ptr) : spec->ptr; +} + +// write state to file and/or to dump +static uint8_t *writespecdata(const dataspec_t *spec, FileWriter *fil, uint8_t *dump) +{ + for (; spec->flags != DS_END; spec++) + { + if (spec->flags & (DS_SAVEFN|DS_LOADFN)) + { + if (spec->flags & DS_SAVEFN) + (*(void (*)(void))spec->ptr)(); + continue; + } + + if (!fil && (spec->flags & (DS_NOCHK|DS_CMP|DS_STRING))) + continue; + else if (spec->flags & DS_STRING) + { + fil->Write(spec->ptr, Bstrlen((const char *)spec->ptr)); // not null-terminated! + continue; + } + + void * ptr; + int32_t cnt; + + ds_get(spec, &ptr, &cnt); + + if (cnt < 0) + { + Printf("wsd: cnt=%d, f=0x%x.\n", cnt, spec->flags); + continue; + } + + if (!ptr || !cnt) + continue; + + if (fil) + { + fil->Write(ptr, spec->size * cnt); + } + + if (dump && (spec->flags & (DS_NOCHK|DS_CMP)) == 0) + { + Bmemcpy(dump, ptr, spec->size * cnt); + dump += spec->size * cnt; + } + } + return dump; +} + +// let havedump=dumpvar&&*dumpvar +// (fil>=0 && havedump): first restore dump from file, then restore state from dump +// (fil<0 && havedump): only restore state from dump +// (fil>=0 && !havedump): only restore state from file +static int32_t readspecdata(const dataspec_t *spec, FileReader *fil, uint8_t **dumpvar) +{ + uint8_t * dump = dumpvar ? *dumpvar : NULL; + auto const sptr = spec; + + for (; spec->flags != DS_END; spec++) + { + if (fil == nullptr && spec->flags & (DS_NOCHK|DS_STRING|DS_CMP)) // we're updating + continue; + + if (spec->flags & (DS_LOADFN|DS_SAVEFN)) + { + if (spec->flags & DS_LOADFN) + (*(void (*)())spec->ptr)(); + continue; + } + + if (spec->flags & (DS_STRING|DS_CMP)) // DS_STRING and DS_CMP is for static data only + { + static char cmpstrbuf[32]; + int const siz = (spec->flags & DS_STRING) ? Bstrlen((const char *)spec->ptr) : spec->size * spec->cnt; + int const ksiz = fil->Read(cmpstrbuf, siz); + + if (ksiz != siz || Bmemcmp(spec->ptr, cmpstrbuf, siz)) + { + Printf("rsd: spec=%s, idx=%d:\n", (char *)sptr->ptr, (int32_t)(spec-sptr)); + + if (ksiz!=siz) + Printf(" file read returned %d, expected %d.\n", ksiz, siz); + else + Printf(" sp->ptr and cmpstrbuf not identical!\n"); + + return -1; + } + continue; + } + + void * ptr; + int32_t cnt; + + ds_get(spec, &ptr, &cnt); + + if (cnt < 0) + { + Printf("rsd: cnt<0... wtf?\n"); + return -1; + } + + if (!ptr || !cnt) + continue; + + if (fil != nullptr && fil->isOpen()) + { + auto const mem = (dump && (spec->flags & DS_NOCHK) == 0) ? dump : (uint8_t *)ptr; + int const siz = cnt * spec->size; + int const ksiz = fil->Read(mem, siz); + + if (ksiz != siz) + { + Printf("rsd: spec=%s, idx=%d, mem=%p\n", (char *)sptr->ptr, (int32_t)(spec - sptr), mem); + Printf(" : read %d, expected %d!\n", + ksiz, siz); + + if (ksiz == -1) + Printf(" read: %s\n", strerror(errno)); + + return -1; + } + } + + if (dump && (spec->flags & DS_NOCHK) == 0) + { + Bmemcpy(ptr, dump, spec->size * cnt); + dump += spec->size * cnt; + } + } + + if (dumpvar) + *dumpvar = dump; + + return 0; +} + +#define UINT(bits) uint##bits##_t +#define BYTES(bits) (bits>>3) +#define VAL(bits,p) (*(UINT(bits) const *)(p)) +#define WVAL(bits,p) (*(UINT(bits) *)(p)) + +static void docmpsd(const void *ptr, void *dump, uint32_t size, uint32_t cnt, uint8_t **diffvar) +{ + uint8_t *retdiff = *diffvar; + + // Hail to the C preprocessor, baby! +#define CPSINGLEVAL(Datbits) \ + if (VAL(Datbits, ptr) != VAL(Datbits, dump)) \ + { \ + WVAL(Datbits, retdiff) = WVAL(Datbits, dump) = VAL(Datbits, ptr); \ + *diffvar = retdiff + BYTES(Datbits); \ + } + + if (cnt == 1) + switch (size) + { + case 8: CPSINGLEVAL(64); return; + case 4: CPSINGLEVAL(32); return; + case 2: CPSINGLEVAL(16); return; + case 1: CPSINGLEVAL(8); return; + } + +#define CPELTS(Idxbits, Datbits) \ + do \ + { \ + for (int i = 0; i < nelts; i++) \ + { \ + if (*p != *op) \ + { \ + *op = *p; \ + WVAL(Idxbits, retdiff) = i; \ + retdiff += BYTES(Idxbits); \ + WVAL(Datbits, retdiff) = *p; \ + retdiff += BYTES(Datbits); \ + } \ + p++; \ + op++; \ + } \ + WVAL(Idxbits, retdiff) = -1; \ + retdiff += BYTES(Idxbits); \ + } while (0) + +#define CPDATA(Datbits) \ + do \ + { \ + auto p = (UINT(Datbits) const *)ptr; \ + auto op = (UINT(Datbits) *)dump; \ + int nelts = tabledivide32_noinline(size * cnt, BYTES(Datbits)); \ + if (nelts > 65536) \ + CPELTS(32, Datbits); \ + else if (nelts > 256) \ + CPELTS(16, Datbits); \ + else \ + CPELTS(8, Datbits); \ + } while (0) + + if (size == 8) + CPDATA(64); + else if ((size & 3) == 0) + CPDATA(32); + else if ((size & 1) == 0) + CPDATA(16); + else + CPDATA(8); + + *diffvar = retdiff; + +#undef CPELTS +#undef CPSINGLEVAL +#undef CPDATA +} + +// get the number of elements to be monitored for changes +static int32_t getnumvar(const dataspec_t *spec) +{ + int n = 0; + for (; spec->flags != DS_END; spec++) + if (spec->flags & (DS_STRING|DS_CMP|DS_NOCHK|DS_SAVEFN|DS_LOADFN)) + ++n; + return n; +} + +// update dump at *dumpvar with new state and write diff to *diffvar +static void cmpspecdata(const dataspec_t *spec, uint8_t **dumpvar, uint8_t **diffvar) +{ + uint8_t * dump = *dumpvar; + uint8_t * diff = *diffvar; + int nbytes = (getnumvar(spec) + 7) >> 3; + int const slen = Bstrlen((const char *)spec->ptr); + + Bmemcpy(diff, spec->ptr, slen); + diff += slen; + + while (nbytes--) + *(diff++) = 0; // the bitmap of indices which elements of spec have changed go here + + int eltnum = 0; + + for (spec++; spec->flags!=DS_END; spec++) + { + if ((spec->flags&(DS_NOCHK|DS_STRING|DS_CMP))) + continue; + + if (spec->flags&(DS_LOADFN|DS_SAVEFN)) + { + if ((spec->flags&(DS_PROTECTFN))==0) + (*(void (*)())spec->ptr)(); + continue; + } + + void * ptr; + int32_t cnt; + + ds_get(spec, &ptr, &cnt); + + if (cnt < 0) + { + Printf("csd: cnt=%d, f=0x%x\n", cnt, spec->flags); + continue; + } + + uint8_t * const tmptr = diff; + + docmpsd(ptr, dump, spec->size, cnt, &diff); + + if (diff != tmptr) + (*diffvar + slen)[eltnum>>3] |= 1<<(eltnum&7); + + dump += spec->size*cnt; + eltnum++; + } + + *diffvar = diff; + *dumpvar = dump; +} + +#define VALOFS(bits,p,ofs) (*(((UINT(bits) *)(p)) + (ofs))) + +// apply diff to dump, not to state! state is restored from dump afterwards. +static int32_t applydiff(const dataspec_t *spec, uint8_t **dumpvar, uint8_t **diffvar) +{ + uint8_t * dump = *dumpvar; + uint8_t * diff = *diffvar; + int const nbytes = (getnumvar(spec)+7)>>3; + int const slen = Bstrlen((const char *)spec->ptr); + + if (Bmemcmp(diff, spec->ptr, slen)) // check STRING magic (sync check) + return 1; + + diff += slen+nbytes; + + int eltnum = -1; + for (spec++; spec->flags != DS_END; spec++) + { + if ((spec->flags & (DS_NOCHK|DS_STRING|DS_CMP|DS_LOADFN|DS_SAVEFN))) + continue; + + int const cnt = ds_getcnt(spec); + if (cnt < 0) return 1; + + eltnum++; + if (((*diffvar+slen)[eltnum>>3] & (1<<(eltnum&7))) == 0) + { + dump += spec->size * cnt; + continue; + } + +// ---------- +#define CPSINGLEVAL(Datbits) \ + WVAL(Datbits, dump) = VAL(Datbits, diff); \ + diff += BYTES(Datbits); \ + dump += BYTES(Datbits) + + if (cnt == 1) + { + switch (spec->size) + { + case 8: CPSINGLEVAL(64); continue; + case 4: CPSINGLEVAL(32); continue; + case 2: CPSINGLEVAL(16); continue; + case 1: CPSINGLEVAL(8); continue; + } + } + +#define CPELTS(Idxbits, Datbits) \ + do \ + { \ + UINT(Idxbits) idx; \ + goto readidx_##Idxbits##_##Datbits; \ + do \ + { \ + VALOFS(Datbits, dump, idx) = VAL(Datbits, diff); \ + diff += BYTES(Datbits); \ +readidx_##Idxbits##_##Datbits: \ + idx = VAL(Idxbits, diff); \ + diff += BYTES(Idxbits); \ + } while ((int##Idxbits##_t)idx != -1); \ + } while (0) + +#define CPDATA(Datbits) \ + do \ + { \ + int const elts = tabledivide32_noinline(spec->size * cnt, BYTES(Datbits)); \ + if (elts > 65536) \ + CPELTS(32, Datbits); \ + else if (elts > 256) \ + CPELTS(16, Datbits); \ + else \ + CPELTS(8, Datbits); \ + } while (0) + + if (spec->size == 8) + CPDATA(64); + else if ((spec->size & 3) == 0) + CPDATA(32); + else if ((spec->size & 1) == 0) + CPDATA(16); + else + CPDATA(8); + dump += spec->size * cnt; +// ---------- + +#undef CPELTS +#undef CPSINGLEVAL +#undef CPDATA + } + + *diffvar = diff; + *dumpvar = dump; + return 0; +} + +#undef VAL +#undef VALOFS +#undef BYTES +#undef UINT + +// calculate size needed for dump +static uint32_t calcsz(const dataspec_t *spec) +{ + uint32_t dasiz = 0; + + for (; spec->flags != DS_END; spec++) + { + // DS_STRINGs are used as sync checks in the diffs but not in the dump + if ((spec->flags & (DS_CMP|DS_NOCHK|DS_SAVEFN|DS_LOADFN|DS_STRING))) + continue; + + int const cnt = ds_getcnt(spec); + + if (cnt <= 0) + continue; + + dasiz += cnt * spec->size; + } + + return dasiz; +} + +static void sv_postactordata(); +static void sv_preanimateptrsave(); +static void sv_postanimateptr(); +static void sv_restsave(); +static void sv_restload(); +static void sv_rrrafog(); + +#define SVARDATALEN \ + ((sizeof(g_player[0].user_name)+sizeof(g_player[0].pcolor)+sizeof(g_player[0].pteam) \ + +sizeof(g_player[0].frags)+sizeof(DukePlayer_t))*MAXPLAYERS) + +static uint8_t savegame_restdata[SVARDATALEN]; + +static char svgm_udnetw_string [] = "blK:udnt"; +static const dataspec_t svgm_udnetw[] = +{ + { DS_STRING, (void *)svgm_udnetw_string, 0, 1 }, + { 0, &ud.multimode, sizeof(ud.multimode), 1 }, + { 0, &g_playerSpawnCnt, sizeof(g_playerSpawnCnt), 1 }, + { 0, &g_playerSpawnPoints, sizeof(g_playerSpawnPoints), 1 }, + + { DS_NOCHK, &ud.volume_number, sizeof(ud.volume_number), 1 }, + { DS_NOCHK, &ud.level_number, sizeof(ud.level_number), 1 }, + { DS_NOCHK, &ud.user_map, sizeof(ud.user_map), 1 }, + { DS_NOCHK, &ud.player_skill, sizeof(ud.player_skill), 1 }, + { DS_NOCHK, &ud.music_episode, sizeof(ud.music_episode), 1 }, + { DS_NOCHK, &ud.music_level, sizeof(ud.music_level), 1 }, + + { DS_NOCHK, &ud.from_bonus, sizeof(ud.from_bonus), 1 }, + { DS_NOCHK, &ud.secretlevel, sizeof(ud.secretlevel), 1 }, + { DS_NOCHK, &ud.respawn_monsters, sizeof(ud.respawn_monsters), 1 }, + { DS_NOCHK, &ud.respawn_items, sizeof(ud.respawn_items), 1 }, + { DS_NOCHK, &ud.respawn_inventory, sizeof(ud.respawn_inventory), 1 }, + { 0, &ud.god, sizeof(ud.god), 1 }, + { DS_NOCHK, &ud.monsters_off, sizeof(ud.monsters_off), 1 }, + { DS_NOCHK, &ud.last_level, sizeof(ud.last_level), 1 }, + { 0, &ud.eog, sizeof(ud.eog), 1 }, + { DS_NOCHK, &ud.coop, sizeof(ud.coop), 1 }, + { DS_NOCHK, &ud.marker, sizeof(ud.marker), 1 }, + { DS_NOCHK, &ud.ffire, sizeof(ud.ffire), 1 }, + { DS_NOCHK, &ud.noexits, sizeof(ud.noexits), 1 }, + { DS_NOCHK, &ud.playerai, sizeof(ud.playerai), 1 }, + { 0, &paused, sizeof(paused), 1 }, + { 0, connectpoint2, sizeof(connectpoint2), 1 }, + { 0, &randomseed, sizeof(randomseed), 1 }, + { 0, &g_globalRandom, sizeof(g_globalRandom), 1 }, +// { 0, &lockclock_dummy, sizeof(lockclock), 1 }, + { DS_END, 0, 0, 0 } +}; + +#if !defined DEBUG_MAIN_ARRAYS +# define DS_MAINAR DS_DYNAMIC +#else +# define DS_MAINAR 0 +#endif + +static char svgm_secwsp_string [] = "blK:swsp"; +static const dataspec_t svgm_secwsp[] = +{ + { DS_STRING, (void *)svgm_secwsp_string, 0, 1 }, + { DS_NOCHK, &g_cyclerCnt, sizeof(g_cyclerCnt), 1 }, + { DS_CNT(g_cyclerCnt), &g_cyclers[0][0], sizeof(g_cyclers[0]), (intptr_t)&g_cyclerCnt }, + { DS_NOCHK, &g_animWallCnt, sizeof(g_animWallCnt), 1 }, + { DS_CNT(g_animWallCnt), &animwall, sizeof(animwall[0]), (intptr_t)&g_animWallCnt }, + { DS_NOCHK, &g_mirrorCount, sizeof(g_mirrorCount), 1 }, + { DS_NOCHK, &g_mirrorWall[0], sizeof(g_mirrorWall[0]), ARRAY_SIZE(g_mirrorWall) }, + { DS_NOCHK, &g_mirrorSector[0], sizeof(g_mirrorSector[0]), ARRAY_SIZE(g_mirrorSector) }, + { 0, &everyothertime, sizeof(everyothertime), 1 }, + { DS_END, 0, 0, 0 } +}; + +static char svgm_script_string [] = "blK:scri"; +static const dataspec_t svgm_script[] = +{ + { DS_STRING, (void *)svgm_script_string, 0, 1 }, + { 0, &actor[0], sizeof(actor_t), MAXSPRITES }, + { DS_SAVEFN|DS_LOADFN, (void *)&sv_postactordata, 0, 1 }, + { DS_END, 0, 0, 0 } +}; + +static char svgm_anmisc_string [] = "blK:anms"; +static char svgm_end_string [] = "savegame_end"; + +static const dataspec_t svgm_anmisc[] = +{ + { DS_STRING, (void *)svgm_anmisc_string, 0, 1 }, + { 0, &g_animateCnt, sizeof(g_animateCnt), 1 }, + { 0, &g_animateSect[0], sizeof(g_animateSect[0]), MAXANIMATES }, + { 0, &g_animateGoal[0], sizeof(g_animateGoal[0]), MAXANIMATES }, + { 0, &g_animateVel[0], sizeof(g_animateVel[0]), MAXANIMATES }, + { DS_SAVEFN, (void *)&sv_preanimateptrsave, 0, 1 }, + { 0, &g_animatePtr[0], sizeof(g_animatePtr[0]), MAXANIMATES }, + { DS_SAVEFN|DS_LOADFN , (void *)&sv_postanimateptr, 0, 1 }, + { 0, &g_curViewscreen, sizeof(g_curViewscreen), 1 }, + { 0, &g_origins[0], sizeof(g_origins[0]), ARRAY_SIZE(g_origins) }, + { 0, &g_spriteDeleteQueuePos, sizeof(g_spriteDeleteQueuePos), 1 }, + { DS_NOCHK, &g_deleteQueueSize, sizeof(g_deleteQueueSize), 1 }, + { DS_CNT(g_deleteQueueSize), &SpriteDeletionQueue[0], sizeof(int16_t), (intptr_t)&g_deleteQueueSize }, + { DS_NOCHK, &g_cloudCnt, sizeof(g_cloudCnt), 1 }, + { 0, &g_cloudSect[0], sizeof(g_cloudSect), 1 }, + { 0, &g_cloudX, sizeof(g_cloudX), 1 }, + { 0, &g_cloudY, sizeof(g_cloudY), 1 }, + { 0, &g_pskyidx, sizeof(g_pskyidx), 1 }, // DS_NOCHK? + { 0, &g_earthquakeTime, sizeof(g_earthquakeTime), 1 }, + + // RR stuff + { 0, &g_spriteExtra[0], sizeof(g_spriteExtra[0]), MAXSPRITES }, + { 0, &g_sectorExtra[0], sizeof(g_sectorExtra[0]), MAXSECTORS }, + + { 0, &g_jailDoorSecHitag[0], sizeof(g_jailDoorSecHitag[0]), ARRAY_SIZE(g_jailDoorSecHitag) }, + { 0, &g_jailDoorSect[0], sizeof(g_jailDoorSect[0]), ARRAY_SIZE(g_jailDoorSect) }, + { 0, &g_jailDoorOpen[0], sizeof(g_jailDoorOpen[0]), ARRAY_SIZE(g_jailDoorOpen) }, + { 0, &g_jailDoorDir[0], sizeof(g_jailDoorDir[0]), ARRAY_SIZE(g_jailDoorDir) }, + { 0, &g_jailDoorDrag[0], sizeof(g_jailDoorDrag[0]), ARRAY_SIZE(g_jailDoorDrag) }, + { 0, &g_jailDoorDist[0], sizeof(g_jailDoorDist[0]), ARRAY_SIZE(g_jailDoorDist) }, + { 0, &g_jailDoorSpeed[0], sizeof(g_jailDoorSpeed[0]), ARRAY_SIZE(g_jailDoorSpeed) }, + { 0, &g_jailDoorSound[0], sizeof(g_jailDoorSound[0]), ARRAY_SIZE(g_jailDoorSound) }, + { 0, &g_jailDoorCnt, sizeof(g_jailDoorCnt), 1 }, + + { 0, &g_shadedSector[0], sizeof(g_shadedSector[0]), MAXSECTORS }, + + { 0, &g_mineCartSect[0], sizeof(g_mineCartSect[0]), ARRAY_SIZE(g_mineCartSect) }, + { 0, &g_mineCartChildSect[0], sizeof(g_mineCartChildSect[0]), ARRAY_SIZE(g_mineCartChildSect) }, + { 0, &g_mineCartOpen[0], sizeof(g_mineCartOpen[0]), ARRAY_SIZE(g_mineCartOpen) }, + { 0, &g_mineCartDir[0], sizeof(g_mineCartDir[0]), ARRAY_SIZE(g_mineCartDir) }, + { 0, &g_mineCartDrag[0], sizeof(g_mineCartDrag[0]), ARRAY_SIZE(g_mineCartDrag) }, + { 0, &g_mineCartDist[0], sizeof(g_mineCartDist[0]), ARRAY_SIZE(g_mineCartDist) }, + { 0, &g_mineCartSpeed[0], sizeof(g_mineCartSpeed[0]), ARRAY_SIZE(g_mineCartSpeed) }, + { 0, &g_mineCartSound[0], sizeof(g_mineCartSound[0]), ARRAY_SIZE(g_mineCartSound) }, + { 0, &g_mineCartCnt, sizeof(g_mineCartCnt), 1 }, + + { 0, &g_ambientCnt, sizeof(g_ambientCnt), 1 }, + { 0, &g_ambientHitag[0], sizeof(g_ambientHitag[0]), ARRAY_SIZE(g_ambientHitag) }, + { 0, &g_ambientLotag[0], sizeof(g_ambientLotag[0]), ARRAY_SIZE(g_ambientLotag) }, + + { 0, &g_ufoSpawn, sizeof(g_ufoSpawn), 1 }, + { 0, &g_ufoCnt, sizeof(g_ufoCnt), 1 }, + { 0, &g_hulkSpawn, sizeof(g_hulkSpawn), 1 }, + { 0, &g_lastLevel, sizeof(g_lastLevel), 1 }, + + { 0, &g_torchSector[0], sizeof(g_torchSector[0]), ARRAY_SIZE(g_torchSector) }, + { 0, &g_torchSectorShade[0], sizeof(g_torchSectorShade[0]), ARRAY_SIZE(g_torchSectorShade) }, + { 0, &g_torchType[0], sizeof(g_torchType[0]), ARRAY_SIZE(g_torchType) }, + { 0, &g_torchCnt, sizeof(g_torchCnt), 1 }, + + { 0, &g_lightninSector[0], sizeof(g_lightninSector[0]), ARRAY_SIZE(g_lightninSector) }, + { 0, &g_lightninSectorShade[0], sizeof(g_lightninSectorShade[0]), ARRAY_SIZE(g_lightninSectorShade) }, + { 0, &g_lightninCnt, sizeof(g_lightninCnt), 1 }, + + { 0, &g_geoSector[0], sizeof(g_geoSector[0]), ARRAY_SIZE(g_geoSector) }, + { 0, &g_geoSectorWarp[0], sizeof(g_geoSectorWarp[0]), ARRAY_SIZE(g_geoSectorWarp) }, + { 0, &g_geoSectorX[0], sizeof(g_geoSectorX[0]), ARRAY_SIZE(g_geoSectorX) }, + { 0, &g_geoSectorY[0], sizeof(g_geoSectorY[0]), ARRAY_SIZE(g_geoSectorY) }, + { 0, &g_geoSectorWarp2[0], sizeof(g_geoSectorWarp2[0]), ARRAY_SIZE(g_geoSectorWarp2) }, + { 0, &g_geoSectorX2[0], sizeof(g_geoSectorX2[0]), ARRAY_SIZE(g_geoSectorX2) }, + { 0, &g_geoSectorY2[0], sizeof(g_geoSectorY2[0]), ARRAY_SIZE(g_geoSectorY2) }, + { 0, &g_geoSectorCnt, sizeof(g_geoSectorCnt), 1 }, + + { 0, &g_windTime, sizeof(g_windTime), 1 }, + { 0, &g_windDir, sizeof(g_windDir), 1 }, + { 0, &g_fakeBubbaCnt, sizeof(g_fakeBubbaCnt), 1 }, + { 0, &g_mamaSpawnCnt, sizeof(g_mamaSpawnCnt), 1 }, + { 0, &g_banjoSong, sizeof(g_banjoSong), 1 }, + { 0, &g_bellTime, sizeof(g_bellTime), 1 }, + { 0, &g_bellSprite, sizeof(g_bellSprite), 1 }, + + { 0, &g_changeEnemySize, sizeof(g_changeEnemySize), 1 }, + { 0, &g_slotWin, sizeof(g_slotWin), 1 }, + { 0, &g_ufoSpawnMinion, sizeof(g_ufoSpawnMinion), 1 }, + { 0, &g_pistonSound, sizeof(g_pistonSound), 1 }, + { 0, &g_chickenWeaponTimer, sizeof(g_chickenWeaponTimer), 1 }, + { 0, &g_RAendLevel, sizeof(g_RAendLevel), 1 }, + { 0, &g_RAendEpisode, sizeof(g_RAendEpisode), 1 }, + { 0, &g_fogType, sizeof(g_fogType), 1 }, + { DS_LOADFN, (void *)sv_rrrafog, 0, 1 }, + + { DS_SAVEFN, (void *)&sv_restsave, 0, 1 }, + { 0, savegame_restdata, 1, sizeof(savegame_restdata) }, // sz/cnt swapped for kdfread + { DS_LOADFN, (void *)&sv_restload, 0, 1 }, + + { DS_STRING, (void *)svgm_end_string, 0, 1 }, + { DS_END, 0, 0, 0 } +}; + +static dataspec_gv_t *svgm_vars=NULL; +static uint8_t *dosaveplayer2(FileWriter *fil, uint8_t *mem); +static int32_t doloadplayer2(FileReader &fil, uint8_t **memptr); +static void postloadplayer(int32_t savegamep); + +// SVGM snapshot system +static uint32_t svsnapsiz; +static uint8_t *svsnapshot; +static uint8_t *svinitsnap; +static uint32_t svdiffsiz; +static uint8_t *svdiff; + +#include "gamedef.h" + +#define SV_SKIPMASK (/*GAMEVAR_SYSTEM|*/ GAMEVAR_READONLY | GAMEVAR_PTR_MASK | /*GAMEVAR_NORESET |*/ GAMEVAR_SPECIAL) + +static char svgm_vars_string [] = "blK:vars"; +// setup gamevar data spec for snapshotting and diffing... gamevars must be loaded when called +static void sv_makevarspec() +{ + int vcnt = 0; + + for (int i = 0; i < g_gameVarCount; i++) + vcnt += (aGameVars[i].flags & SV_SKIPMASK) ? 0 : 1; + + svgm_vars = (dataspec_gv_t *)Xrealloc(svgm_vars, (vcnt + 2) * sizeof(dataspec_gv_t)); + + svgm_vars[0].flags = DS_STRING; + svgm_vars[0].ptr = svgm_vars_string; + svgm_vars[0].cnt = 1; + + vcnt = 1; + + for (int i = 0; i < g_gameVarCount; i++) + { + if (aGameVars[i].flags & SV_SKIPMASK) + continue; + + unsigned const per = aGameVars[i].flags & GAMEVAR_USER_MASK; + + svgm_vars[vcnt].flags = 0; + svgm_vars[vcnt].ptr = (per == 0) ? &aGameVars[i].global : aGameVars[i].pValues; + svgm_vars[vcnt].size = sizeof(intptr_t); + svgm_vars[vcnt].cnt = (per == 0) ? 1 : (per == GAMEVAR_PERPLAYER ? MAXPLAYERS : MAXSPRITES); + + ++vcnt; + } + + svgm_vars[vcnt].flags = DS_END; + svgm_vars[vcnt].ptr = NULL; + svgm_vars[vcnt].size = 0; + svgm_vars[vcnt].cnt = 0; +} + +void sv_freemem() +{ + DO_FREE_AND_NULL(svsnapshot); + DO_FREE_AND_NULL(svinitsnap); + DO_FREE_AND_NULL(svdiff); +} + +static void SV_AllocSnap(int32_t allocinit) +{ + sv_freemem(); + + svsnapshot = (uint8_t *)Xmalloc(svsnapsiz); + if (allocinit) + svinitsnap = (uint8_t *)Xmalloc(svsnapsiz); + svdiffsiz = svsnapsiz; // theoretically it's less than could be needed in the worst case, but practically it's overkill + svdiff = (uint8_t *)Xmalloc(svdiffsiz); +} + +// make snapshot only if spot < 0 (demo) +int32_t sv_saveandmakesnapshot(FileWriter &fil, int8_t spot, bool isAutoSave) +{ + savehead_t h; + + // calculate total snapshot size + sv_makevarspec(); + svsnapsiz = calcsz((const dataspec_t *)svgm_vars); + svsnapsiz += calcsz(svgm_udnetw) + calcsz(svgm_secwsp) + calcsz(svgm_script) + calcsz(svgm_anmisc); + + + // create header + Bmemcpy(h.headerstr, "DERSAVEGAME", 11); + h.majorver = SV_MAJOR_VER; + h.minorver = SV_MINOR_VER; + h.ptrsize = sizeof(intptr_t); + + if (isAutoSave) + h.ptrsize |= 1u << 7u; + + h.bytever = BYTEVERSION; + h.userbytever = ud.userbytever; + h.scriptcrc = g_scriptcrc; + + h.reccnt = 0; + h.snapsiz = svsnapsiz; + + // the following is kinda redundant, but we save it here to be able to quickly fetch + // it in a savegame header read + + h.numplayers = ud.multimode; + h.volnum = ud.volume_number; + h.levnum = ud.level_number; + h.skill = ud.player_skill; + + if (spot >= 0) + { + // savegame + auto fw = WriteSavegameChunk("header.dat"); + fw->Write(&h, sizeof(savehead_t)); + } + else + { + // demo + // demo (currently broken, needs a new format.) + const time_t t = time(NULL); + struct tm * st = localtime(&t); + FStringf demoname("Demo %04d%02d%02d %s", st->tm_year+1900, st->tm_mon+1, st->tm_mday, GetGitDescription()); + fil.Write(&h, sizeof(savehead_t)); + + } + + + // write header + +#if 0 // not usable anymore + if (spot >= 0 && tileData(TILE_SAVESHOT)) + { + auto fw = WriteSavegameChunk("screenshot.dat"); + fw->Write(tileData(TILE_SAVESHOT), 320*200); + + } +#endif + + + if (spot >= 0) + { + // savegame + dosaveplayer2(&fil, NULL); + } + else + { + // demo + SV_AllocSnap(0); + + uint8_t * const p = dosaveplayer2(&fil, svsnapshot); + + if (p != svsnapshot+svsnapsiz) + { + Printf("sv_saveandmakesnapshot: ptr-(snapshot end)=%d!\n", (int32_t)(p - (svsnapshot + svsnapsiz))); + return 1; + } + } + + return 0; +} + +// if file is not an EDuke32 savegame/demo, h->headerstr will be all zeros +int32_t sv_loadheader(FileReader &fill, int32_t spot, savehead_t *h) +{ + FileReader filc; + FileReader* filp = &fill; + int32_t havedemo = (spot < 0); + if (!havedemo) + { + filc = ReadSavegameChunk("header.dat"); + filp = &filc; + } + + if (filp->Read(h, sizeof(savehead_t)) != sizeof(savehead_t)) + { + Printf("%s %d header corrupt.\n", havedemo ? "Demo":"Savegame", havedemo ? -spot : spot); + Bmemset(h->headerstr, 0, sizeof(h->headerstr)); + return -1; + } + + if (Bmemcmp(h->headerstr, "DERSAVEGAME", 11) + ) + { + char headerCstr[sizeof(h->headerstr) + 1]; + Bmemcpy(headerCstr, h->headerstr, sizeof(h->headerstr)); + headerCstr[sizeof(h->headerstr)] = '\0'; + Printf("%s %d header reads \"%s\", expected \"DERSAVEGAME\".\n", + havedemo ? "Demo":"Savegame", havedemo ? -spot : spot, headerCstr); + Bmemset(h->headerstr, 0, sizeof(h->headerstr)); + return -2; + } + + if (h->majorver != SV_MAJOR_VER || h->minorver != SV_MINOR_VER || h->bytever != BYTEVERSION || h->userbytever != ud.userbytever || (apScript != NULL && h->scriptcrc != g_scriptcrc)) + { +#ifndef DEBUGGINGAIDS + if (havedemo) +#endif + Printf("Incompatible savegame. Expected version %d.%d.%d.%d.%0x, found %d.%d.%d.%d.%0x\n", SV_MAJOR_VER, SV_MINOR_VER, BYTEVERSION, + ud.userbytever, g_scriptcrc, h->majorver, h->minorver, h->bytever, h->userbytever, h->scriptcrc); + + if (h->majorver == SV_MAJOR_VER && h->minorver == SV_MINOR_VER) + { + return 1; + } + else + { + Bmemset(h->headerstr, 0, sizeof(h->headerstr)); + return -3; + } + } + + if (h->getPtrSize() != sizeof(intptr_t)) + { +#ifndef DEBUGGINGAIDS + if (havedemo) +#endif + Printf("File incompatible. Expected pointer size %d, found %d\n", + (int32_t)sizeof(intptr_t), h->getPtrSize()); + + Bmemset(h->headerstr, 0, sizeof(h->headerstr)); + return -4; + } + + return 0; +} + +int32_t sv_loadsnapshot(FileReader &fil, int32_t spot, savehead_t *h) +{ + uint8_t *p; + int32_t i; + + if (spot < 0) + { + // demo + i = sv_loadheader(fil, spot, h); + if (i) + return i; + + // Used to be in doloadplayer2(), now redundant for savegames since + // we checked before. Multiplayer demos need still to be taken care of. + if (h->numplayers != numplayers) + return 9; + } + // else (if savegame), we just read the header and are now at offset sizeof(savehead_t) + +#ifdef DEBUGGINGAIDS + Printf("sv_loadsnapshot: snapshot size: %d bytes.\n", h->snapsiz); +#endif + + if (spot >= 0) + { + // savegame + i = doloadplayer2(fil, NULL); + if (i) + { + Printf("sv_loadsnapshot: doloadplayer2() returned %d.\n", i); + return 5; + } + } + else + { + svsnapsiz = h->snapsiz; + + SV_AllocSnap(1); + + p = svsnapshot; + i = doloadplayer2(fil, &p); + if (i) + { + Printf("sv_loadsnapshot: doloadplayer2() returned %d.\n", i); + sv_freemem(); + return 5; + } + + if (p != svsnapshot+svsnapsiz) + { + Printf("sv_loadsnapshot: internal error: p-(snapshot end)=%d!\n", + (int32_t)(p-(svsnapshot+svsnapsiz))); + sv_freemem(); + return 6; + } + + Bmemcpy(svinitsnap, svsnapshot, svsnapsiz); + } + + postloadplayer((spot >= 0)); + + return 0; +} + + +uint32_t sv_writediff(FileWriter *fil) +{ + uint8_t *p = svsnapshot; + uint8_t *d = svdiff; + + cmpspecdata(svgm_udnetw, &p, &d); + cmpspecdata(svgm_secwsp, &p, &d); + cmpspecdata(svgm_script, &p, &d); + cmpspecdata(svgm_anmisc, &p, &d); + cmpspecdata((const dataspec_t *)svgm_vars, &p, &d); + + if (p != svsnapshot+svsnapsiz) + Printf("sv_writediff: dump+siz=%p, p=%p!\n", svsnapshot+svsnapsiz, p); + + uint32_t const diffsiz = d - svdiff; + + fil->Write("dIfF",4); + fil->Write(&diffsiz, sizeof(diffsiz)); + + fil->Write(svdiff, diffsiz); + + return diffsiz; +} + +int32_t sv_readdiff(FileReader &fil) +{ + int32_t diffsiz; + + if (fil.Read(&diffsiz, sizeof(uint32_t)) != sizeof(uint32_t)) + return -1; + + if (fil.Read(svdiff, diffsiz) != diffsiz) + return -2; + + uint8_t *p = svsnapshot; + uint8_t *d = svdiff; + + if (applydiff(svgm_udnetw, &p, &d)) return -3; + if (applydiff(svgm_secwsp, &p, &d)) return -4; + if (applydiff(svgm_script, &p, &d)) return -5; + if (applydiff(svgm_anmisc, &p, &d)) return -6; + if (applydiff((const dataspec_t *)svgm_vars, &p, &d)) return -7; + + int i = 0; + + if (p!=svsnapshot+svsnapsiz) + i|=1; + if (d!=svdiff+diffsiz) + i|=2; + if (i) + Printf("sv_readdiff: p=%p, svsnapshot+svsnapsiz=%p; d=%p, svdiff+diffsiz=%p", + p, svsnapshot+svsnapsiz, d, svdiff+diffsiz); + return i; +} + +// SVGM data description +static void sv_postudload() +{ +#if 1 + m_level_number = ud.level_number; + ud.m_volume_number = ud.volume_number; + ud.m_player_skill = ud.player_skill; + ud.m_respawn_monsters = ud.respawn_monsters; + ud.m_respawn_items = ud.respawn_items; + ud.m_respawn_inventory = ud.respawn_inventory; + ud.m_monsters_off = ud.monsters_off; + m_coop = ud.coop; + m_marker = ud.marker; + m_ffire = ud.ffire; + m_noexits = ud.noexits; +#endif +} +//static int32_t lockclock_dummy; + + +static void sv_postactordata() +{ +#ifdef POLYMER + for (auto & i : actor) + { + i.lightptr = NULL; + i.lightId = -1; + } +#endif +} + +static void sv_preanimateptrsave() +{ + G_Util_PtrToIdx(g_animatePtr, g_animateCnt, sector, P2I_FWD); +} +static void sv_postanimateptr() +{ + G_Util_PtrToIdx(g_animatePtr, g_animateCnt, sector, P2I_BACK); +} +static void sv_restsave() +{ + uint8_t * mem = savegame_restdata; + DukePlayer_t dummy_ps; + + Bmemset(&dummy_ps, 0, sizeof(DukePlayer_t)); + +#define CPDAT(ptr,sz) do { Bmemcpy(mem, ptr, sz), mem+=sz ; } while (0) + for (int i = 0; i < MAXPLAYERS; i++) + { + CPDAT(g_player[i].user_name, 32); + CPDAT(&g_player[i].pcolor, sizeof(g_player[0].pcolor)); + CPDAT(&g_player[i].pteam, sizeof(g_player[0].pteam)); + CPDAT(&g_player[i].frags[0], sizeof(g_player[0].frags)); + CPDAT(g_player[i].ps ? g_player[i].ps : &dummy_ps, sizeof(DukePlayer_t)); + } + + Bassert((savegame_restdata + SVARDATALEN) - mem == 0); +#undef CPDAT +} +static void sv_restload() +{ + uint8_t * mem = savegame_restdata; + DukePlayer_t dummy_ps; + +#define CPDAT(ptr,sz) Bmemcpy(ptr, mem, sz), mem+=sz + for (int i = 0; i < MAXPLAYERS; i++) + { + CPDAT(g_player[i].user_name, 32); + CPDAT(&g_player[i].pcolor, sizeof(g_player[0].pcolor)); + CPDAT(&g_player[i].pteam, sizeof(g_player[0].pteam)); + CPDAT(&g_player[i].frags[0], sizeof(g_player[0].frags)); + CPDAT(g_player[i].ps ? g_player[i].ps : &dummy_ps, sizeof(DukePlayer_t)); + } +#undef CPDAT + + if (g_player[myconnectindex].ps) + g_player[myconnectindex].ps->auto_aim = cl_autoaim; +} + +#ifdef DEBUGGINGAIDS +# define PRINTSIZE(name) do { if (mem) Printf(name ": %d\n", (int32_t)(mem-tmem)); \ + Printf(name ": %d ms\n", timerGetTicks()-t); t=timerGetTicks(); tmem=mem; } while (0) +#else +# define PRINTSIZE(name) do { } while (0) +#endif + +static uint8_t *dosaveplayer2(FileWriter *fil, uint8_t *mem) +{ +#ifdef DEBUGGINGAIDS + uint8_t *tmem = mem; + int32_t t=timerGetTicks(); +#endif + mem=writespecdata(svgm_udnetw, fil, mem); // user settings, players & net + PRINTSIZE("ud"); + mem=writespecdata(svgm_secwsp, fil, mem); // sector, wall, sprite + PRINTSIZE("sws"); + mem=writespecdata(svgm_script, fil, mem); // script + PRINTSIZE("script"); + mem=writespecdata(svgm_anmisc, fil, mem); // animates, quotes & misc. + PRINTSIZE("animisc"); + Gv_WriteSave(*fil); // gamevars + mem=writespecdata((const dataspec_t *)svgm_vars, 0, mem); + PRINTSIZE("vars"); + + return mem; +} + +static int32_t doloadplayer2(FileReader &fil, uint8_t **memptr) +{ + uint8_t *mem = memptr ? *memptr : NULL; +#ifdef DEBUGGINGAIDS + uint8_t *tmem=mem; + int32_t t=timerGetTicks(); +#endif + if (readspecdata(svgm_udnetw, &fil, &mem)) return -2; + PRINTSIZE("ud"); + if (readspecdata(svgm_secwsp, &fil, &mem)) return -4; + PRINTSIZE("sws"); + if (readspecdata(svgm_script, &fil, &mem)) return -5; + PRINTSIZE("script"); + if (readspecdata(svgm_anmisc, &fil, &mem)) return -6; + PRINTSIZE("animisc"); + + int i; + + if ((i = Gv_ReadSave(fil))) return i; + + if (mem) + { + int32_t i; + + sv_makevarspec(); + for (i=1; svgm_vars[i].flags!=DS_END; i++) + { + Bmemcpy(mem, svgm_vars[i].ptr, svgm_vars[i].size*svgm_vars[i].cnt); // careful! works because there are no DS_DYNAMIC's! + mem += svgm_vars[i].size*svgm_vars[i].cnt; + } + } + PRINTSIZE("vars"); + + if (memptr) + *memptr = mem; + return 0; +} + +int32_t sv_updatestate(int32_t frominit) +{ + uint8_t *p = svsnapshot, *pbeg=p; + + if (frominit) + Bmemcpy(svsnapshot, svinitsnap, svsnapsiz); + + if (readspecdata(svgm_udnetw, nullptr, &p)) return -2; + if (readspecdata(svgm_secwsp, nullptr, &p)) return -4; + if (readspecdata(svgm_script, nullptr, &p)) return -5; + if (readspecdata(svgm_anmisc, nullptr, &p)) return -6; + if (readspecdata((const dataspec_t *)svgm_vars, nullptr, &p)) return -8; + + if (p != pbeg+svsnapsiz) + { + Printf("sv_updatestate: ptr-(snapshot end)=%d\n", (int32_t)(p-(pbeg+svsnapsiz))); + return -9; + } + + if (frominit) + postloadplayer(0); +#ifdef POLYMER + if (videoGetRenderMode() == REND_POLYMER) + polymer_resetlights(); // must do it after polymer_loadboard() !!! +#endif + + return 0; +} + +static void sv_rrrafog() +{ + G_SetFog(g_fogType ? 2 : 0); +} + +static void postloadplayer(int32_t savegamep) +{ + int32_t i; + + //1 + if (g_player[myconnectindex].ps->over_shoulder_on != 0) + { + CAMERADIST = 0; + CAMERACLOCK = 0; + g_player[myconnectindex].ps->over_shoulder_on = 1; + } + + //2 + screenpeek = myconnectindex; + + //2.5 + if (savegamep) + { + Bmemset(gotpic, 0, sizeof(gotpic)); + S_ClearSoundLocks(); + G_CacheMapData(); + Mus_ResumeSaved(); + Mus_SetPaused(false); + + g_player[myconnectindex].ps->gm = MODE_GAME; + ud.recstat = 0; + + if (g_player[myconnectindex].ps->jetpack_on) + A_PlaySound(DUKE_JETPACK_IDLE, g_player[myconnectindex].ps->i); + } + + //3 + P_UpdateScreenPal(g_player[myconnectindex].ps); + g_restorePalette = -1; + + //3.5 + if (savegamep) + { + for (SPRITES_OF(STAT_FX, i)) + if (sprite[i].picnum == MUSICANDSFX) + { + T2(i) = SoundEnabled(); + T1(i) = 0; + } + + G_UpdateScreenArea(); + FX_SetReverb(0); + } + + //4 + if (savegamep) + { + if (adult_lockout) + { + for (i=0; i= 0) + wall[animwall[i].wallnum].picnum = wall[animwall[i].wallnum].extra; + } +#endif + } + + //5 + G_ResetInterpolations(); + + //6 + g_showShareware = 0; + if (savegamep) + everyothertime = 0; + + //7 + for (i=0; idrug_timer = 0; + + G_InitRRRASkies(); +} + +////////// END GENERIC SAVING/LOADING SYSTEM ////////// + + +END_DUKE_NS diff --git a/source/duke/src/savegame.h b/source/duke/src/savegame.h new file mode 100644 index 000000000..ead6a8a57 --- /dev/null +++ b/source/duke/src/savegame.h @@ -0,0 +1,85 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef savegame_h_ +#define savegame_h_ + +#include "game.h" + +BEGIN_DUKE_NS + +# define SV_MAJOR_VER 1 +#define SV_MINOR_VER 7 + +#pragma pack(push,1) +struct savehead_t +{ + char headerstr[11]; + uint8_t majorver, minorver, ptrsize; + uint16_t bytever; + // 16 bytes + + uint32_t userbytever; + uint32_t scriptcrc; + + uint8_t recdiffsp; + // 4 bytes + + int32_t reccnt, snapsiz; + // 8 bytes + + uint8_t numplayers, volnum, levnum, skill; + // 286 bytes + + uint8_t getPtrSize() const { return ptrsize; } +}; +#pragma pack(pop) + +int32_t sv_updatestate(int32_t frominit); +int32_t sv_readdiff(FileReader& fil); +uint32_t sv_writediff(FileWriter *fil); +int32_t sv_loadheader(FileReader &fil, int32_t spot, savehead_t *h); +int32_t sv_loadsnapshot(FileReader &fil, int32_t spot, savehead_t *h); +int32_t sv_saveandmakesnapshot(FileWriter &fil, int8_t spot, bool isAutoSave = false); +void sv_freemem(); + +// XXX: The 'bitptr' decl really belongs into gamedef.h, but we don't want to +// pull all of it in savegame.c? +extern char *bitptr; + +enum +{ + P2I_BACK_BIT = 1, + P2I_ONLYNON0_BIT = 2, + + P2I_FWD = 0, + P2I_BACK = 1, + + P2I_FWD_NON0 = 0+2, + P2I_BACK_NON0 = 1+2, +}; +void G_Util_PtrToIdx(void *ptr, int32_t count, const void *base, int32_t mode); +void G_Util_PtrToIdx2(void *ptr, int32_t count, size_t stride, const void *base, int32_t const mode); + +END_DUKE_NS + +#endif diff --git a/source/duke/src/sbar.cpp b/source/duke/src/sbar.cpp new file mode 100644 index 000000000..193539593 --- /dev/null +++ b/source/duke/src/sbar.cpp @@ -0,0 +1,1541 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- +#include "ns.h" // Must come before everything else! + +#include "v_font.h" +#include "duke3d.h" +#include "compat.h" +#include "sbar.h" + +BEGIN_DUKE_NS + + +void InitFonts() +{ + GlyphSet fontdata; + + // Small font + for (int i = 0; i < 95; i++) + { + auto tile = tileGetTexture(STARTALPHANUM + i); + if (tile && tile->GetTexelWidth() > 0 && tile->GetTexelHeight() > 0) + fontdata.Insert('!' + i, tile); + } + SmallFont = new ::FFont("SmallFont", nullptr, "defsmallfont", 0, 0, 0, -1, -1, false, false, false, &fontdata); + fontdata.Clear(); + + // Big font + + // This font is VERY messy... + fontdata.Insert('_', tileGetTexture(BIGALPHANUM - 11)); + fontdata.Insert('-', tileGetTexture(BIGALPHANUM - 11)); + for (int i = 0; i < 10; i++) fontdata.Insert('0' + i, tileGetTexture(BIGALPHANUM - 10 + i)); + for (int i = 0; i < 26; i++) fontdata.Insert('A' + i, tileGetTexture(BIGALPHANUM + i)); + fontdata.Insert('.', tileGetTexture(BIGPERIOD)); + fontdata.Insert(',', tileGetTexture(BIGCOMMA)); + fontdata.Insert('!', tileGetTexture(BIGX_)); + fontdata.Insert('?', tileGetTexture(BIGQ)); + fontdata.Insert(';', tileGetTexture(BIGSEMI)); + fontdata.Insert(':', tileGetTexture(BIGCOLIN)); + fontdata.Insert('\\', tileGetTexture(BIGALPHANUM + 68)); + fontdata.Insert('/', tileGetTexture(BIGALPHANUM + 68)); + fontdata.Insert('%', tileGetTexture(BIGALPHANUM + 69)); + fontdata.Insert('`', tileGetTexture(BIGAPPOS)); + fontdata.Insert('"', tileGetTexture(BIGAPPOS)); + fontdata.Insert('\'', tileGetTexture(BIGAPPOS)); + BigFont = new ::FFont("BigFont", nullptr, "defbigfont", 0, 0, 0, -1, -1, false, false, false, &fontdata); + fontdata.Clear(); + + // Tiny font + for (int i = 0; i < 95; i++) + { + auto tile = tileGetTexture(MINIFONT + i); + if (tile && tile->GetTexelWidth() > 0 && tile->GetTexelHeight() > 0) + fontdata.Insert('!' + i, tile); + } + SmallFont2 = new ::FFont("SmallFont2", nullptr, "defsmallfont2", 0, 0, 0, -1, -1, false, false, false, &fontdata); + fontdata.Clear(); + + // SBAR index font + for (int i = 0; i < 10; i++) fontdata.Insert('0' + i, tileGetTexture(THREEBYFIVE + i)); + fontdata.Insert(':', tileGetTexture(THREEBYFIVE + 10)); + fontdata.Insert('/', tileGetTexture(THREEBYFIVE + 11)); + new ::FFont("IndexFont", nullptr, nullptr, 0, 0, 0, -1, -1, false, false, false, &fontdata); + +} + +static int32_t sbarx(int32_t x) +{ + if (ud.screen_size == 4) return sbarsc(x<<16); + return (((320<<16) - sbarsc(320<<16)) >> 1) + sbarsc(x<<16); +} + +static int32_t sbarxr(int32_t x) +{ + if (ud.screen_size == 4) return (320<<16) - sbarsc(x<<16); + return (((320<<16) - sbarsc(320<<16)) >> 1) + sbarsc(x<<16); +} + +static int32_t sbary(int32_t y) +{ + if (hud_position == 1 && ud.screen_size == 4 && ud.althud == 1) return sbarsc(y << 16); + else return (200<<16) - sbarsc(200<<16) + sbarsc(y<<16); +} + +int32_t sbarx16(int32_t x) +{ + if (ud.screen_size == 4) return sbarsc(x); + return (((320<<16) - sbarsc(320<<16)) >> 1) + sbarsc(x); +} + +int32_t sbarxr16(int32_t x) +{ + if (ud.screen_size == 4) return (320<<16) - sbarsc(x); + return (((320<<16) - sbarsc(320<<16)) >> 1) + sbarsc(x); +} + +#if 0 // enable if ever needed +static int32_t sbarxr16(int32_t x) +{ + if (ud.screen_size == 4) return (320<<16) - sbarsc(x); + return (((320<<16) - sbarsc(320<<16)) >> 1) + sbarsc(x); +} +#endif + +int32_t sbary16(int32_t y) +{ + return (200<<16) - sbarsc(200<<16) + sbarsc(y); +} + +static void G_PatchStatusBar(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t aspectCorrect = 1) +{ + int32_t const scl = sbarsc(RR ? 32768 : 65536); + int32_t const tx = sbarx16((160<<16) - (tilesiz[BOTTOMSTATUSBAR].x<<(RR ? 14 : 15))); // centered + int32_t const ty = sbary(200-(tilesiz[BOTTOMSTATUSBAR].y>>(RR ? 1 : 0))); + // Assumed to be 4:3 aspect ratio + int32_t const xdimcorrect = aspectCorrect ? (4 * ydim) / 3 : xdim; + + int32_t const clx1 = sbarsc(scale(x1, xdimcorrect, 320)), cly1 = sbarsc(scale(y1, ydim, 200)); + int32_t const clx2 = sbarsc(scale(x2, xdimcorrect, 320)), cly2 = sbarsc(scale(y2, ydim, 200)); + int32_t const clofx = (xdim - sbarsc(xdimcorrect)) >> 1, clofy = (ydim - sbarsc(ydim)); + + rotatesprite(tx, ty, scl, 0, BOTTOMSTATUSBAR, 4, 0, 10+16+64, clx1+clofx, cly1+clofy, clx2+clofx-1, cly2+clofy-1); +} + +static void G_PatchStatusBar2(int32_t x1, int32_t y1, int32_t x2, int32_t y2) +{ + if (!RR) + return; + int32_t const scl = sbarsc(32768); + int32_t const tx = sbarx16((160<<16) - (tilesiz[WEAPONBAR].x<<14)); // centered + int32_t const ty = sbary(200-tilesiz[BOTTOMSTATUSBAR].y/2-tilesiz[WEAPONBAR].y/2); + // Assumed to be 4:3 aspect ratio + int32_t const xdimcorrect = (4 * ydim) / 3; + + int32_t const clx1 = sbarsc(scale(x1, xdimcorrect, 320)), cly1 = sbarsc(scale(y1, ydim, 200)); + int32_t const clx2 = sbarsc(scale(x2, xdimcorrect, 320)), cly2 = sbarsc(scale(y2, ydim, 200)); + int32_t const clofx = (xdim - sbarsc(xdimcorrect)) >> 1, clofy = (ydim - sbarsc(ydim)); + + rotatesprite(tx, ty, scl, 0, WEAPONBAR, 4, 0, 10+16+64, clx1+clofx, cly1+clofy, clx2+clofx-1, cly2+clofy-1); +} + +#define POLYMOSTTRANS (1) +#define POLYMOSTTRANS2 (1|32) + +// Draws inventory numbers in the HUD for both the full and mini status bars. +// yofs: in hud_scale-independent, (<<16)-scaled, 0-200-normalized y coords. +static void G_DrawInvNum(int32_t x, int32_t yofs, int32_t y, char num1, char ha, int32_t sbits) +{ + char dabuf[16]; + int32_t shd = (x < 0); + + const int32_t sbscale = sbarsc(RR ? 32768 : 65536); + const int32_t sby = yofs+sbary(y), sbyp1 = yofs+sbary(y+1), sbym1 = yofs+sbary(y-1); + + if (shd) x = -x; + + Bsprintf(dabuf, "%d", num1); + + if (sbits & RS_ALIGN_R) + { + if (num1 > 99) + { + if (shd && ud.screen_size == 4 && videoGetRenderMode() >= REND_POLYMOST && althud_shadows) + { + rotatesprite_fs(sbarxr(x+4+1), RR ? sby : sbyp1, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', 127, 4, POLYMOSTTRANS|sbits); + rotatesprite_fs(sbarxr(x-1), sbyp1, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', 127, 4, POLYMOSTTRANS|sbits); + rotatesprite_fs(sbarxr(x-4+1), sbyp1, sbscale, 0, THREEBYFIVE+dabuf[2]-'0', 127, 4, POLYMOSTTRANS|sbits); + } + + rotatesprite_fs(sbarxr(x+4), RR ? sbym1 : sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, sbits); + rotatesprite_fs(sbarxr(x), sby, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', ha, 0, sbits); + rotatesprite_fs(sbarxr(x-4), sby, sbscale, 0, THREEBYFIVE+dabuf[2]-'0', ha, 0, sbits); + return; + } + + if (num1 > 9) + { + if (shd && ud.screen_size == 4 && videoGetRenderMode() >= REND_POLYMOST && althud_shadows) + { + rotatesprite_fs(sbarxr(x+1), sbyp1, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', 127, 4, POLYMOSTTRANS|sbits); + rotatesprite_fs(sbarxr(x-4-1), sbyp1, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', 127, 4, POLYMOSTTRANS|sbits); + } + + rotatesprite_fs(sbarxr(x), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, sbits); + rotatesprite_fs(sbarxr(x-4), sby, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', ha, 0, sbits); + return; + } + + rotatesprite_fs(sbarxr(x-4+1), sbyp1, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 4, sbits); + rotatesprite_fs(sbarxr(x-4), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, sbits); + return; + } + + if (num1 > 99) + { + if (shd && ud.screen_size == 4 && videoGetRenderMode() >= REND_POLYMOST && althud_shadows) + { + rotatesprite_fs(sbarx(x-4+1), RR ? sby : sbyp1, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', 127, 4, POLYMOSTTRANS|sbits); + rotatesprite_fs(sbarx(x+1), sbyp1, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', 127, 4, POLYMOSTTRANS|sbits); + rotatesprite_fs(sbarx(x+4+1), sbyp1, sbscale, 0, THREEBYFIVE+dabuf[2]-'0', 127, 4, POLYMOSTTRANS|sbits); + } + + rotatesprite_fs(sbarx(x-4), RR ? sbym1 : sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, sbits); + rotatesprite_fs(sbarx(x), sby, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', ha, 0, sbits); + rotatesprite_fs(sbarx(x+4), sby, sbscale, 0, THREEBYFIVE+dabuf[2]-'0', ha, 0, sbits); + return; + } + + if (num1 > 9) + { + if (shd && ud.screen_size == 4 && videoGetRenderMode() >= REND_POLYMOST && althud_shadows) + { + rotatesprite_fs(sbarx(x+1), sbyp1, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', 127, 4, POLYMOSTTRANS|sbits); + rotatesprite_fs(sbarx(x+4+1), sbyp1, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', 127, 4, POLYMOSTTRANS|sbits); + } + + rotatesprite_fs(sbarx(x), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, sbits); + rotatesprite_fs(sbarx(x+4), sby, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', ha, 0, sbits); + return; + } + + rotatesprite_fs(sbarx(x+4+1), sbyp1, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 4, sbits); + rotatesprite_fs(sbarx(x+4), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, sbits); +} + +static void G_DrawWeapNum(int16_t ind, int32_t x, int32_t y, int32_t num1, int32_t num2, int32_t ha) +{ + char dabuf[16]; + + const int32_t sbscale = sbarsc(65536); + const int32_t sby = sbary(y); + + rotatesprite_fs(sbarx(x-7), sby, sbscale, 0, THREEBYFIVE+ind+1, ha-10, 7, 10); + rotatesprite_fs(sbarx(x-3), sby, sbscale, 0, THREEBYFIVE+10, ha, 0, 10); + + if (VOLUMEONE && (ind > HANDBOMB_WEAPON || ind < 0)) + { + minitextshade(x+1, y-4, "ORDER", 20, 11, 2+8+16+ROTATESPRITE_MAX); + return; + } + + rotatesprite_fs(sbarx(x+9), sby, sbscale, 0, THREEBYFIVE+11, ha, 0, 10); + + if (num1 > 99) num1 = 99; + if (num2 > 99) num2 = 99; + + Bsprintf(dabuf, "%d", num1); + if (num1 > 9) + { + rotatesprite_fs(sbarx(x), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, 10); + rotatesprite_fs(sbarx(x+4), sby, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', ha, 0, 10); + } + else rotatesprite_fs(sbarx(x+4), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, 10); + + Bsprintf(dabuf, "%d", num2); + if (num2 > 9) + { + rotatesprite_fs(sbarx(x+13), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, 10); + rotatesprite_fs(sbarx(x+17), sby, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', ha, 0, 10); + return; + } + rotatesprite_fs(sbarx(x+13), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, 10); +} + +static void G_DrawWeapNum2(char ind, int32_t x, int32_t y, int32_t num1, int32_t num2, char ha) +{ + char dabuf[16]; + + const int32_t sbscale = sbarsc(65536); + const int32_t sby = sbary(y); + + rotatesprite_fs(sbarx(x-7), sby, sbscale, 0, THREEBYFIVE+ind+1, ha-10, 7, 10); + rotatesprite_fs(sbarx(x-4), sby, sbscale, 0, THREEBYFIVE+10, ha, 0, 10); + rotatesprite_fs(sbarx(x+13), sby, sbscale, 0, THREEBYFIVE+11, ha, 0, 10); + + Bsprintf(dabuf, "%d", num1); + if (num1 > 99) + { + rotatesprite_fs(sbarx(x), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, 10); + rotatesprite_fs(sbarx(x+4), sby, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', ha, 0, 10); + rotatesprite_fs(sbarx(x+8), sby, sbscale, 0, THREEBYFIVE+dabuf[2]-'0', ha, 0, 10); + } + else if (num1 > 9) + { + rotatesprite_fs(sbarx(x+4), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, 10); + rotatesprite_fs(sbarx(x+8), sby, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', ha, 0, 10); + } + else rotatesprite_fs(sbarx(x+8), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, 10); + + Bsprintf(dabuf, "%d", num2); + if (num2 > 99) + { + rotatesprite_fs(sbarx(x+17), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, 10); + rotatesprite_fs(sbarx(x+21), sby, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', ha, 0, 10); + rotatesprite_fs(sbarx(x+25), sby, sbscale, 0, THREEBYFIVE+dabuf[2]-'0', ha, 0, 10); + } + else if (num2 > 9) + { + rotatesprite_fs(sbarx(x+17), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, 10); + rotatesprite_fs(sbarx(x+21), sby, sbscale, 0, THREEBYFIVE+dabuf[1]-'0', ha, 0, 10); + return; + } + else + rotatesprite_fs(sbarx(x+25), sby, sbscale, 0, THREEBYFIVE+dabuf[0]-'0', ha, 0, 10); +} + +static void G_DrawWeapAmounts(const DukePlayer_t *p, int32_t x, int32_t y, int32_t u) +{ + int32_t cw = p->curr_weapon; + + if (u&4) + { + if (u != -1) G_PatchStatusBar(88, 178, 88+37, 178+6); //original code: (96,178,96+12,178+6); + G_DrawWeapNum2(PISTOL_WEAPON, x, y, + p->ammo_amount[PISTOL_WEAPON], p->max_ammo_amount[PISTOL_WEAPON], + 12-20*(cw == PISTOL_WEAPON)); + } + if (u&8) + { + if (u != -1) G_PatchStatusBar(88, 184, 88+37, 184+6); //original code: (96,184,96+12,184+6); + G_DrawWeapNum2(SHOTGUN_WEAPON, x, y+6, + p->ammo_amount[SHOTGUN_WEAPON], p->max_ammo_amount[SHOTGUN_WEAPON], + (((p->gotweapon & (1<ammo_amount[CHAINGUN_WEAPON], p->max_ammo_amount[CHAINGUN_WEAPON], + (((p->gotweapon & (1<ammo_amount[RPG_WEAPON], p->max_ammo_amount[RPG_WEAPON], + (((p->gotweapon & (1<ammo_amount[HANDBOMB_WEAPON], p->max_ammo_amount[HANDBOMB_WEAPON], + (((!p->ammo_amount[HANDBOMB_WEAPON])|((p->gotweapon & (1<subweapon&(1<ammo_amount[GROW_WEAPON], p->max_ammo_amount[GROW_WEAPON], + (((p->gotweapon & (1<ammo_amount[SHRINKER_WEAPON], p->max_ammo_amount[SHRINKER_WEAPON], + (((p->gotweapon & (1<ammo_amount[DEVISTATOR_WEAPON], p->max_ammo_amount[DEVISTATOR_WEAPON], + (((p->gotweapon & (1<ammo_amount[TRIPBOMB_WEAPON], p->max_ammo_amount[TRIPBOMB_WEAPON], + (((p->gotweapon & (1<ammo_amount[FREEZE_WEAPON], p->max_ammo_amount[FREEZE_WEAPON], + (((p->gotweapon & (1<=0; k--) + { + p = althud_numbertile + b[k]-'0'; + j += (tilesiz[p].x>>(RR?1:0))+1; + } + c = x-(j>>1); + + if (rev) + { + for (k=0; k= REND_POLYMOST && althud_shadows) + rotatesprite_fs(sbarxr(c+j-1), sbary(y+1), sbscale, 0, p, 127, 4, cs|POLYMOSTTRANS2); + rotatesprite_fs(sbarxr(c+j), sbary(y), sbscale, 0, p, s, althud_numberpal, cs); + j -= (tilesiz[p].x>>(RR?1:0))+1; + } + return; + } + + j = 0; + for (k=0; k= REND_POLYMOST && althud_shadows) + rotatesprite_fs(sbarx(c+j+1), sbary(y+1), sbscale, 0, p, 127, 4, cs|POLYMOSTTRANS2); + rotatesprite_fs(sbarx(c+j), sbary(y), sbscale, 0, p, s, althud_numberpal, cs); + j += (tilesiz[p].x>>(RR?1:0))+1; + } +} + +static int32_t invensc(int32_t maximum) // used to reposition the inventory icon selector as the HUD scales +{ + return scale(maximum << 16, ud.statusbarscale - 36, 100 - 36); +} + +void G_DrawInventory(const DukePlayer_t *p) +{ + int32_t n, j = 0, x = 0, y; + + n = (p->inv_amount[GET_JETPACK] > 0)<<3; + if (n&8) j++; + n |= (p->inv_amount[GET_SCUBA] > 0)<<5; + if (n&32) j++; + n |= (p->inv_amount[GET_STEROIDS] > 0)<<1; + if (n&2) j++; + n |= (p->inv_amount[GET_HOLODUKE] > 0)<<2; + if (n&4) j++; + n |= (p->inv_amount[GET_FIRSTAID] > 0); + if (n&1) j++; + n |= (p->inv_amount[GET_HEATS] > 0)<<4; + if (n&16) j++; + n |= (p->inv_amount[GET_BOOTS] > 0)<<6; + if (n&64) j++; + + x = (160-(j*11))<<16; // nearly center + + j = 0; + + if (ud.screen_size < 8) // mini-HUDs or no HUD + { + y = RR ? 180<<16 : 172<<16; + + if (ud.screen_size == 4 && ud.althud == 1) // modern mini-HUD + y -= invensc(tilesiz[BIGALPHANUM].y+10); // slide on the y-axis + } + else // full HUD + { + y = (200<<16) - (sbarsc(tilesiz[BOTTOMSTATUSBAR].y<<(RR ? 15 : 16)) + (RR ? (6<<16) : (12<<16)) + (tilesiz[BOTTOMSTATUSBAR].y<<((RR ? 15 : 16)-1))); + + if (!ud.statusbarmode) // original non-overlay mode + y += sbarsc(tilesiz[BOTTOMSTATUSBAR].y<<(RR ? 15 : 16))>>1; // account for the viewport y-size as the HUD scales + } + + if (ud.screen_size == 4 && !ud.althud) // classic mini-HUD + x += invensc(ud.multimode > 1 ? 56 : 65); // slide on the x-axis + + while (j <= 9) + { + const int iconscale = RR ? 32768 : 65536; + if (n&(1<inven_icon == j+1) + rotatesprite_win(x-(2<<16), y+(19<<16), iconscale, 1024, ARROW, -32, 0, 2+16); + } + + j++; + } +} + +void G_DrawFrags(void) +{ + if (ud.statusbarflags & STATUSBAR_NOFRAGBAR) + return; + + int32_t i, j = 0; + const int32_t orient = 2+8+16+64; + + for (TRAVERSE_CONNECT(i)) + if (i > j) + j = i; + + for (i=0; i<=(j>>2); i++) + rotatesprite_fs(0, (8*i)<<16, RR ? 32800 : 65600, 0, FRAGBAR, 0, 0, orient); + + for (TRAVERSE_CONNECT(i)) + { + const DukePlayer_t *ps = g_player[i].ps; + minitext(21+(73*(i&3)), 2+((i&28)<<1), g_player[i].user_name, ps->palookup, 2+8+16); + Bsprintf(tempbuf, "%d", ps->frag-ps->fraggedself); + minitext(17+50+(73*(i&3)), 2+((i&28)<<1), tempbuf, ps->palookup, 2+8+16); + } +} + +static int32_t G_GetInvAmount(const DukePlayer_t *p) +{ + switch (p->inven_icon) + { + case ICON_FIRSTAID: + return p->inv_amount[GET_FIRSTAID]; + case ICON_STEROIDS: + return (p->inv_amount[GET_STEROIDS]+3)>>2; + case ICON_HOLODUKE: + if (RR) return p->inv_amount[GET_HOLODUKE]/400; + return (p->inv_amount[GET_HOLODUKE]+15)/24; + case ICON_JETPACK: + if (RR) return p->inv_amount[GET_JETPACK]/100; + return (p->inv_amount[GET_JETPACK]+15)>>4; + case ICON_HEATS: + return p->inv_amount[GET_HEATS]/12; + case ICON_SCUBA: + return (p->inv_amount[GET_SCUBA]+63)>>6; + case ICON_BOOTS: + if (RR) return (p->inv_amount[GET_BOOTS]/10)>>1; + return p->inv_amount[GET_BOOTS]>>1; + } + + return -1; +} + +static void G_DrawWeaponBar(const DukePlayer_t *p) +{ + const int32_t sbscale = sbarsc(32800); + const int32_t SBY = (200-tilesiz[BOTTOMSTATUSBAR].y/2); + rotatesprite_fs(sbarx(0), sbary(158), sbscale, 0, WEAPONBAR, 0, 0, 10+16+64); + for (int i = 0; i < 9; i++) { + if (RRRA && i == 4 && p->curr_weapon == CHICKEN_WEAPON) + { + rotatesprite_fs(sbarx(18+i*32), sbary(SBY-6), sbscale, 0, AMMO_ICON + 10, 0, 0, 10+16+64); + G_DrawInvNum(38+i*32, 0, 162, (char)p->ammo_amount[CHICKEN_WEAPON], 0, 10); + } + else + { + if (p->gotweapon&(1 << (i + 1))) { + rotatesprite_fs(sbarx(18+i*32), sbary(SBY-6), sbscale, 0, AMMO_ICON + i, 0, 0, 10+16+64); + } + G_DrawInvNum(38+i*32, 0, SBY-4, (char)p->ammo_amount[i+1], 0, 10); + } + } +} + +static int32_t G_GetInvOn(const DukePlayer_t *p) +{ + switch (p->inven_icon) + { + case ICON_HOLODUKE: + return p->holoduke_on; + case ICON_JETPACK: + return p->jetpack_on; + case ICON_HEATS: + return p->heat_on; + } + + return 0x80000000; +} + +static int32_t G_GetMorale(int32_t p_i, int32_t snum) +{ + return Gv_GetVarByLabel("PLR_MORALE", -1, p_i, snum); +} + +static inline void rotatesprite_althud(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum, int8_t dashade, uint8_t dapalnum, int32_t dastat){ + if (videoGetRenderMode() >= REND_POLYMOST && althud_shadows) + rotatesprite_(sbarx(sx+1), sbary(sy+1), z, a, picnum, 127, 4, dastat + POLYMOSTTRANS2, 0, 0, 0, 0, xdim - 1, ydim - 1); + rotatesprite_(sbarx(sx), sbary(sy), z, a, picnum, dashade, dapalnum, dastat, 0, 0, 0, 0, xdim - 1, ydim - 1); +} + +static inline void rotatesprite_althudr(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum, int8_t dashade, uint8_t dapalnum, int32_t dastat) +{ + if (videoGetRenderMode() >= REND_POLYMOST && althud_shadows) + rotatesprite_(sbarxr(sx + 1), sbary(sy + 1), z, a, picnum, 127, 4, dastat + POLYMOSTTRANS2, 0, 0, 0, 0, xdim - 1, ydim - 1); + rotatesprite_(sbarxr(sx), sbary(sy), z, a, picnum, dashade, dapalnum, dastat, 0, 0, 0, 0, xdim - 1, ydim - 1); +} + +void G_DrawStatusBar(int32_t snum) +{ + DukePlayer_t *const p = g_player[snum].ps; + int32_t i, j, o, u; + int32_t permbit = 0; + +#ifdef SPLITSCREEN_MOD_HACKS + const int32_t ss = g_fakeMultiMode ? 4 : ud.screen_size; + const int32_t althud = g_fakeMultiMode ? 0 : ud.althud; +#else + const int32_t ss = ud.screen_size; + const int32_t althud = ud.althud; +#endif + + const int32_t SBY = (200-(tilesiz[BOTTOMSTATUSBAR].y >> (RR ? 1 : 0))); + + const int32_t sb15 = sbarsc(32768), sb15h = sbarsc(49152); + const int32_t sb16 = sbarsc(65536); + + static int32_t item_icons[8]; + + if (ss < 4) + return; + + if (item_icons[0] == 0) + { + int32_t iicons[8] = { -1, FIRSTAID_ICON, STEROIDS_ICON, HOLODUKE_ICON, + JETPACK_ICON, HEAT_ICON, AIRTANK_ICON, BOOT_ICON }; + Bmemcpy(item_icons, iicons, sizeof(item_icons)); + } + + if (videoGetRenderMode() >= REND_POLYMOST) pus = NUMPAGES; // JBF 20040101: always redraw in GL + + if ((g_netServer || ud.multimode > 1) && ((g_gametypeFlags[ud.coop] & GAMETYPE_FRAGBAR))) + { + if (pus) + G_DrawFrags(); + else + { + for (TRAVERSE_CONNECT(i)) + if (g_player[i].ps->frag != sbar.frag[i]) + { + G_DrawFrags(); + break; + } + + } + for (TRAVERSE_CONNECT(i)) + if (i != myconnectindex) + sbar.frag[i] = g_player[i].ps->frag; + } + + if (ss == 4) //DRAW MINI STATUS BAR: + { + if (althud) + { + // ALTERNATIVE STATUS BAR + + if (RR) + { + int32_t hudoffset = hud_position == 1 ? 32 : 200; + static int32_t ammo_sprites[MAX_WEAPONS]; + + if (EDUKE32_PREDICT_FALSE(ammo_sprites[0] == 0)) + { + /* this looks stupid but it lets us initialize static memory to dynamic values + these values can be changed from the CONs with dynamic tile remapping + but we don't want to have to recreate the values in memory every time + the HUD is drawn */ + + int32_t asprites[MAX_WEAPONS] = { -1, AMMO, SHOTGUNAMMO, BATTERYAMMO, + HBOMBAMMO, HBOMBAMMO, RRTILE43, DEVISTATORAMMO, + TRIPBOMBSPRITE, GROWSPRITEICON, HBOMBAMMO, -1, BOWLINGBALLSPRITE, + MOTOAMMO, BOATAMMO, -1, RPG2SPRITE + }; + Bmemcpy(ammo_sprites, asprites, sizeof(ammo_sprites)); + // Hardcoded for now + althud_numbertile = BIGALPHANUM-10; + } + + // rotatesprite_fs(sbarx(5+1),sbary(200-25+1),sb15h,0,SIXPAK,0,4,10+16+1+32); + // rotatesprite_fs(sbarx(5),sbary(200-25),sb15h,0,SIXPAK,0,0,10+16); + rotatesprite_althud(2, hudoffset-26, sbarsc(10000), 0, SPINNINGNUKEICON+1, 0, 0, 10+16+256); + + if (sprite[p->i].pal == 1 && p->last_extra < 2) + G_DrawAltDigiNum(44, -(hudoffset-22), 1, -16, 10+16+256); + else if (!althud_flashing || p->last_extra >(p->max_player_health>>2) || (int32_t) totalclock&32) + { + int32_t s = -8; + if (althud_flashing && p->last_extra > p->max_player_health) + s += (sintable[((int32_t) totalclock<<5)&2047]>>10); + G_DrawAltDigiNum(44, -(hudoffset-22), p->last_extra, s, 10+16+256); + } + + rotatesprite_althud(70, hudoffset-22, sbarsc(10000), 0, COLA, 0, 0, 10+16+256); + G_DrawAltDigiNum(98, -(hudoffset-22), p->drink_amt, -8, 10+16+256); + + rotatesprite_althud(122, hudoffset-22, sbarsc(19000), 0, JETPACK, 0, 0, 10+16+256); + G_DrawAltDigiNum(175, -(hudoffset-22), p->eat_amt, -8, 10+16+256); + + if (ammo_sprites[p->curr_weapon] >= 0) + { + i = (tilesiz[ammo_sprites[p->curr_weapon]].y >= 50) ? 16384 : 32768; + if (p->curr_weapon == TRIPBOMB_WEAPON) + rotatesprite_althudr(57, hudoffset-30, sbarsc(i), 0, ammo_sprites[p->curr_weapon], 0, 0, 10+512); + else + rotatesprite_althudr(57, hudoffset-15, sbarsc(i), 0, ammo_sprites[p->curr_weapon], 0, 0, 10+512); + } + + if (p->curr_weapon== HANDREMOTE_WEAPON) i = HANDBOMB_WEAPON; + else i = p->curr_weapon; + + if (p->curr_weapon != KNEE_WEAPON && p->curr_weapon != SLINGBLADE_WEAPON && + (!althud_flashing || (int32_t) totalclock&32 || p->ammo_amount[i] > (p->max_ammo_amount[i]/10))) + G_DrawAltDigiNum(-20, -(hudoffset-22), p->ammo_amount[i], -16, 10+16+512); + + o = 102; + permbit = 0; + + if (p->inven_icon) + { + const int32_t orient = 10+16+permbit+512; + + i = ((unsigned) p->inven_icon < ICON_MAX) ? item_icons[p->inven_icon] : -1; + + if (i >= 0) + rotatesprite_althudr(320-(231-o+85), hudoffset-21-2, sb15, 0, i, 0, 0, orient); + + if (p->inven_icon == 1 || p->inven_icon == 2) + { + if (videoGetRenderMode() >= REND_POLYMOST && althud_shadows) + minitextshade(320-(292-30-o+1+85), hudoffset-10-3+1, "%", 127, 4, POLYMOSTTRANS+orient+ROTATESPRITE_MAX); + minitext(320-(292-30-o+85), hudoffset-10-3, "%", 0, orient+ROTATESPRITE_MAX); + } + + i = G_GetInvAmount(p); + + G_DrawInvNum(320-(284-30-o+85), 0, hudoffset-6-3, (uint8_t) i, 0, 10+permbit+512); + + if (p->inven_icon >= ICON_SCUBA) + { + if (videoGetRenderMode() >= REND_POLYMOST && althud_shadows) + minitextshade(320-(284-35-o+1+85), hudoffset-20-3+1, "Auto", 127, 4, POLYMOSTTRANS+orient+ROTATESPRITE_MAX); + minitext(320-(284-35-o+85), hudoffset-20-3, "Auto", 2, orient+ROTATESPRITE_MAX); + } + } + + if (hud_position == 1) + hudoffset += 40; + + if (p->keys[1]) rotatesprite_althudr(39, hudoffset-43, sb15, 0, ACCESSCARD, 0, 0, 10+16+512); + if (p->keys[3]) rotatesprite_althudr(34, hudoffset-41, sb15, 0, ACCESSCARD, 0, 23, 10+16+512); + if (p->keys[2]) rotatesprite_althudr(29, hudoffset-39, sb15, 0, ACCESSCARD, 0, 21, 10+16+512); + } + else + { + int32_t hudoffset = hud_position == 1 ? 32 : 200; + static int32_t ammo_sprites[MAX_WEAPONS]; + + if (EDUKE32_PREDICT_FALSE(ammo_sprites[0] == 0)) + { + /* this looks stupid but it lets us initialize static memory to dynamic values + these values can be changed from the CONs with dynamic tile remapping + but we don't want to have to recreate the values in memory every time + the HUD is drawn */ + + int32_t asprites[MAX_WEAPONS] = { -1, AMMO, SHOTGUNAMMO, BATTERYAMMO, + RPGAMMO, HBOMBAMMO, CRYSTALAMMO, DEVISTATORAMMO, + TRIPBOMBSPRITE, FREEZEAMMO+1, HBOMBAMMO, GROWAMMO + }; + Bmemcpy(ammo_sprites, asprites, sizeof(ammo_sprites)); + // Hardcoded for now + althud_numbertile = BIGALPHANUM-10; + } + + // rotatesprite_fs(sbarx(5+1),sbary(200-25+1),sb15h,0,SIXPAK,0,4,10+16+1+32); + // rotatesprite_fs(sbarx(5),sbary(200-25),sb15h,0,SIXPAK,0,0,10+16); + rotatesprite_althud(2, hudoffset-21, sb15h, 0, COLA, 0, 0, 10+16+256); + + if (sprite[p->i].pal == 1 && p->last_extra < 2) + G_DrawAltDigiNum(40, -(hudoffset-22), 1, -16, 10+16+256); + else if (!althud_flashing || p->last_extra >(p->max_player_health>>2) || (int32_t) totalclock&32) + { + int32_t s = -8; + if (althud_flashing && p->last_extra > p->max_player_health) + s += (sintable[((int32_t) totalclock<<5)&2047]>>10); + G_DrawAltDigiNum(40, -(hudoffset-22), p->last_extra, s, 10+16+256); + } + + rotatesprite_althud(62, hudoffset-25, sb15h, 0, SHIELD, 0, 0, 10+16+256); + + { + int32_t lAmount = G_GetMorale(p->i, snum); + if (lAmount == -1) + lAmount = p->inv_amount[GET_SHIELD]; + G_DrawAltDigiNum(105, -(hudoffset-22), lAmount, -16, 10+16+256); + } + + if (ammo_sprites[p->curr_weapon] >= 0) + { + i = (tilesiz[ammo_sprites[p->curr_weapon]].y >= 50) ? 16384 : 32768; + rotatesprite_althudr(57, hudoffset-15, sbarsc(i), 0, ammo_sprites[p->curr_weapon], 0, 0, 10+512); + } + + if (p->curr_weapon== HANDREMOTE_WEAPON) i = HANDBOMB_WEAPON; + else i = p->curr_weapon; + + if (p->curr_weapon != KNEE_WEAPON && + (!althud_flashing || (int32_t) totalclock&32 || p->ammo_amount[i] > (p->max_ammo_amount[i]/10))) + G_DrawAltDigiNum(-20, -(hudoffset-22), p->ammo_amount[i], -16, 10+16+512); + + o = 102; + permbit = 0; + + if (p->inven_icon) + { + const int32_t orient = 10+16+permbit+256; + + i = ((unsigned) p->inven_icon < ICON_MAX) ? item_icons[p->inven_icon] : -1; + + if (i >= 0) + rotatesprite_althud(231-o, hudoffset-21-2, sb16, 0, i, 0, 0, orient); + + if (videoGetRenderMode() >= REND_POLYMOST && althud_shadows) + minitextshade(292-30-o+1, hudoffset-10-3+1, "%", 127, 4, POLYMOSTTRANS+orient+ROTATESPRITE_MAX); + minitext(292-30-o, hudoffset-10-3, "%", 6, orient+ROTATESPRITE_MAX); + + i = G_GetInvAmount(p); + j = G_GetInvOn(p); + + G_DrawInvNum(-(284-30-o), 0, hudoffset-6-3, (uint8_t) i, 0, 10+permbit+256); + + if (!WW2GI) + { + if (j > 0) + { + if (videoGetRenderMode() >= REND_POLYMOST && althud_shadows) + minitextshade(288-30-o+1, hudoffset-20-3+1, "On", 127, 4, POLYMOSTTRANS+orient+ROTATESPRITE_MAX); + minitext(288-30-o, hudoffset-20-3, "On", 0, orient+ROTATESPRITE_MAX); + } + else if ((uint32_t) j != 0x80000000) + { + if (videoGetRenderMode() >= REND_POLYMOST && althud_shadows) + minitextshade(284-30-o+1, hudoffset-20-3+1, "Off", 127, 4, POLYMOSTTRANS+orient+ROTATESPRITE_MAX); + minitext(284-30-o, hudoffset-20-3, "Off", 2, orient+ROTATESPRITE_MAX); + } + } + + if (p->inven_icon >= ICON_SCUBA) + { + if (videoGetRenderMode() >= REND_POLYMOST && althud_shadows) + minitextshade(284-35-o+1, hudoffset-20-3+1, "Auto", 127, 4, POLYMOSTTRANS+orient+ROTATESPRITE_MAX); + minitext(284-35-o, hudoffset-20-3, "Auto", 2, orient+ROTATESPRITE_MAX); + } + } + + if (hud_position == 1) + hudoffset += 40; + + if (p->got_access&1) rotatesprite_althudr(39, hudoffset-43, sb15, 0, ACCESSCARD, 0, 0, 10+16+512); + if (p->got_access&4) rotatesprite_althudr(34, hudoffset-41, sb15, 0, ACCESSCARD, 0, 23, 10+16+512); + if (p->got_access&2) rotatesprite_althudr(29, hudoffset-39, sb15, 0, ACCESSCARD, 0, 21, 10+16+512); + } + } + else + { + // ORIGINAL MINI STATUS BAR + int32_t orient = 2+8+16+256, yofssh=0; + +#ifdef SPLITSCREEN_MOD_HACKS + int32_t yofs=0; + + if (g_fakeMultiMode) + { + const int32_t sidebyside = (ud.screen_size!=0); + + if (sidebyside && snum==1) + { + orient |= RS_CENTERORIGIN; + } + else if (!sidebyside && snum==0) + { + yofs = -100; + yofssh = yofs<<16; + } + } +#endif + + if (RR) + { + rotatesprite_fs(sbarx(2), yofssh+sbary(200-28), sb15, 0, HEALTHBOX, 0, 21, orient); + if (p->inven_icon) + rotatesprite_fs(sbarx(77), yofssh+sbary(200-30), sb15, 0, INVENTORYBOX, 0, 21, orient); + + // health + { + int32_t health = (sprite[p->i].pal == 1 && p->last_extra < 2) ? 1 : p->last_extra; + G_DrawDigiNum_(20, yofssh, 200-17, health, -16, orient); + } + + rotatesprite_fs(sbarx(41), yofssh+sbary(200-28), sb15, 0, AMMOBOX, 0, 21, orient); + + if (p->curr_weapon == HANDREMOTE_WEAPON) + i = HANDBOMB_WEAPON; + else + i = p->curr_weapon; + G_DrawDigiNum_(59, yofssh, 200-17, p->ammo_amount[i], -16, orient); + + o = 158; + permbit = 0; + if (p->inven_icon) + { + // orient |= permbit; + + i = ((unsigned) p->inven_icon < ICON_MAX) ? item_icons[p->inven_icon] : -1; + if (i >= 0) + rotatesprite_fs(sbarx(231-o+10), yofssh+sbary(200-21), sb15, 0, i, 0, 0, orient); + + // scale by status bar size + orient |= ROTATESPRITE_MAX; + + minitext_yofs = yofssh; + if (p->inven_icon == 1 || p->inven_icon == 2) + minitext(292-30-o+10, 190, "%", 0, orient); + i = G_GetInvAmount(p); + + G_DrawInvNum(284-30-o+8, yofssh, 200-6, (uint8_t) i, 0, orient&~16); + + minitext_yofs = 0; + } + } + else + { + rotatesprite_fs(sbarx(5), yofssh+sbary(200-28), sb16, 0, HEALTHBOX, 0, 21, orient); + if (p->inven_icon) + rotatesprite_fs(sbarx(69), yofssh+sbary(200-30), sb16, 0, INVENTORYBOX, 0, 21, orient); + + // health + { + int32_t health = (sprite[p->i].pal == 1 && p->last_extra < 2) ? 1 : p->last_extra; + G_DrawDigiNum_(20, yofssh, 200-17, health, -16, orient); + } + + rotatesprite_fs(sbarx(37), yofssh+sbary(200-28), sb16, 0, AMMOBOX, 0, 21, orient); + + if (p->curr_weapon == HANDREMOTE_WEAPON) + i = HANDBOMB_WEAPON; + else + i = p->curr_weapon; + G_DrawDigiNum_(53, yofssh, 200-17, p->ammo_amount[i], -16, orient); + + o = 158; + permbit = 0; + if (p->inven_icon) + { + // orient |= permbit; + + i = ((unsigned) p->inven_icon < ICON_MAX) ? item_icons[p->inven_icon] : -1; + if (i >= 0) + rotatesprite_fs(sbarx(231-o), yofssh+sbary(200-21), sb16, 0, i, 0, 0, orient); + + // scale by status bar size + orient |= ROTATESPRITE_MAX; + + minitext_yofs = yofssh; + minitext(292-30-o, 190, "%", 6, orient); + + i = G_GetInvAmount(p); + j = G_GetInvOn(p); + + G_DrawInvNum(284-30-o, yofssh, 200-6, (uint8_t) i, 0, orient&~16); + + if (!WW2GI) + { + if (j > 0) + minitext(288-30-o, 180, GStrings("OPTVAL_ON"), 0, orient); + else if ((uint32_t) j != 0x80000000) + minitext(284-30-o, 180, GStrings("OPTVAL_OFF"), 2, orient); + } + + if (p->inven_icon >= ICON_SCUBA) + minitext(284-35-o, 180, GStrings("OPTVAL_AUTO"), 2, orient); + + minitext_yofs = 0; + } + } + } + + return; + } + + //DRAW/UPDATE FULL STATUS BAR: + + if (pus) + { + pus = 0; + u = -1; + } + else u = 0; + + if (sbar.frag[myconnectindex] != p->frag) + { + sbar.frag[myconnectindex] = p->frag; + u |= 32768; + } + if (sbar.got_access != p->got_access) + { + sbar.got_access = p->got_access; + u |= 16384; + } + + if (sbar.last_extra != p->last_extra) + { + sbar.last_extra = p->last_extra; + u |= 1; + } + + { + int32_t lAmount = G_GetMorale(p->i, snum); + if (lAmount == -1) + lAmount = p->inv_amount[GET_SHIELD]; + if (sbar.inv_amount[GET_SHIELD] != lAmount) + { + sbar.inv_amount[GET_SHIELD] = lAmount; + u |= 2; + } + } + + if (sbar.curr_weapon != p->curr_weapon) + { + sbar.curr_weapon = p->curr_weapon; + u |= (4+8+16+32+64+128+256+512+1024+65536L); + } + + for (i=1; iammo_amount[i]) + { + sbar.ammo_amount[i] = p->ammo_amount[i]; + if (i < 9) + u |= ((2<gotweapon & (1<gotweapon & (1<inven_icon) + { + sbar.inven_icon = p->inven_icon; + u |= (2048+4096+8192); + } + if (sbar.holoduke_on != p->holoduke_on) + { + sbar.holoduke_on = p->holoduke_on; + u |= (4096+8192); + } + if (sbar.jetpack_on != p->jetpack_on) + { + sbar.jetpack_on = p->jetpack_on; + u |= (4096+8192); + } + if (sbar.heat_on != p->heat_on) + { + sbar.heat_on = p->heat_on; + u |= (4096+8192); + } + + { + static const int32_t check_items [] = { + GET_FIRSTAID, GET_STEROIDS, GET_HOLODUKE, GET_JETPACK, + GET_HEATS, GET_SCUBA, GET_BOOTS + }; + + for (i=0; i<(int32_t)sizeof(check_items)/(int32_t)sizeof(check_items[0]); i++) + { + int32_t item = check_items[i]; + + if (sbar.inv_amount[item] != p->inv_amount[item]) + { + sbar.inv_amount[item] = p->inv_amount[item]; + u |= 8192; + } + } + } +#if 0 + if (u == 0) + return; +#else + // FIXME: full status bar draws rectangles in the wrong places when it's + // updated partially. + u = -1; +#endif + + //0 - update health + //1 - update armor + //2 - update PISTOL_WEAPON ammo + //3 - update SHOTGUN_WEAPON ammo + //4 - update CHAINGUN_WEAPON ammo + //5 - update RPG_WEAPON ammo + //6 - update HANDBOMB_WEAPON ammo + //7 - update SHRINKER_WEAPON ammo + //8 - update DEVISTATOR_WEAPON ammo + //9 - update TRIPBOMB_WEAPON ammo + //10 - update ammo display + //11 - update inventory icon + //12 - update inventory on/off + //13 - update inventory % + //14 - update keys + //15 - update kills + //16 - update FREEZE_WEAPON ammo + + if (u == -1) + { + G_PatchStatusBar(0, 0, 320, 200, 0); + if ((g_netServer || ud.multimode > 1) && (g_gametypeFlags[ud.coop] & GAMETYPE_FRAGBAR)) + rotatesprite_fs(sbarx(277+1), sbary(SBY+7-1), sb16, 0, KILLSICON, 0, 0, 10+16); + if (ud.screen_size > 8) + G_DrawWeaponBar(p); + } + + if ((g_netServer || ud.multimode > 1) && (g_gametypeFlags[ud.coop] & GAMETYPE_FRAGBAR)) + { + if (u&32768) + { + if (u != -1) G_PatchStatusBar(276, SBY+17, 299, SBY+17+10); + G_DrawDigiNum(287, SBY+17, max(p->frag-p->fraggedself, 0), -16, 10+16); + } + } + else + { + if (u&16384) + { + if (RR) + { + if (u != -1) G_PatchStatusBar(136, SBY+16, 164, SBY+16+12); + if (p->keys[3]) rotatesprite_fs(sbarx(140), sbary(SBY+16), sb15, 0, ACCESS_ICON, 0, 23, 10+16); + if (p->keys[2]) rotatesprite_fs(sbarx(153), sbary(SBY+16), sb15, 0, ACCESS_ICON, 0, 21, 10+16); + if (p->keys[1]) rotatesprite_fs(sbarx(146), sbary(SBY+23), sb15, 0, ACCESS_ICON, 0, 0, 10+16); + } + else + { + if (u != -1) G_PatchStatusBar(275, SBY+18, 299, SBY+18+12); + if (p->got_access&4) rotatesprite_fs(sbarx(275), sbary(SBY+16), sb16, 0, ACCESS_ICON, 0, 23, 10+16); + if (p->got_access&2) rotatesprite_fs(sbarx(288), sbary(SBY+16), sb16, 0, ACCESS_ICON, 0, 21, 10+16); + if (p->got_access&1) rotatesprite_fs(sbarx(281), sbary(SBY+23), sb16, 0, ACCESS_ICON, 0, 0, 10+16); + } + } + } + + if (!RR && (u&(4+8+16+32+64+128+256+512+65536L))) + G_DrawWeapAmounts(p, 96, SBY+16, u); + + if (u&1) + { + if (u != -1) G_PatchStatusBar(RR ? 52 : 20, SBY+17, RR ? 77 : 43, SBY+17+11); + if (sprite[p->i].pal == 1 && p->last_extra < 2) + G_DrawDigiNum(RR ? 64 : 32, SBY+17, 1, -16, 10+16); + else G_DrawDigiNum(RR ? 64 : 32, SBY+17, p->last_extra, -16, 10+16); + } + if (!RR && (u&2)) + { + if (u != -1) + G_PatchStatusBar(52, SBY+17, 75, SBY+17+11); + + G_DrawDigiNum(64, SBY+17, p->inv_amount[GET_SHIELD], -16, 10+16); + } + + if (u&1024) + { + if (u != -1) G_PatchStatusBar(RR ? 95 : 196, SBY+17, RR ? 120 : 219, SBY+17+11); + if (p->curr_weapon != KNEE_WEAPON && (!RRRA || p->curr_weapon != SLINGBLADE_WEAPON)) + { + if (p->curr_weapon == HANDREMOTE_WEAPON) i = HANDBOMB_WEAPON; + else i = p->curr_weapon; + G_DrawDigiNum(RR ? 107 : (230-22), SBY+17, p->ammo_amount[i], -16, 10+16); + if (RR && ud.screen_size > 8) + { + if (p->curr_weapon == RPG_WEAPON || p->curr_weapon == HANDBOMB_WEAPON) + { + G_PatchStatusBar2(126, SBY-8, 142, SBY-8+16); + G_DrawInvNum(134, 0, SBY-4, p->ammo_amount[HANDBOMB_WEAPON], 0, 10); + G_PatchStatusBar2(158, SBY-8, 174, SBY-8+16); + G_DrawInvNum(166, 0, SBY-4, p->ammo_amount[RPG_WEAPON], 0, 10); + } + else if (RRRA && p->curr_weapon == CHICKEN_WEAPON) + { + G_PatchStatusBar2(158, SBY-8, 174, SBY-8+16); + G_DrawInvNum(166, 0, SBY-4, p->ammo_amount[CHICKEN_WEAPON], 0, 10); + } + else if (p->curr_weapon <= DEVISTATOR_WEAPON) + { + G_PatchStatusBar2(p->curr_weapon * 32 - 2, SBY-8, p->curr_weapon * 32 + 14, SBY-8+16); + G_DrawInvNum(p->curr_weapon * 32 + 6, 0, SBY-4, p->ammo_amount[p->curr_weapon], 0, 10); + } + /*for (i = 1; i < 10; i++) + { + if (RRRA && i == 4 && p->curr_weapon == CHICKEN_WEAPON) + { + if (!p->ammo_amount[CHICKEN_WEAPON] && (p->gotweapon&(1<< CHICKEN_WEAPON))) + { + G_PatchStatusBar2(i * 32 - 2, SBY-8, i * 32 + 14, SBY-8+16); + G_DrawInvNum(i * 32 + 6, 0, SBY-4, p->ammo_amount[CHICKEN_WEAPON], 0, 10); + } + } + else if (!p->ammo_amount[i] && (p->gotweapon&(1<ammo_amount[i], 0, 10); + } + }*/ + } + } + } + + if (u&(2048+4096+8192)) + { + if (u != -1) + { + if (RR) + { + if (u&(2048+4096)) + G_PatchStatusBar(177, SBY+10, 222, SBY+10+21); + else + G_PatchStatusBar(201, SBY+24, 216, SBY+24+10); + } + else + { + if (u&(2048+4096)) + G_PatchStatusBar(231, SBY+13, 265, SBY+13+18); + else + G_PatchStatusBar(250, SBY+24, 261, SBY+24+6); + } + } + + if (p->inven_icon) + { + o = 0; + // permbit = 128; + + if (u&(2048+4096)) + { + i = ((unsigned) p->inven_icon < ICON_MAX) ? item_icons[p->inven_icon] : -1; + // XXX: i < 0? + if (RR) + { + if (i == FIRSTAID_ICON || i == STEROIDS_ICON) + minitext(214-o+2, SBY+24, "%", 0, 10+16+permbit + ROTATESPRITE_MAX); + if (i == AIRTANK_ICON) + rotatesprite_fs(sbarx(183-o), sbary(SBY+10), sb15, 0, i, 0, 0, 10+16+permbit); + else if (i == FIRSTAID_ICON || i == BOOT_ICON || i == STEROIDS_ICON) + rotatesprite_fs(sbarx(183-o), sbary(SBY+12), sb15, 0, i, 0, 0, 10+16+permbit); + else + rotatesprite_fs(sbarx(183-o), sbary(SBY+13), sb15, 0, i, 0, 0, 10+16+permbit); + if (p->inven_icon == ICON_SCUBA || p->inven_icon == ICON_BOOTS) + minitext(201-o, SBY+14, "Auto", 2, 10+16+permbit + ROTATESPRITE_MAX); + } + else + { + rotatesprite_fs(sbarx(231-o), sbary(SBY+13), sb16, 0, i, 0, 0, 10+16+permbit); + minitext(292-30-o, SBY+24, "%", 6, 10+16+permbit + ROTATESPRITE_MAX); + if (p->inven_icon >= ICON_SCUBA) minitext(284-35-o, SBY+14, GStrings("OPTVAL_AUTO"), 2, 10+16+permbit + ROTATESPRITE_MAX); + } + } + + if (u&(2048+4096) && !WW2GI) + { + j = G_GetInvOn(p); + + if (!RR) + { + if (j > 0) minitext(288-30-o, SBY+14, GStrings("OPTVAL_ON"), 0, 10+16+permbit + ROTATESPRITE_MAX); + else if ((uint32_t) j != 0x80000000) minitext(284-30-o, SBY+14, GStrings("OPTVAL_OFF"), 2, 10+16+permbit + ROTATESPRITE_MAX); + } + } + + if (u&8192) + { + i = G_GetInvAmount(p); + G_DrawInvNum((RR ? 206 : (284-30))-o, 0, SBY+28, (uint8_t) i, 0, 10+permbit); + } + } + } + + // Gut meter + if (RR) + { + G_PatchStatusBar(240,SBY+2,310,SBY+33); + p->drink_ang = ((p->drink_amt*8)+1647)&2047; + if (p->drink_amt >= 100) + { + p->drink_amt = 100; + p->drink_ang = 400; + } + rotatesprite_fs(sbarx(257),sbary(SBY+15),sb15,p->drink_ang,GUTMETER,0,0,10); + rotatesprite_fs(sbarx(293),sbary(SBY+15),sb15,p->eat_ang,GUTMETER,0,0,10); + o = 9; + if (p->drink_amt >= 0 && p->drink_amt <= 30) + { + rotatesprite_fs(sbarx(239),sbary((SBY+15+o)),sb15,0,GUTMETER_LIGHT1,0,0,10+16); + } + else if (p->drink_amt >= 31 && p->drink_amt <= 65) + { + rotatesprite_fs(sbarx(248),sbary((SBY+15+o)),sb15,0,GUTMETER_LIGHT2,0,0,10+16); + } + else if (p->drink_amt >= 66 && p->drink_amt <= 87) + { + rotatesprite_fs(sbarx(256),sbary((SBY+15+o)),sb15,0,GUTMETER_LIGHT3,0,0,10+16); + } + else + { + rotatesprite_fs(sbarx(265),sbary((SBY+15+o)),sb15,0,GUTMETER_LIGHT4,0,0,10+16); + } + + if (p->eat_amt >= 0 && p->eat_amt <= 30) + { + rotatesprite_fs(sbarx(276),sbary((SBY+15+o)),sb15,0,GUTMETER_LIGHT1,0,0,10+16); + } + else if (p->eat_amt >= 31 && p->eat_amt <= 65) + { + rotatesprite_fs(sbarx(285),sbary((SBY+15+o)),sb15,0,GUTMETER_LIGHT2,0,0,10+16); + } + else if (p->eat_amt >= 66 && p->eat_amt <= 87) + { + rotatesprite_fs(sbarx(294),sbary((SBY+15+o)),sb15,0,GUTMETER_LIGHT3,0,0,10+16); + } + else + { + rotatesprite_fs(sbarx(302),sbary((SBY+15+o)),sb15,0,GUTMETER_LIGHT4,0,0,10+16); + } + } +} + +void G_DrawBackground(void) +{ + int32_t x, y, x1, x2; + + renderFlushPerms(); + + int32_t y1=0, y2=ydim; + + if ((g_player[myconnectindex].ps->gm&MODE_GAME) == 0 && ud.recstat != 2) + { + const int32_t MENUTILE = DEER ? 7040 : MENUSCREEN; + const int32_t fstilep = tilesiz[MENUTILE].x>=320 && tilesiz[MENUTILE].y==200; + int32_t bgtile = (fstilep ? MENUTILE : (RRRA ? RRTILE7629 : BIGHOLE)); + + videoClearScreen(0); + + // when not rendering a game, fullscreen wipe + // Gv_SetVar(g_iReturnVarID,tilesizx[MENUTILE]==320&&tilesizy[MENUTILE]==200?MENUTILE:BIGHOLE, -1, -1); + // MENU_TILE: is the menu tile tileable? + if (!fstilep) + { + const int32_t tileScale = RR ? 32768L : 65536L; + const int32_t tileShade = RR ? 18 : 8; + if ((unsigned) bgtile < MAXTILES) + for (y=y1; y= 0 && tilesiz[dapicnum].x == 0) || (dapicnum >= 0 && tilesiz[dapicnum].y == 0) || + (windowxy1.x-1 <= 0 && windowxy2.x >= xdim-1 && windowxy1.y-1 <= 0 && windowxy2.y >= ydim-1) || + dapicnum < 0) + { + pus = pub = NUMPAGES; + return; + } + + y1 = fragbarheight(); + if (y1 != 0) + { + y1 = scale(ydim, y1, 200); + y1 -= ((tilesiz[dapicnum].y / y1) +1) * tilesiz[dapicnum].y; + } + + if (windowxy1.y > 0) + { + for (y=y1; y 0 || windowxy2.x < xdim) + { + const int32_t rx = windowxy2.x-windowxy2.x%tilesiz[dapicnum].x; + for (y=y1+windowxy1.y-windowxy1.y%tilesiz[dapicnum].y; y 0) + rotatesprite(x<<16, y<<16, 65536L, 0, dapicnum, 8, 0, 8+16+64, 0, windowxy1.y-1, windowxy1.x-2, windowxy2.y); // left + if (windowxy2.x < xdim) + rotatesprite((x+rx)<<16, y<<16, 65536L, 0, dapicnum, 8, 0, 8+16+64, windowxy2.x+1, windowxy1.y-1, xdim-1, windowxy2.y); // right + } + } + + if (windowxy2.y < ydim) + { + for (y=y1+windowxy2.y-(windowxy2.y%tilesiz[dapicnum].y); y 0 || windowxy2.x < xdim) + for (y=y1+4; y 0) + rotatesprite(x1<<16, y<<16, 65536L, 0, VIEWBORDER, 0, 0, 8+16+64, x1, y1, x2, y2); // left + if (windowxy2.x < xdim) + rotatesprite((x2+1)<<16, (y+64)<<16, 65536L, 1024, VIEWBORDER, 0, 0, 8+16+64, x1, y1, x2, y2); // right + } + + if (windowxy1.y > 0 || windowxy2.y < ydim) + for (x=x1+4; x 0) + rotatesprite((x+64)<<16, y1<<16, 65536L, 512, VIEWBORDER, 0, 0, 8+16+64, x1, y1, x2, y2); // top + if (windowxy2.y < ydim) + rotatesprite(x<<16, (y2+1)<<16, 65536L, 1536, VIEWBORDER, 0, 0, 8+16+64, x1, y1, x2, y2); // bottom + } + + if (windowxy1.x > 0 && windowxy1.y > 0) + rotatesprite(x1<<16, y1<<16, 65536L, 0, VIEWBORDER+1, 0, 0, 8+16+64, x1, y1, x2, y2); // top left + if (windowxy2.x < xdim && windowxy1.y > 0) + rotatesprite((x2+1)<<16, y1<<16, 65536L, 512, VIEWBORDER+1, 0, 0, 8+16+64, x1, y1, x2, y2); // top right + if (windowxy2.x < xdim && windowxy2.y < ydim) + rotatesprite((x2+1)<<16, (y2+1)<<16, 65536L, 1024, VIEWBORDER+1, 0, 0, 8+16+64, x1, y1, x2, y2); // bottom right + if (windowxy1.x > 0 && windowxy2.y < ydim) + rotatesprite(x1<<16, (y2+1)<<16, 65536L, 1536, VIEWBORDER+1, 0, 0, 8+16+64, x1, y1, x2, y2); // bottom left + + pus = pub = NUMPAGES; +} + +END_DUKE_NS diff --git a/source/duke/src/sbar.h b/source/duke/src/sbar.h new file mode 100644 index 000000000..cd6034deb --- /dev/null +++ b/source/duke/src/sbar.h @@ -0,0 +1,39 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#pragma once + +BEGIN_DUKE_NS + + +static FORCE_INLINE int32_t sbarsc(int32_t sc) +{ + return scale(sc, ud.statusbarscale, 100); +} + +int32_t sbarx16(int32_t x); +int32_t sbarxr16(int32_t x); +int32_t sbary16(int32_t y); +void G_DrawInventory(const DukePlayer_t *p); +void G_DrawStatusBar(int32_t snum); + +END_DUKE_NS diff --git a/source/duke/src/screens.cpp b/source/duke/src/screens.cpp new file mode 100644 index 000000000..f27e2b3f6 --- /dev/null +++ b/source/duke/src/screens.cpp @@ -0,0 +1,2851 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- +#include "ns.h" // Must come before everything else! + +#include "duke3d.h" +#include "compat.h" +#include "screens.h" + +#include "anim.h" +#include "sbar.h" +#include "menus.h" +#include "demo.h" +#include "mdsprite.h" +#include "gamecvars.h" +#include "menu/menu.h" +#include "mapinfo.h" +#include "v_2ddrawer.h" + +BEGIN_DUKE_NS + +#define quotepulseshade (sintable[((uint32_t)totalclock<<5)&2047]>>11) + +int32_t g_crosshairSum = -1; +// yxaspect and viewingrange just before the 'main' drawrooms call +int32_t dr_yxaspect, dr_viewingrange; +double g_moveActorsTime, g_moveWorldTime; // in ms, smoothed +int32_t g_noLogoAnim = 0; +int32_t g_noLogo = 0; + +void PlayBonusMusic() +{ + if (MusicEnabled() && mus_enabled) + S_PlaySound(BONUSMUSIC, CHAN_AUTO, CHANF_UI); + +} + +////////// OFTEN-USED FEW-LINERS ////////// +static void G_HandleEventsWhileNoInput(void) +{ + inputState.ClearAllInput(); + + while (!inputState.CheckAllInput()) + G_HandleAsync(); + +} + +static int32_t G_PlaySoundWhileNoInput(int32_t soundnum) +{ + S_PlaySound(soundnum, CHAN_AUTO, CHANF_UI); + inputState.ClearAllInput(); + while (S_CheckSoundPlaying(-1, soundnum)) + { + G_HandleAsync(); + if (inputState.CheckAllInput()) + { + return 1; + } + } + + return 0; +} +////////// + +void P_SetGamePalette(DukePlayer_t *player, uint32_t palid, ESetPalFlags set) +{ + if (palid >= MAXBASEPALS) + palid = 0; + + player->palette = palid; + + if (player != g_player[screenpeek].ps) + return; + + videoSetPalette(0, palid, set); +} + + +#define SCORESHEETOFFSET -20 +static void G_ShowScores(void) +{ + int32_t t, i; + + if (g_mostConcurrentPlayers > 1 && (g_gametypeFlags[ud.coop]&GAMETYPE_SCORESHEET)) + { + gametext_center(SCORESHEETOFFSET+58+2, GStrings("Multiplayer Totals")); + gametext_center(SCORESHEETOFFSET+58+10, currentLevel->DisplayName()); + + t = 0; + minitext(70, SCORESHEETOFFSET+80, GStrings("Name"), 8, 2+8+16+ROTATESPRITE_MAX); + minitext(170, SCORESHEETOFFSET+80, GStrings("Frags"), 8, 2+8+16+ROTATESPRITE_MAX); + minitext(200, SCORESHEETOFFSET+80, GStrings("Deaths"), 8, 2+8+16+ROTATESPRITE_MAX); + minitext(235, SCORESHEETOFFSET+80, GStrings("Ping"), 8, 2+8+16+ROTATESPRITE_MAX); + + for (i=g_mostConcurrentPlayers-1; i>=0; i--) + { + if (!g_player[i].playerquitflag) + continue; + + minitext(70, SCORESHEETOFFSET+90+t, g_player[i].user_name, g_player[i].ps->palookup, 2+8+16+ROTATESPRITE_MAX); + + Bsprintf(tempbuf, "%-4d", g_player[i].ps->frag); + minitext(170, SCORESHEETOFFSET+90+t, tempbuf, 2, 2+8+16+ROTATESPRITE_MAX); + + Bsprintf(tempbuf, "%-4d", g_player[i].frags[i] + g_player[i].ps->fraggedself); + minitext(200, SCORESHEETOFFSET+90+t, tempbuf, 2, 2+8+16+ROTATESPRITE_MAX); + + //Bsprintf(tempbuf, "%-4d", g_player[i].ping); + //minitext(235, SCORESHEETOFFSET+90+t, tempbuf, 2, 2+8+16+ROTATESPRITE_MAX); + + t += 7; + } + } +} +#undef SCORESHEETOFFSET + +////////// TINT ACCUMULATOR ////////// + +typedef struct { + int32_t r, g, b; + // f: 0-63 scale + int32_t maxf, sumf; +} palaccum_t; + +#define PALACCUM_INITIALIZER { 0, 0, 0, 0, 0 } + +/* For a picture frame F and n tints C_1, C_2, ... C_n weighted a_1, a_2, +* ... a_n (on a 0-1 scale), the faded frame is calculated as +* +* F_new := (1-max_i(a_i))*F + d*sum_i(a_i), where +* +* d := max_i(a_i)/sum_i(a_i). +* +* This means that +* 1) tint application is independent of their order. +* 2) going from n+1 to n tints is continuous when the leaving one has faded. +* +* But note that for more than one tint, the composite tint will in general +* change its hue as the ratio of the weights of the individual ones changes. +*/ +static void palaccum_add(palaccum_t *pa, const palette_t *pal, int32_t f) +{ + f = clamp(f, 0, 63); + if (f == 0) + return; + + pa->maxf = max(pa->maxf, f); + pa->sumf += f; + + pa->r += f*clamp(pal->r, 0, 63); + pa->g += f*clamp(pal->g, 0, 63); + pa->b += f*clamp(pal->b, 0, 63); +} + +static void G_FadePalaccum(const palaccum_t *pa) +{ + videoFadePalette(tabledivide32_noinline(pa->r, pa->sumf)<<2, + tabledivide32_noinline(pa->g, pa->sumf)<<2, + tabledivide32_noinline(pa->b, pa->sumf)<<2, pa->maxf<<2); +} + + +static int32_t gtextsc(int32_t sc) +{ + return scale(sc, hud_textscale, 400); +} + +////////// DISPLAYREST ////////// + +static void G_DrawCameraText(int16_t i) +{ + //if (VM_OnEvent(EVENT_DISPLAYCAMERAOSD, i, screenpeek) != 0) + // return; + + if (!T1(i)) + { + rotatesprite_win(24<<16, 33<<16, 65536L, 0, CAMCORNER, 0, 0, 2); + rotatesprite_win((320-26)<<16, 34<<16, 65536L, 0, CAMCORNER+1, 0, 0, 2); + rotatesprite_win(22<<16, 163<<16, 65536L, 512, CAMCORNER+1, 0, 0, 2+4); + rotatesprite_win((310-10)<<16, 163<<16, 65536L, 512, CAMCORNER+1, 0, 0, 2); + + if ((int32_t) totalclock&16) + rotatesprite_win(46<<16, 32<<16, 65536L, 0, CAMLIGHT, 0, 0, 2); + } + else + { + int32_t flipbits = ((int32_t) totalclock<<1)&48; + + for (bssize_t x=-64; x<394; x+=64) + for (bssize_t y=0; y<200; y+=64) + rotatesprite_win(x<<16, y<<16, 65536L, 0, STATIC, 0, 0, 2+flipbits); + } +} + +static inline void G_MoveClouds(void) +{ + int32_t i; + + if (totalclock <= g_cloudClock && totalclock >= (g_cloudClock-7)) + return; + + g_cloudClock = totalclock+6; + + g_cloudX += sintable[(fix16_to_int(g_player[screenpeek].ps->q16ang)+512)&2047]>>9; + g_cloudY += sintable[fix16_to_int(g_player[screenpeek].ps->q16ang)&2047]>>9; + + for (i=g_cloudCnt-1; i>=0; i--) + { + sector[g_cloudSect[i]].ceilingxpanning = g_cloudX>>6; + sector[g_cloudSect[i]].ceilingypanning = g_cloudY>>6; + } +} + +static void G_DrawOverheadMap(int32_t cposx, int32_t cposy, int32_t czoom, int16_t cang) +{ + int32_t i, j, k, l, x1, y1, x2=0, y2=0, x3, y3, x4, y4, ox, oy, xoff, yoff; + int32_t dax, day, cosang, sinang, xspan, yspan, sprx, spry; + int32_t xrepeat, yrepeat, z1, z2, startwall, endwall, tilenum, daang; + int32_t xvect, yvect, xvect2, yvect2; + int16_t p; + PalEntry col; + uwalltype *wal, *wal2; + spritetype *spr; + + int32_t tmpydim = (xdim*5)/8; + + renderSetAspect(65536, divscale16(tmpydim*320, xdim*200)); + + xvect = sintable[(-cang)&2047] * czoom; + yvect = sintable[(1536-cang)&2047] * czoom; + xvect2 = mulscale16(xvect, yxaspect); + yvect2 = mulscale16(yvect, yxaspect); + + //Draw red lines + for (i=numsectors-1; i>=0; i--) + { + if (!gFullMap && !show2dsector[i]) continue; + + startwall = sector[i].wallptr; + endwall = sector[i].wallptr + sector[i].wallnum; + + z1 = sector[i].ceilingz; + z2 = sector[i].floorz; + + for (j=startwall, wal=(uwalltype *)&wall[startwall]; jnextwall; + if (k < 0) continue; + + if (sector[wal->nextsector].ceilingz == z1 && sector[wal->nextsector].floorz == z2) + if (((wal->cstat|wall[wal->nextwall].cstat)&(16+32)) == 0) continue; + + if (!gFullMap && !show2dsector[wal->nextsector]) + { + + col = PalEntry(170, 170, 170); + ox = wal->x-cposx; + oy = wal->y-cposy; + x1 = dmulscale16(ox, xvect, -oy, yvect)+(xdim<<11); + y1 = dmulscale16(oy, xvect2, ox, yvect2)+(ydim<<11); + + wal2 = (uwalltype *)&wall[wal->point2]; + ox = wal2->x-cposx; + oy = wal2->y-cposy; + x2 = dmulscale16(ox, xvect, -oy, yvect)+(xdim<<11); + y2 = dmulscale16(oy, xvect2, ox, yvect2)+(ydim<<11); + + drawlinergb(x1, y1, x2, y2, col); + } + } + } + + //Draw sprites + k = g_player[screenpeek].ps->i; + /*if (!FURY)*/ for (i=numsectors-1; i>=0; i--) // todo - make a switchable flag. + { + if (!gFullMap || !show2dsector[i]) continue; + for (j=headspritesect[i]; j>=0; j=nextspritesect[j]) + { + spr = &sprite[j]; + + if (j == k || (spr->cstat&0x8000) || spr->cstat == 257 || spr->xrepeat == 0) continue; + + col = PalEntry(0, 170, 170); + if (spr->cstat & 1) col = PalEntry(170, 0, 170); + + sprx = spr->x; + spry = spr->y; + + if ((spr->cstat&257) != 0) switch (spr->cstat&48) + { + case 0: + // break; + + ox = sprx-cposx; + oy = spry-cposy; + x1 = dmulscale16(ox, xvect, -oy, yvect); + y1 = dmulscale16(oy, xvect2, ox, yvect2); + + ox = (sintable[(spr->ang+512)&2047]>>7); + oy = (sintable[(spr->ang)&2047]>>7); + x2 = dmulscale16(ox, xvect, -oy, yvect); + y2 = dmulscale16(oy, xvect, ox, yvect); + + x3 = mulscale16(x2, yxaspect); + y3 = mulscale16(y2, yxaspect); + + drawlinergb(x1-x2+(xdim<<11), y1-y3+(ydim<<11), + x1+x2+(xdim<<11), y1+y3+(ydim<<11), col); + drawlinergb(x1-y2+(xdim<<11), y1+x3+(ydim<<11), + x1+x2+(xdim<<11), y1+y3+(ydim<<11), col); + drawlinergb(x1+y2+(xdim<<11), y1-x3+(ydim<<11), + x1+x2+(xdim<<11), y1+y3+(ydim<<11), col); + break; + + case 16: + if (spr->picnum == LASERLINE) + { + x1 = sprx; + y1 = spry; + tilenum = spr->picnum; + xoff = tileLeftOffset(tilenum) + spr->xoffset; + if ((spr->cstat&4) > 0) xoff = -xoff; + k = spr->ang; + l = spr->xrepeat; + dax = sintable[k&2047]*l; + day = sintable[(k+1536)&2047]*l; + l = tilesiz[tilenum].x; + k = (l>>1)+xoff; + x1 -= mulscale16(dax, k); + x2 = x1+mulscale16(dax, l); + y1 -= mulscale16(day, k); + y2 = y1+mulscale16(day, l); + + ox = x1-cposx; + oy = y1-cposy; + x1 = dmulscale16(ox, xvect, -oy, yvect); + y1 = dmulscale16(oy, xvect2, ox, yvect2); + + ox = x2-cposx; + oy = y2-cposy; + x2 = dmulscale16(ox, xvect, -oy, yvect); + y2 = dmulscale16(oy, xvect2, ox, yvect2); + + drawlinergb(x1+(xdim<<11), y1+(ydim<<11), + x2+(xdim<<11), y2+(ydim<<11), col); + } + + break; + + case 32: + tilenum = spr->picnum; + xoff = tileLeftOffset(tilenum) + spr->xoffset; + yoff = tileTopOffset(tilenum) + spr->yoffset; + if ((spr->cstat&4) > 0) xoff = -xoff; + if ((spr->cstat&8) > 0) yoff = -yoff; + + k = spr->ang; + cosang = sintable[(k+512)&2047]; + sinang = sintable[k&2047]; + xspan = tilesiz[tilenum].x; + xrepeat = spr->xrepeat; + yspan = tilesiz[tilenum].y; + yrepeat = spr->yrepeat; + + dax = ((xspan>>1)+xoff)*xrepeat; + day = ((yspan>>1)+yoff)*yrepeat; + x1 = sprx + dmulscale16(sinang, dax, cosang, day); + y1 = spry + dmulscale16(sinang, day, -cosang, dax); + l = xspan*xrepeat; + x2 = x1 - mulscale16(sinang, l); + y2 = y1 + mulscale16(cosang, l); + l = yspan*yrepeat; + k = -mulscale16(cosang, l); + x3 = x2+k; + x4 = x1+k; + k = -mulscale16(sinang, l); + y3 = y2+k; + y4 = y1+k; + + ox = x1-cposx; + oy = y1-cposy; + x1 = dmulscale16(ox, xvect, -oy, yvect); + y1 = dmulscale16(oy, xvect2, ox, yvect2); + + ox = x2-cposx; + oy = y2-cposy; + x2 = dmulscale16(ox, xvect, -oy, yvect); + y2 = dmulscale16(oy, xvect2, ox, yvect2); + + ox = x3-cposx; + oy = y3-cposy; + x3 = dmulscale16(ox, xvect, -oy, yvect); + y3 = dmulscale16(oy, xvect2, ox, yvect2); + + ox = x4-cposx; + oy = y4-cposy; + x4 = dmulscale16(ox, xvect, -oy, yvect); + y4 = dmulscale16(oy, xvect2, ox, yvect2); + + drawlinergb(x1+(xdim<<11), y1+(ydim<<11), + x2+(xdim<<11), y2+(ydim<<11), col); + + drawlinergb(x2+(xdim<<11), y2+(ydim<<11), + x3+(xdim<<11), y3+(ydim<<11), col); + + drawlinergb(x3+(xdim<<11), y3+(ydim<<11), + x4+(xdim<<11), y4+(ydim<<11), col); + + drawlinergb(x4+(xdim<<11), y4+(ydim<<11), + x1+(xdim<<11), y1+(ydim<<11), col); + + break; + } + } + } + + //Draw white lines + for (i=numsectors-1; i>=0; i--) + { + if (!gFullMap && !show2dsector[i]) continue; + + startwall = sector[i].wallptr; + endwall = sector[i].wallptr + sector[i].wallnum; + + k = -1; + for (j=startwall, wal=(uwalltype *)&wall[startwall]; jnextwall >= 0) continue; + + if (tilesiz[wal->picnum].x == 0) continue; + if (tilesiz[wal->picnum].y == 0) continue; + + if (j == k) + { + x1 = x2; + y1 = y2; + } + else + { + ox = wal->x-cposx; + oy = wal->y-cposy; + x1 = dmulscale16(ox, xvect, -oy, yvect)+(xdim<<11); + y1 = dmulscale16(oy, xvect2, ox, yvect2)+(ydim<<11); + } + + k = wal->point2; + wal2 = (uwalltype *)&wall[k]; + ox = wal2->x-cposx; + oy = wal2->y-cposy; + x2 = dmulscale16(ox, xvect, -oy, yvect)+(xdim<<11); + y2 = dmulscale16(oy, xvect2, ox, yvect2)+(ydim<<11); + + drawlinergb(x1, y1, x2, y2, PalEntry(170, 170, 170)); + } + } + + videoSetCorrectedAspect(); + + for (TRAVERSE_CONNECT(p)) + { + if (ud.scrollmode && p == screenpeek) continue; + + DukePlayer_t const * const pPlayer = g_player[p].ps; + uspritetype const * const pSprite = (uspritetype const *)&sprite[pPlayer->i]; + + ox = pSprite->x - cposx; + oy = pSprite->y - cposy; + daang = (pSprite->ang - cang) & 2047; + if (p == screenpeek) + { + ox = 0; + oy = 0; + daang = 0; + } + x1 = mulscale16(ox, xvect) - mulscale16(oy, yvect); + y1 = mulscale16(oy, xvect2) + mulscale16(ox, yvect2); + + if (p == screenpeek || GTFLAGS(GAMETYPE_OTHERPLAYERSINMAP)) + { + if (pSprite->xvel > 16 && pPlayer->on_ground) + i = APLAYERTOP+(((int32_t) totalclock>>4)&3); + else + i = APLAYERTOP; + + //i = VM_OnEventWithReturn(EVENT_DISPLAYOVERHEADMAPPLAYER, pPlayer->i, p, i); + + if (i < 0) + continue; + + j = klabs(pPlayer->truefz - pPlayer->pos.z) >> 8; + j = mulscale16(czoom * (pSprite->yrepeat + j), yxaspect); + + if (j < 22000) j = 22000; + else if (j > (65536<<1)) j = (65536<<1); + + rotatesprite_win((x1<<4)+(xdim<<15), (y1<<4)+(ydim<<15), j, daang, i, pSprite->shade, + P_GetOverheadPal(pPlayer), 0); + } + } +} + +#ifdef DEBUGGINGAIDS +sprstat_t g_spriteStat; +#endif + +FString G_PrintCoords(int32_t snum) +{ + const int32_t x = g_Debug ? 288 : 0; + int32_t y = 0; + + auto const ps = g_player[snum].ps; + const int32_t sectnum = ps->cursectnum; + + if ((g_gametypeFlags[ud.coop] & GAMETYPE_FRAGBAR)) + { + if (ud.multimode > 4) + y = 32; + else if (g_netServer || ud.multimode > 1) + y = 24; + } + FString out; + + out.AppendFormat("XYZ= (%d, %d, %d)\n", ps->pos.x, ps->pos.y, ps->pos.z); + char ang[16], horiz[16], horizoff[16]; + fix16_to_str(ps->q16ang, ang, 2); + fix16_to_str(ps->q16horiz, horiz, 2); + fix16_to_str(ps->q16horizoff, horizoff, 2); + out.AppendFormat("A/H/HO= %s, %s, %s\n", ang, horiz, horizoff); + out.AppendFormat("VEL= (%d, %d, %d) + (%d, %d, 0)\n", ps->vel.x >> 14, ps->vel.y >> 14, ps->vel.z, ps->fric.x >> 5, ps->fric.y >> 5); + out.AppendFormat("OG= %d SBRIDGE=%d SBS=%d\n", ps->on_ground, ps->spritebridge, ps->sbs); + if (sectnum >= 0) + out.AppendFormat("SECT= %d (LO=%d EX=%d)\n", sectnum, TrackerCast(sector[sectnum].lotag), TrackerCast(sector[sectnum].extra)); + else + out.AppendFormat("SECT= %d\n", sectnum); + + out.AppendFormat("\nTHOLD= %d ", ps->transporter_hold); + out.AppendFormat("GAMETIC= %u, TOTALCLOCK=%d\n", g_moveThingsCount, (int32_t)totalclock); +#ifdef DEBUGGINGAIDS + out.AppendFormat("NUMSPRITES= %d\n", Numsprites); + if (g_moveThingsCount > g_spriteStat.lastgtic + REALGAMETICSPERSEC) + { + g_spriteStat.lastgtic = g_moveThingsCount; + g_spriteStat.lastnumins = g_spriteStat.numins; + g_spriteStat.numins = 0; + } + out.AppendFormat("INSERTIONS/s= %u\n", g_spriteStat.lastnumins); + out.AppendFormat("ONSCREEN= %d\n", g_spriteStat.numonscreen); +#endif + out.AppendFormat("\nVR=%.03f YX=%.03f", (double)dr_viewingrange / 65536.0, (double)dr_yxaspect / 65536.0); + return out; +} + +FString GameInterface::GetCoordString() +{ + return G_PrintCoords(screenpeek); +} + + +FString GameInterface::statFPS() +{ + FString output; + static int32_t frameCount; + static double cumulativeFrameDelay; + static double lastFrameTime; + static float lastFPS, minFPS = FLT_MAX, maxFPS; + static double minGameUpdate = DBL_MAX, maxGameUpdate; + + double frameTime = timerGetHiTicks(); + double frameDelay = frameTime - lastFrameTime; + cumulativeFrameDelay += frameDelay; + + if (frameDelay >= 0) + { + int32_t x = (xdim <= 640); + + //if (r_showfps) + { + output.AppendFormat("%.1f ms, %5.1f fps\n", frameDelay, lastFPS); + + if (r_showfps > 1) + { + output.AppendFormat("max: %5.1f fps\n", maxFPS); + output.AppendFormat("min: %5.1f fps\n", minFPS); + } + if (r_showfps > 2) + { + if (g_gameUpdateTime > maxGameUpdate) maxGameUpdate = g_gameUpdateTime; + if (g_gameUpdateTime < minGameUpdate) minGameUpdate = g_gameUpdateTime; + + output.AppendFormat("Game Update: %2.2f ms + draw: %2.2f ms\n", g_gameUpdateTime, g_gameUpdateAndDrawTime - g_gameUpdateTime); + output.AppendFormat("GU min/max/avg: %5.2f/%5.2f/%5.2f ms\n", minGameUpdate, maxGameUpdate, g_gameUpdateAvgTime); + output.AppendFormat("G_MoveActors(): %.3f ms\n", g_moveActorsTime); + output.AppendFormat("G_MoveWorld(): %.3f ms\n", g_moveWorldTime); + } + + // lag meter +#ifndef NETCODE_DISABLE + Net_PrintLag(output); +#endif + } + + if (cumulativeFrameDelay >= 1000.0) + { + lastFPS = 1000.f * frameCount / cumulativeFrameDelay; + g_frameRate = Blrintf(lastFPS); + frameCount = 0; + cumulativeFrameDelay = 0.0; + + if (r_showfps > 1) + { + if (lastFPS > maxFPS) maxFPS = lastFPS; + if (lastFPS < minFPS) minFPS = lastFPS; + + static int secondCounter; + + if (++secondCounter >= r_showfpsperiod) + { + maxFPS = (lastFPS + maxFPS) * .5f; + minFPS = (lastFPS + minFPS) * .5f; + maxGameUpdate = (g_gameUpdateTime + maxGameUpdate) * 0.5; + minGameUpdate = (g_gameUpdateTime + minGameUpdate) * 0.5; + secondCounter = 0; + } + } + } + frameCount++; + } + lastFrameTime = frameTime; + return output; +} + +GameStats GameInterface::getStats() +{ + DukePlayer_t* p = g_player[myconnectindex].ps; + return { p->actors_killed, p->max_actors_killed, p->secret_rooms, p->max_secret_rooms, p->player_par / REALGAMETICSPERSEC, p->frag }; +} + + +void G_DisplayRest(int32_t smoothratio) +{ + int32_t i, j; + palaccum_t tint = PALACCUM_INITIALIZER; + + DukePlayer_t *const pp = g_player[screenpeek].ps; + int32_t cposx, cposy, cang; + + // this takes care of fullscreen tint for OpenGL + if (videoGetRenderMode() >= REND_POLYMOST) + { + auto & fstint = lookups.tables[MAXPALOOKUPS-1]; + + if (pp->palette == WATERPAL) + { + fstint.tintColor.r = 224; + fstint.tintColor.g = 192; + fstint.tintColor.b = 255; + fstint.tintFlags = 0; + } + else if (pp->palette == SLIMEPAL) + { + fstint.tintColor.r = 208; + fstint.tintColor.g = 255; + fstint.tintColor.b = 192; + fstint.tintFlags = 0; + } + else + { + fstint.tintColor.r = 255; + fstint.tintColor.g = 255; + fstint.tintColor.b = 255; + fstint.tintFlags = 0; + } + } + palaccum_add(&tint, &pp->pals, pp->pals.f); + if (!RR) + { + static const palette_t loogiepal = { 0, 63, 0, 0 }; + + palaccum_add(&tint, &loogiepal, pp->loogcnt>>1); + } + + if (g_restorePalette) + { + // reset a normal palette + static uint32_t omovethingscnt; + + if (g_restorePalette < 2 || omovethingscnt+1 == g_moveThingsCount) + { + int32_t pal = pp->palette; + + // g_restorePalette < 0: reset tinting, too (e.g. when loading new game) + P_SetGamePalette(pp, pal, (g_restorePalette > 0) ? Pal_DontResetFade : ESetPalFlags::FromInt(0)); + g_restorePalette = 0; + } + else + { + // delay setting the palette by one game tic + omovethingscnt = g_moveThingsCount; + } + } + + i = pp->cursectnum; + if (i > -1) + { + const walltype *wal = &wall[sector[i].wallptr]; + + show2dsector.Set(i); + for (j=sector[i].wallnum; j>0; j--, wal++) + { + i = wal->nextsector; + if (i < 0) continue; + if (wal->cstat&0x0071) continue; + if (wall[wal->nextwall].cstat&0x0071) continue; + if (sector[i].lotag == 32767) continue; + if (sector[i].ceilingz >= sector[i].floorz) continue; + show2dsector.Set(i); + } + } + + if (ud.camerasprite == -1) + { + if (ud.overhead_on != 2) + { + if (!RR && pp->newowner >= 0) + G_DrawCameraText(pp->newowner); + else + { + PspTwoDSetter set; + P_DisplayWeapon(); + + if (pp->over_shoulder_on == 0) + P_DisplayScuba(); + } + if (!RR) + G_MoveClouds(); + } + + if (DEER) + sub_57B38(pp->opos.x, pp->opos.y, 20, 1536); + + if (ud.overhead_on > 0) + { + // smoothratio = min(max(smoothratio,0),65536); + smoothratio = calc_smoothratio(totalclock, ototalclock); + G_DoInterpolations(smoothratio); + + if (ud.scrollmode == 0) + { + if (pp->newowner == -1 && !paused) + { + if (screenpeek == myconnectindex && numplayers > 1) + { + cposx = omypos.x + mulscale16(mypos.x-omypos.x, smoothratio); + cposy = omypos.y + mulscale16(mypos.y-omypos.y, smoothratio); + cang = fix16_to_int(omyang) + mulscale16((fix16_to_int(myang+F16(1024)-omyang)&2047)-1024, smoothratio); + } + else + { + cposx = pp->opos.x + mulscale16(pp->pos.x-pp->opos.x, smoothratio); + cposy = pp->opos.y + mulscale16(pp->pos.y-pp->opos.y, smoothratio); + cang = fix16_to_int(pp->oq16ang) + mulscale16((fix16_to_int(pp->q16ang+F16(1024)-pp->oq16ang)&2047)-1024, smoothratio); + } + } + else + { + cposx = pp->opos.x; + cposy = pp->opos.y; + cang = fix16_to_int(pp->oq16ang); + } + } + else + { + if (!paused) + { + ud.fola += ud.folavel>>3; + ud.folx += (ud.folfvel*sintable[(512+2048-ud.fola)&2047])>>14; + ud.foly += (ud.folfvel*sintable[(512+1024-512-ud.fola)&2047])>>14; + } + cposx = ud.folx; + cposy = ud.foly; + cang = ud.fola; + } + + if (ud.overhead_on == 2) + { + twod->ClearScreen(); + G_DrawBackground(); + renderDrawMapView(cposx, cposy, pp->zoom, cang); + } + G_DrawOverheadMap(cposx, cposy, pp->zoom, cang); + + G_RestoreInterpolations(); + + //int32_t const textret = VM_OnEvent(EVENT_DISPLAYOVERHEADMAPTEXT, g_player[screenpeek].ps->i, screenpeek); + if (/*textret == 0 &&*/ ud.overhead_on == 2) + { + const int32_t a = RR ? 0 : ((ud.screen_size > 0) ? 147 : 179); + + if (!G_HaveUserMap()) // && !(G_GetLogoFlags() & LOGO_HIDEEPISODE)) + minitext(5, a+6, GStrings.localize(gVolumeNames[ud.volume_number]), 0, 2+8+16+256); + minitext(5, a+6+6, currentLevel->DisplayName(), 0, 2+8+16+256); + } + } + } + + if (pp->invdisptime > 0) G_DrawInventory(pp); + + //if (VM_OnEvent(EVENT_DISPLAYSBAR, g_player[screenpeek].ps->i, screenpeek) == 0) + G_DrawStatusBar(screenpeek); + + G_PrintGameQuotes(screenpeek); + + if (ud.show_level_text && hud_showmapname && g_levelTextTime > 1 && !M_Active()) + { + int32_t o = 10|16; + + if (g_levelTextTime < 3) + o |= 1|32; + else if (g_levelTextTime < 5) + o |= 1; + + menutext_(160<<16, (90+16+8)<<16, -g_levelTextTime+22/*quotepulseshade*/, currentLevel->DisplayName(), o, TEXT_XCENTER); + } + + if (!DEER && g_player[myconnectindex].ps->newowner == -1 && ud.overhead_on == 0 && cl_crosshair && ud.camerasprite == -1) + { + int32_t a = CROSSHAIR; + //ud.returnvar[0] = (160<<16) - (fix16_to_int(g_player[myconnectindex].ps->q16look_ang)<<15); + //ud.returnvar[1] = 100<<16; + //int32_t a = VM_OnEventWithReturn(EVENT_DISPLAYCROSSHAIR, g_player[screenpeek].ps->i, screenpeek, CROSSHAIR); + if ((unsigned) a < MAXTILES) + { + vec2_t crosshairpos = { (160<<16) - (fix16_to_int(g_player[myconnectindex].ps->q16look_ang)<<15), 100<<16 }; + //vec2_t crosshairpos = { ud.returnvar[0], ud.returnvar[1] }; + uint32_t crosshair_o = 1|2; + uint32_t crosshair_scale = divscale16(cl_crosshairscale, 100); + if (RR) + crosshair_scale >>= 1; + + rotatesprite_win(crosshairpos.x, crosshairpos.y, crosshair_scale, 0, a, 0, 0, crosshair_o); + } + } + + /* + if (VM_HaveEvent(EVENT_DISPLAYREST)) + { + int32_t vr=viewingrange, asp=yxaspect; + VM_ExecuteEvent(EVENT_DISPLAYREST, g_player[screenpeek].ps->i, screenpeek); + renderSetAspect(vr, asp); + } + */ + + if (paused==1 && (g_player[myconnectindex].ps->gm&MODE_MENU) == 0) + menutext_center(100, GStrings("Game Paused")); + + mdpause = (paused || (ud.recstat==2 && (g_demo_paused && g_demo_goalCnt==0)) || (g_player[myconnectindex].ps->gm&MODE_MENU && numplayers < 2)); + + // JBF 20040124: display level stats in screen corner + if (ud.overhead_on != 2 && hud_stats) // && VM_OnEvent(EVENT_DISPLAYLEVELSTATS, g_player[screenpeek].ps->i, screenpeek) == 0) + { + DukePlayer_t const * const myps = g_player[myconnectindex].ps; + int const sbarshift = RR ? 15 : 16; + int const ystep = RR ? (10<<16) : (7<<16); + + i = 198<<16; + + if (ud.screen_size == 4) + { + if (ud.althud == 0 || hud_position == 0) + i -= sbarsc(ud.althud ? ((tilesiz[BIGALPHANUM].y< 2) + i -= sbarsc(tilesiz[BOTTOMSTATUSBAR].y<player_par/(REALGAMETICSPERSEC*60)), + (myps->player_par/REALGAMETICSPERSEC)%60, + ((myps->player_par%REALGAMETICSPERSEC)*33)/10 + ); + G_ScreenText(MF_Bluefont.tilenum, 2<<16, i-gtextsc(ystep*3), gtextsc(MF_Bluefont.zoom), 0, 0, tempbuf, 0, 10, 2|8|16|256|ROTATESPRITE_FULL16, 0, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, xbetween, MF_Bluefont.between.y, MF_Bluefont.textflags|TEXT_XOFFSETZERO|TEXT_GAMETEXTNUMHACK, 0, 0, xdim-1, ydim-1); + + if ((!RR && ud.player_skill > 3) || ((g_netServer || ud.multimode > 1) && !GTFLAGS(GAMETYPE_PLAYERSFRIENDLY))) + Bsprintf(tempbuf, "K:^15%d", (ud.multimode>1 &&!GTFLAGS(GAMETYPE_PLAYERSFRIENDLY)) ? + myps->frag-myps->fraggedself : myps->actors_killed); + else + { + if (myps->actors_killed >= myps->max_actors_killed) + Bsprintf(tempbuf, "K:%d/%d", myps->actors_killed, myps->actors_killed); + else + Bsprintf(tempbuf, "K:^15%d/%d", myps->actors_killed, myps->max_actors_killed); + } + G_ScreenText(MF_Bluefont.tilenum, 2<<16, i-gtextsc(ystep*2), gtextsc(MF_Bluefont.zoom), 0, 0, tempbuf, 0, 10, 2|8|16|256|ROTATESPRITE_FULL16, 0, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, xbetween, MF_Bluefont.between.y, MF_Bluefont.textflags|TEXT_XOFFSETZERO|TEXT_GAMETEXTNUMHACK, 0, 0, xdim-1, ydim-1); + + if (myps->secret_rooms == myps->max_secret_rooms) + Bsprintf(tempbuf, "S:%d/%d", myps->secret_rooms, myps->max_secret_rooms); + else Bsprintf(tempbuf, "S:^15%d/%d", myps->secret_rooms, myps->max_secret_rooms); + G_ScreenText(MF_Bluefont.tilenum, 2<<16, i-gtextsc(ystep), gtextsc(MF_Bluefont.zoom), 0, 0, tempbuf, 0, 10, 2|8|16|256|ROTATESPRITE_FULL16, 0, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, xbetween, MF_Bluefont.between.y, MF_Bluefont.textflags|TEXT_XOFFSETZERO|TEXT_GAMETEXTNUMHACK, 0, 0, xdim-1, ydim-1); + } + + if (g_player[myconnectindex].gotvote == 0 && voting != -1 && voting != myconnectindex) + { + Bsprintf(tempbuf, "%s^00 has called a vote for map", g_player[voting].user_name); + gametext_center(40, tempbuf); + Bsprintf(tempbuf, "%s (E%dL%d)", mapList[vote_episode*MAXLEVELS + vote_map].DisplayName(), vote_episode+1, vote_map+1); + gametext_center(48, tempbuf); + gametext_center(70, "Press F1 to Accept, F2 to Decline"); + } + + if (buttonMap.ButtonDown(gamefunc_Show_DukeMatch_Scores)) + G_ShowScores(); + + Net_DisplaySyncMsg(); + +#ifndef EDUKE32_TOUCH_DEVICES + if (VOLUMEONE) + { + if (g_showShareware > 0 && (g_player[myconnectindex].ps->gm&MODE_MENU) == 0) + rotatesprite_fs((320-50)<<16, 9<<16, 65536L, 0, BETAVERSION, 0, 0, 2+8+16+128); + } +#endif + + if (!Demo_IsProfiling()) + { + if (g_player[myconnectindex].ps->gm&MODE_TYPE) + Net_SendMessage(); + //else + //M_DisplayMenus(); + } + + { + static int32_t applied = 0; + + if (tint.maxf) + { + G_FadePalaccum(&tint); + applied = 1; + } + else if (applied) + { + // be sure to always un-apply a tint. + videoFadePalette(0, 0, 0, 0); + applied = 0; + } + } +} + +void G_FadePalette(int32_t r, int32_t g, int32_t b, int32_t e) +{ + if (ud.screenfade == 0) + return; + videoFadePalette(r, g, b, e); + videoNextPage(); + + int32_t tc = (int32_t) totalclock; + while (totalclock < tc + 4) + G_HandleAsync(); +} + +// START and END limits are always inclusive! +// STEP must evenly divide END-START, i.e. abs(end-start)%step == 0 +void fadepal(int32_t r, int32_t g, int32_t b, int32_t start, int32_t end, int32_t step) +{ + if (ud.screenfade == 0) + return; + if (videoGetRenderMode() >= REND_POLYMOST) + { + G_FadePalette(r, g, b, end); + return; + } + + // (end-start)/step + 1 iterations + do + { + if (inputState.GetKeyStatus(sc_Space)) + { + inputState.ClearKeyStatus(sc_Space); + videoFadePalette(r, g, b, end); // have to set to end fade value if we break! + return; + } + + G_FadePalette(r, g, b, start); + + start += step; + } while (start != end+step); +} + +// START and END limits are always inclusive! +static void fadepaltile(int32_t r, int32_t g, int32_t b, int32_t start, int32_t end, int32_t step, int32_t tile, int basepal) +{ + if (ud.screenfade == 0) + return; + // STEP must evenly divide END-START + Bassert(klabs(end-start)%step == 0); + + videoClearScreen(0); + + // (end-start)/step + 1 iterations + do + { + if (inputState.GetKeyStatus(sc_Space)) + { + inputState.ClearKeyStatus(sc_Space); + videoFadePalette(r, g, b, end); // have to set to end fade value if we break! + return; + } + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, tile, 0, 0, 2+8+64+BGSTRETCH, nullptr, basepal); + G_FadePalette(r, g, b, start); + + start += step; + } while (start != end+step); +} + +void G_DisplayExtraScreens(void) +{ + Mus_Stop(); + FX_StopAllSounds(); + if (RR) + return; + + if (!VOLUMEALL) + { + videoSetViewableArea(0, 0, xdim-1, ydim-1); + renderFlushPerms(); + //g_player[myconnectindex].ps->palette = palette; + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + fadepal(0, 0, 0, 0, 252, 28); + inputState.ClearAllInput(); + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, 3291, 0, 0, 2+8+64+BGSTRETCH); + fadepaltile(0, 0, 0, 252, 0, -28, 3291, BASEPAL); + while (!inputState.CheckAllInput()) + G_HandleAsync(); + + fadepaltile(0, 0, 0, 0, 252, 28, 3291, BASEPAL); + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, 3290, 0, 0, 2+8+64+BGSTRETCH); + fadepaltile(0, 0, 0, 252, 0, -28, 3290, BASEPAL); + while (!inputState.CheckAllInput()) + G_HandleAsync(); + + } + + if (0) + { + videoSetViewableArea(0, 0, xdim-1, ydim-1); + renderFlushPerms(); + //g_player[myconnectindex].ps->palette = palette; + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + fadepal(0, 0, 0, 0, 252, 28); + inputState.ClearAllInput(); + totalclock = 0; + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, TENSCREEN, 0, 0, 2+8+64+BGSTRETCH); + fadepaltile(0, 0, 0, 252, 0, -28, TENSCREEN, BASEPAL); + while (!inputState.CheckAllInput() && totalclock < 2400) + G_HandleAsync(); + + fadepaltile(0, 0, 0, 0, 252, 28, TENSCREEN, BASEPAL); + inputState.ClearAllInput(); + } +} + +void G_DisplayLogo(void) +{ + int32_t soundanm = 0; + //int32_t logoflags = G_GetLogoFlags(); + + ready2send = 0; + + inputState.ClearAllInput(); + + videoSetViewableArea(0, 0, xdim-1, ydim-1); + videoClearScreen(0L); + G_FadePalette(0, 0, 0, 252); + + renderFlushPerms(); + videoNextPage(); + + Mus_Stop(); + FX_StopAllSounds(); // JBF 20031228 + if (DEER) + { + if (!g_noLogo /* && (!g_netServer && ud.multimode < 2) */) + { + if (!inputState.CheckAllInput() && g_noLogoAnim == 0) + { + videoClearScreen(0); + + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + fadepal(0, 0, 0, 0, 252, 28); + renderFlushPerms(); + rotatesprite_fs(160 << 16, 100 << 16, 65536L, 0, 7106, 0, 0, 2 + 8 + 64 + BGSTRETCH); + videoNextPage(); + fadepaltile(0, 0, 0, 252, 0, -4, 7106, BASEPAL); + totalclock = 0; + + while (totalclock < (120 * 3) && !inputState.CheckAllInput()) + { + if (G_FPSLimit()) + { + videoClearScreen(0); + rotatesprite_fs(160 << 16, 100 << 16, 65536L, 0, 7106, 0, 0, 2 + 8 + 64 + BGSTRETCH); + G_HandleAsync(); + + if (g_restorePalette) + { + P_SetGamePalette(g_player[myconnectindex].ps, g_player[myconnectindex].ps->palette, 0); + g_restorePalette = 0; + } + videoNextPage(); + } + } + + fadepaltile(0, 0, 0, 0, 252, 4, 7106, BASEPAL); + } + + videoClearScreen(0L); + videoNextPage(); + + inputState.ClearAllInput(); + + videoClearScreen(0L); + videoNextPage(); + + videoClearScreen(0); + + //g_player[myconnectindex].ps->palette = drealms; + //G_FadePalette(0,0,0,252); + + if (!inputState.CheckAllInput() && g_noLogoAnim == 0) + { + videoClearScreen(0); + + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + fadepal(0, 0, 0, 0, 252, 28); + renderFlushPerms(); + rotatesprite_fs(160 << 16, 100 << 16, 65536L, 0, 7107, 0, 0, 2 + 8 + 64 + BGSTRETCH); + videoNextPage(); + fadepaltile(0, 0, 0, 252, 0, -4, 7107, BASEPAL); + totalclock = 0; + + while (totalclock < (120 * 3) && !inputState.CheckAllInput()) + { + if (G_FPSLimit()) + { + videoClearScreen(0); + rotatesprite_fs(160 << 16, 100 << 16, 65536L, 0, 7107, 0, 0, 2 + 8 + 64 + BGSTRETCH); + G_HandleAsync(); + + if (g_restorePalette) + { + P_SetGamePalette(g_player[myconnectindex].ps, g_player[myconnectindex].ps->palette, 0); + g_restorePalette = 0; + } + videoNextPage(); + } + } + + fadepaltile(0, 0, 0, 0, 252, 4, 7107, BASEPAL); + } + + inputState.ClearAllInput(); + } + + renderFlushPerms(); + videoClearScreen(0L); + videoNextPage(); + + //g_player[myconnectindex].ps->palette = palette; + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + + //G_FadePalette(0,0,0,0); + videoClearScreen(0L); + + g_noLogo = 1; // Play intro only once + return; + } + if (RRRA) + return; + if (RR) + { + if (!inputState.CheckAllInput() && g_noLogoAnim == 0 && !userConfig.nologo) + { + Net_GetPackets(); + Anim_Play("rr_intro.anm"); + G_FadePalette(0, 0, 0, 252); + inputState.ClearAllInput(); + } + + videoClearScreen(0L); + videoNextPage(); + FX_StopAllSounds(); + S_ClearSoundLocks(); + + if (!inputState.CheckAllInput() && g_noLogoAnim == 0 && !userConfig.nologo) + { + Net_GetPackets(); + Anim_Play("redneck.anm"); + G_FadePalette(0, 0, 0, 252); + inputState.ClearAllInput(); + } + + videoClearScreen(0L); + videoNextPage(); + FX_StopAllSounds(); + S_ClearSoundLocks(); + + if (!inputState.CheckAllInput() && g_noLogoAnim == 0 && !userConfig.nologo) + { + Net_GetPackets(); + Anim_Play("xatlogo.anm"); + G_FadePalette(0, 0, 0, 252); + inputState.ClearAllInput(); + } + + videoClearScreen(0L); + videoNextPage(); + FX_StopAllSounds(); + S_ClearSoundLocks(); + + //g_player[myconnectindex].ps->palette = palette; + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + S_PlaySound(NITEVISION_ONOFF, CHAN_AUTO, CHANF_UI); + + //G_FadePalette(0,0,0,0); + videoClearScreen(0L); + return; + } + if (!g_noLogo && !userConfig.nologo /* && (!g_netServer && ud.multimode < 2) */) + { + if (VOLUMEALL) + { + if (!inputState.CheckAllInput() && g_noLogoAnim == 0 && !userConfig.nologo) + { + Net_GetPackets(); + Anim_Play("logo.anm"); + G_FadePalette(0, 0, 0, 252); + inputState.ClearAllInput(); + } + + videoClearScreen(0L); + videoNextPage(); + FX_StopAllSounds(); + S_ClearSoundLocks(); + } + + S_PlaySpecialMusicOrNothing(MUS_INTRO); + + //g_player[myconnectindex].ps->palette = drealms; + //G_FadePalette(0,0,0,252); + + if (!inputState.CheckAllInput() && g_noLogoAnim == 0 && !userConfig.nologo) + { + Net_GetPackets(); + + if (fileSystem.FileExists("3dr.ivf") || fileSystem.FileExists("3dr.anm")) + { + Anim_Play("3dr.anm"); + G_FadePalette(0, 0, 0, 252); + inputState.ClearAllInput(); + } + else + { + videoClearScreen(0); + + fadepal(0, 0, 0, 0, 252, 28); + renderFlushPerms(); + rotatesprite_fs(160 << 16, 100 << 16, 65536L, 0, DREALMS, 0, 0, 2 + 8 + 64 + BGSTRETCH, nullptr, DREALMSPAL); + videoNextPage(); + fadepaltile(0, 0, 0, 252, 0, -28, DREALMS, DREALMSPAL); + totalclock = 0; + + while (totalclock < (120 * 7) && !inputState.CheckAllInput()) + { + if (G_FPSLimit()) + { + videoClearScreen(0); + rotatesprite_fs(160 << 16, 100 << 16, 65536L, 0, DREALMS, 0, 0, 2 + 8 + 64 + BGSTRETCH, nullptr, DREALMSPAL); + G_HandleAsync(); + videoNextPage(); + } + } + + fadepaltile(0, 0, 0, 0, 252, 28, DREALMS, DREALMSPAL); + } + } + + videoClearScreen(0L); + videoNextPage(); + + inputState.ClearAllInput(); + + videoClearScreen(0L); + videoNextPage(); + + videoClearScreen(0); + + //g_player[myconnectindex].ps->palette = titlepal; + renderFlushPerms(); + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, BETASCREEN, 0, 0, 2+8+64+BGSTRETCH, nullptr, TITLEPAL); + inputState.keyFlushChars(); + fadepaltile(0, 0, 0, 252, 0, -28, BETASCREEN, TITLEPAL); + totalclock = 0; + + while ( + totalclock < (860+120) && + !inputState.CheckAllInput()) + { + if (G_FPSLimit()) + { + videoClearScreen(0); + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, BETASCREEN, 0, 0, 2+8+64+BGSTRETCH, nullptr, TITLEPAL); + + if (totalclock > 120 && totalclock < (120+60)) + { + if (soundanm == 0) + { + soundanm++; + S_PlaySound(PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); + } + rotatesprite_fs(160<<16, 104<<16, ((int32_t) totalclock-120)<<10, 0, DUKENUKEM, 0, 0, 2+8, nullptr, TITLEPAL); + } + else if (totalclock >= (120+60)) + rotatesprite_fs(160<<16, (104)<<16, 60<<10, 0, DUKENUKEM, 0, 0, 2+8, nullptr, TITLEPAL); + + if (totalclock > 220 && totalclock < (220+30)) + { + if (soundanm == 1) + { + soundanm++; + S_PlaySound(PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); + } + + rotatesprite_fs(160<<16, (104)<<16, 60<<10, 0, DUKENUKEM, 0, 0, 2+8, nullptr, TITLEPAL); + rotatesprite_fs(160<<16, (129)<<16, ((int32_t) totalclock - 220)<<11, 0, THREEDEE, 0, 0, 2+8, nullptr, TITLEPAL); + } + else if (totalclock >= (220+30)) + rotatesprite_fs(160<<16, (129)<<16, 30<<11, 0, THREEDEE, 0, 0, 2+8, nullptr, TITLEPAL); + + if (PLUTOPAK) + { + // JBF 20030804 + if (totalclock >= 280 && totalclock < 395) + { + rotatesprite_fs(160<<16, (151)<<16, (410-(int32_t) totalclock)<<12, 0, PLUTOPAKSPRITE+1, (sintable[((int32_t) totalclock<<4)&2047]>>11), 0, 2+8, nullptr, TITLEPAL); + if (soundanm == 2) + { + soundanm++; + S_PlaySound(FLY_BY, CHAN_AUTO, CHANF_UI); + } + } + else if (totalclock >= 395) + { + if (soundanm == 3) + { + soundanm++; + S_PlaySound(PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); + } + rotatesprite_fs(160<<16, (151)<<16, 30<<11, 0, PLUTOPAKSPRITE+1, (sintable[((int32_t) totalclock<<4)&2047]>>11), 0, 2+8, nullptr, TITLEPAL); + } + } + + videoNextPage(); + } + + G_HandleAsync(); + } + + inputState.ClearAllInput(); + } + + renderFlushPerms(); + videoClearScreen(0L); + videoNextPage(); + + //g_player[myconnectindex].ps->palette = palette; + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + S_PlaySound(NITEVISION_ONOFF, CHAN_AUTO, CHANF_UI); + + //G_FadePalette(0,0,0,0); + videoClearScreen(0L); +} + +void G_DoOrderScreen(void) +{ + int32_t i; + + videoSetViewableArea(0, 0, xdim-1, ydim-1); + + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + + for (i=0; i<4; i++) + { + fadepal(0, 0, 0, 0, 252, 28); + inputState.ClearAllInput(); + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, ORDERING+i, 0, 0, 2+8+64+BGSTRETCH); + fadepal(0, 0, 0, 252, 0, -28); + while (!inputState.CheckAllInput()) + G_HandleAsync(); + } +} + + +static void G_BonusCutscenes(void) +{ + if (RRRA) + return; + if (!(numplayers < 2 && ud.eog && ud.from_bonus == 0)) + return; + + if (RR) + { + switch (ud.volume_number) + { + case 0: + videoClearScreen(0L); + videoNextPage(); + if (adult_lockout == 0) + { + Anim_Play("turdmov.anm"); + inputState.ClearAllInput(); + videoClearScreen(0L); + videoNextPage(); + } + m_level_number = ud.level_number = 0; + ud.m_volume_number = ud.volume_number = 1; + ud.eog = 0; + fadepal(0, 0, 0, 0, 252, 4); + inputState.ClearAllInput(); + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); + rotatesprite_fs(0, 0, 65536L, 0, TENSCREEN, 0, 0, 2+8+16+64+128+BGSTRETCH); + videoNextPage(); + fadepal(0, 0, 0, 252, 0, -4); + inputState.ClearAllInput(); + G_HandleEventsWhileNoInput(); + fadepal(0, 0, 0, 0, 252, 4); + FX_StopAllSounds(); + S_ClearSoundLocks(); + break; + case 1: + videoClearScreen(0L); + videoNextPage(); + if (adult_lockout == 0) + { + Anim_Play("rr_outro.anm"); + inputState.ClearAllInput(); + videoClearScreen(0L); + videoNextPage(); + } + g_lastLevel = 0; + g_vixenLevel = 1; + ud.level_number = 0; + ud.volume_number = 0; + fadepal(0, 0, 0, 0, 252, 4); + videoSetViewableArea(0, 0, xdim-1, ydim-1); + inputState.ClearAllInput(); + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); + rotatesprite_fs(0, 0, 65536L, 0, TENSCREEN, 0, 0, 2 + 8 + 16 + 64 + 128 + BGSTRETCH); + videoNextPage(); + fadepal(0, 0, 0, 252, 0, -4); + inputState.ClearAllInput(); + G_HandleEventsWhileNoInput(); + fadepal(0, 0, 0, 0, 252, 4); + FX_StopAllSounds(); + S_ClearSoundLocks(); + break; + } + return; + } + + switch (ud.volume_number) + { + case 0: + if (adult_lockout == 0) + { + int32_t bonuscnt=0; + int32_t const bossmove [] = + { + 0, 120, VICTORY1+3, 86, 59, + 220, 260, VICTORY1+4, 86, 59, + 260, 290, VICTORY1+5, 86, 59, + 290, 320, VICTORY1+6, 86, 59, + 320, 350, VICTORY1+7, 86, 59, + 350, 380, VICTORY1+8, 86, 59, + 350, 380, VICTORY1+8, 86, 59 // duplicate row to alleviate overflow in the for loop below "boss" + }; + + videoClearScreen(0L); + rotatesprite_fs(0, 50<<16, 65536L, 0, VICTORY1, 0, 0, 2+8+16+64+128+BGSTRETCH, nullptr, ENDINGPAL); + videoNextPage(); + fadepal(0, 0, 0, 252, 0, -4); + + inputState.ClearAllInput(); + totalclock = 0; + + while (1) + { + if (G_FPSLimit()) + { + videoClearScreen(0L); + rotatesprite_fs(0, 50 << 16, 65536L, 0, VICTORY1, 0, 0, 2 + 8 + 16 + 64 + 128 + BGSTRETCH, nullptr, ENDINGPAL); + + // boss + if (totalclock > 390 && totalclock < 780) + for (bssize_t t=0; t<35; t+=5) if (bossmove[t+2] && (totalclock%390) > bossmove[t] && (totalclock%390) <= bossmove[t+1]) + { + if (t==10 && bonuscnt == 1) + { + S_PlaySound(SHOTGUN_FIRE, CHAN_AUTO, CHANF_UI); + S_PlaySound(SQUISHED, CHAN_AUTO, CHANF_UI); + bonuscnt++; + } + rotatesprite_fs(bossmove[t+3]<<16, bossmove[t+4]<<16, 65536L, 0, bossmove[t+2], 0, 0, 2+8+16+64+128+BGSTRETCH, nullptr, ENDINGPAL); + } + + // Breathe + if (totalclock < 450 || totalclock >= 750) + { + int32_t const breathe [] = + { + 0, 30, VICTORY1+1, 176, 59, + 30, 60, VICTORY1+2, 176, 59, + 60, 90, VICTORY1+1, 176, 59, + 90, 120, 0, 176, 59 + }; + + if (totalclock >= 750) + { + rotatesprite_fs(86<<16, 59<<16, 65536L, 0, VICTORY1+8, 0, 0, 2+8+16+64+128+BGSTRETCH, nullptr, ENDINGPAL); + if (totalclock >= 750 && bonuscnt == 2) + { + S_PlaySound(DUKETALKTOBOSS, CHAN_AUTO, CHANF_UI); + bonuscnt++; + } + + } + for (bssize_t t=0; t<20; t+=5) + if (breathe[t+2] && (totalclock%120) > breathe[t] && (totalclock%120) <= breathe[t+1]) + { + if (t==5 && bonuscnt == 0) + { + S_PlaySound(BOSSTALKTODUKE, CHAN_AUTO, CHANF_UI); + bonuscnt++; + } + rotatesprite_fs(breathe[t+3]<<16, breathe[t+4]<<16, 65536L, 0, breathe[t+2], 0, 0, 2+8+16+64+128+BGSTRETCH, nullptr, ENDINGPAL); + } + } + + videoNextPage(); + } + + G_HandleAsync(); + + if (inputState.CheckAllInput()) break; + } + + fadepal(0, 0, 0, 0, 252, 4); + } + + inputState.ClearAllInput(); + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, 3292, 0, 0, 2+8+64+BGSTRETCH); + fadepal(0, 0, 0, 252, 0, -4); + G_HandleEventsWhileNoInput(); + fadepal(0, 0, 0, 0, 252, 4); + + Mus_Stop(); + FX_StopAllSounds(); + S_ClearSoundLocks(); + break; + + case 1: + videoSetViewableArea(0, 0, xdim-1, ydim-1); + + Mus_Stop(); + videoClearScreen(0L); + videoNextPage(); + + if (adult_lockout == 0) + { + fadepal(0, 0, 0, 252, 0, -4); + Anim_Play("cineov2.anm"); + inputState.ClearAllInput(); + videoClearScreen(0L); + videoNextPage(); + + S_PlaySound(PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); + fadepal(0, 0, 0, 0, 252, 4); + } + + inputState.ClearAllInput(); + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, 3293, 0, 0, 2+8+64+BGSTRETCH); + fadepal(0, 0, 0, 252, 0, -4); + G_HandleEventsWhileNoInput(); + fadepal(0, 0, 0, 0, 252, 4); + + break; + + case 3: + videoSetViewableArea(0, 0, xdim-1, ydim-1); + + Mus_Stop(); + videoClearScreen(0L); + videoNextPage(); + + if (adult_lockout == 0) + { + fadepal(0, 0, 0, 252, 0, -4); + + inputState.ClearAllInput(); + int t = Anim_Play("vol4e1.anm"); + videoClearScreen(0L); + videoNextPage(); + if (t) + goto end_vol4e; + + t = Anim_Play("vol4e2.anm"); + videoClearScreen(0L); + videoNextPage(); + if (t) + goto end_vol4e; + + Anim_Play("vol4e3.anm"); + videoClearScreen(0L); + videoNextPage(); + } + + end_vol4e: + FX_StopAllSounds(); + S_ClearSoundLocks(); + S_PlaySound(ENDSEQVOL3SND4, CHAN_AUTO, CHANF_UI); + inputState.ClearAllInput(); + + G_FadePalette(0, 0, 0, 0); + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + // G_FadePalette(0,0,0,252); + videoClearScreen(0L); + menutext_center(60, GStrings("Thanks to all our")); + menutext_center(60+16, GStrings("fans for giving")); + menutext_center(60+16+16, GStrings("us big heads.")); + menutext_center(70+16+16+16, GStrings("Look for a Duke Nukem 3D")); + menutext_center(70+16+16+16+16, GStrings("sequel soon.")); + videoNextPage(); + + fadepal(0, 0, 0, 252, 0, -12); + videoNextPage(); + inputState.ClearAllInput(); + G_HandleEventsWhileNoInput(); + fadepal(0, 0, 0, 0, 252, 12); + + videoClearScreen(0L); + videoNextPage(); + + Anim_Play("DUKETEAM.ANM"); + + inputState.ClearAllInput(); + G_HandleEventsWhileNoInput(); + + videoClearScreen(0L); + videoNextPage(); + G_FadePalette(0, 0, 0, 252); + + FX_StopAllSounds(); + S_ClearSoundLocks(); + inputState.ClearAllInput(); + + break; + + case 2: + Mus_Stop(); + videoClearScreen(0L); + videoNextPage(); + if (adult_lockout == 0) + { + fadepal(0, 0, 0, 252, 0, -4); + Anim_Play("cineov3.anm"); + inputState.ClearAllInput(); + ototalclock = totalclock+200; + while (totalclock < ototalclock) + G_HandleAsync(); + videoClearScreen(0L); + videoNextPage(); + + FX_StopAllSounds(); + S_ClearSoundLocks(); + } + + Anim_Play("RADLOGO.ANM"); + + if (!inputState.CheckAllInput() && adult_lockout == 0) + { + if (G_PlaySoundWhileNoInput(ENDSEQVOL3SND5)) goto ENDANM; + if (G_PlaySoundWhileNoInput(ENDSEQVOL3SND6)) goto ENDANM; + if (G_PlaySoundWhileNoInput(ENDSEQVOL3SND7)) goto ENDANM; + if (G_PlaySoundWhileNoInput(ENDSEQVOL3SND8)) goto ENDANM; + if (G_PlaySoundWhileNoInput(ENDSEQVOL3SND9)) goto ENDANM; + } + + totalclock = 0; + if (PLUTOPAK) + { + while (!inputState.CheckAllInput() && totalclock < 120) + G_HandleAsync(); + } + else + { + G_HandleEventsWhileNoInput(); + } + + ENDANM: + if (!PLUTOPAK) + { + FX_StopAllSounds(); + S_ClearSoundLocks(); + S_PlaySound(ENDSEQVOL3SND4, CHAN_AUTO, CHANF_UI); + + videoClearScreen(0L); + videoNextPage(); + + Anim_Play("DUKETEAM.ANM"); + + inputState.ClearAllInput(); + G_HandleEventsWhileNoInput(); + + videoClearScreen(0L); + videoNextPage(); + G_FadePalette(0, 0, 0, 252); + } + + inputState.ClearAllInput(); + FX_StopAllSounds(); + S_ClearSoundLocks(); + + videoClearScreen(0L); + + break; + } +} + +static void G_DisplayMPResultsScreen(void) +{ + int32_t i, y, t = 0; + + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, MENUSCREEN, 16, 0, 2+8+64+BGSTRETCH); + rotatesprite_fs(160<<16, 34<<16, RR ? 23592L : 65536L, 0, INGAMEDUKETHREEDEE, 0, 0, 10); + if (!RR && PLUTOPAK) // JBF 20030804 + rotatesprite_fs((260)<<16, 36<<16, 65536L, 0, PLUTOPAKSPRITE+2, 0, 0, 2+8); + gametext_center(58+(RR ? 0 : 2), GStrings("Multiplayer Totals")); + gametext_center(58+10, currentLevel->DisplayName()); + + gametext_center_shade(RR ? 175 : 165, GStrings("Presskey"), quotepulseshade); + + minitext(38, 80, GStrings("Name"), 8, 2+8+16+128); + minitext(269, 80, GStrings("Kills"), 8, 2+8+16+128); + for (i=0; ipalookup, 2+8+16+128); + + for (y=0; yfraggedself); + minitext(92+(y*23), 90+t, tempbuf, RR ? 0 : 2, 2+8+16+128); + xfragtotal -= g_player[y].ps->fraggedself; + } + else + { + Bsprintf(tempbuf, "%-4d", g_player[i].frags[y]); + minitext(92+(y*23), 90+t, tempbuf, 0, 2+8+16+128); + xfragtotal += g_player[i].frags[y]; + } + } + + Bsprintf(tempbuf, "%-4d", xfragtotal); + minitext(101+(8*23), 90+t, tempbuf, RR ? 0 : 2, 2+8+16+128); + + t += 7; + } + + for (y=0; yfraggedself; + else + yfragtotal += g_player[i].frags[y]; + } + Bsprintf(tempbuf, "%-4d", yfragtotal); + minitext(92+(y*23), 96+(8*7), tempbuf, RR ? 0 : 2, 2+8+16+128); + } + + minitext(45, 96+(8*7), GStrings("Deaths"), RR ? 0 : 8, 2+8+16+128); +} + +static int32_t G_PrintTime_ClockPad(void) +{ + int32_t clockpad = 2; + int32_t ii, ij; + + for (ii=g_player[myconnectindex].ps->player_par/(REALGAMETICSPERSEC*60), ij=1; ii>9; ii/=10, ij++) { } + clockpad = max(clockpad, ij); + if (!(ud.volume_number == 0 && ud.last_level-1 == 7 && boardfilename[0])) + { + for (ii=currentLevel->parTime/(60), ij=1; ii>9; ii/=10, ij++) { } + clockpad = max(clockpad, ij); + if (currentLevel->designerTime) + { + for (ii=currentLevel->designerTime/(60), ij=1; ii>9; ii/=10, ij++) { } + clockpad = max(clockpad, ij); + } + } + if (ud.playerbest > 0) for (ii=ud.playerbest/(REALGAMETICSPERSEC*60), ij=1; ii>9; ii/=10, ij++) { } + clockpad = max(clockpad, ij); + + return clockpad; +} + +static const char* G_PrintTime2(int32_t time) +{ + Bsprintf(tempbuf, RR ? "%0*d : %02d" : "%0*d:%02d", G_PrintTime_ClockPad(), time/(REALGAMETICSPERSEC*60), (time/REALGAMETICSPERSEC)%60); + return tempbuf; +} +static const char* G_PrintTime3(int32_t time) +{ + Bsprintf(tempbuf, RR ? "%0*d : %02d . %02d" : "%0*d:%02d.%02d", G_PrintTime_ClockPad(), time/(REALGAMETICSPERSEC*60), (time/REALGAMETICSPERSEC)%60, ((time%REALGAMETICSPERSEC)*33)/10); + return tempbuf; +} + +const char* G_PrintYourTime(void) +{ + return G_PrintTime3(g_player[myconnectindex].ps->player_par); +} +const char* G_PrintParTime(void) +{ + if (ud.last_level < 1) + return ""; + return G_PrintTime2(currentLevel->parTime * REALGAMETICSPERSEC); +} +const char* G_PrintDesignerTime(void) +{ + if (ud.last_level < 1) + return ""; + return G_PrintTime2(currentLevel->designerTime*REALGAMETICSPERSEC); +} +const char* G_PrintBestTime(void) +{ + return G_PrintTime3(ud.playerbest); +} + +void G_BonusScreen(int32_t bonusonly) +{ + int32_t gfx_offset; + int32_t bonuscnt; + int32_t clockpad = 2; + const char *lastmapname; + + //if (g_networkMode == NET_DEDICATED_SERVER) + // return; + + if (ud.volume_number == 0 && ud.last_level == 8 && boardfilename[0]) + { + lastmapname = Bstrrchr(boardfilename, '\\'); + if (!lastmapname) lastmapname = Bstrrchr(boardfilename, '/'); + if (!lastmapname) lastmapname = boardfilename; + } + else + { + lastmapname = currentLevel->DisplayName(); + } + + fadepal(0, 0, 0, 0, 252, RR ? 4 : 28); + videoSetViewableArea(0, 0, xdim-1, ydim-1); + videoClearScreen(0L); + videoNextPage(); + renderFlushPerms(); + + FX_StopAllSounds(); + S_ClearSoundLocks(); + FX_SetReverb(0L); + inputState.SetBindsEnabled(1); // so you can use your screenshot bind on the score screens + + if (!bonusonly) + G_BonusCutscenes(); + + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + G_FadePalette(0, 0, 0, 252); // JBF 20031228 + inputState.keyFlushChars(); + totalclock = 0; + bonuscnt = 0; + + Mus_Stop(); + FX_StopAllSounds(); + S_ClearSoundLocks(); + + if (g_mostConcurrentPlayers > 1 && (g_gametypeFlags[ud.coop]&GAMETYPE_SCORESHEET)) + { + videoClearScreen(0); + G_DisplayMPResultsScreen(); + + PlayBonusMusic(); + + videoNextPage(); + inputState.ClearAllInput(); + fadepal(0, 0, 0, 252, 0, RR ? -4 : -28); + totalclock = 0; + + while (totalclock < TICRATE*10) + { + G_HandleAsync(); + + if (G_FPSLimit()) + { + videoClearScreen(0); + G_DisplayMPResultsScreen(); + videoNextPage(); + } + + if (inputState.CheckAllInput()) + { + break; + } + } + + fadepal(0, 0, 0, 0, 252, RR ? 4 : 28); + } + + if (bonusonly || (g_netServer || ud.multimode > 1)) return; + + if (!RR) + { + gfx_offset = (ud.volume_number==1) ? 5 : 0; + gfx_offset += BONUSSCREEN; + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, gfx_offset, 0, 0, 2+8+64+128+BGSTRETCH); + + if (lastmapname) + menutext_center(20-6, lastmapname); + menutext_center(36-6, GStrings("Completed")); + + gametext_center_shade(192, GStrings("PRESSKEY"), quotepulseshade); + + PlayBonusMusic(); + } + else + { + gfx_offset = (ud.volume_number==0) ? RRTILE403 : RRTILE409; + gfx_offset += ud.level_number-1; + + if (g_lastLevel || g_vixenLevel) + gfx_offset = RRTILE409+7; + + if (boardfilename[0]) + gfx_offset = RRTILE403; + + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, gfx_offset, 0, 0, 2+8+64+128+BGSTRETCH); + if (lastmapname) + menutext(80,16, lastmapname); + + menutext(15, 192, GStrings("PRESSKEY")); + } + + videoNextPage(); + inputState.ClearAllInput(); + fadepal(0, 0, 0, 252, 0, -4); + bonuscnt = 0; + totalclock = 0; + + do + { + int32_t yy = 0, zz; + + G_HandleAsync(); + + if (G_FPSLimit()) + { + if (g_player[myconnectindex].ps->gm&MODE_EOL) + { + videoClearScreen(0); + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, gfx_offset, 0, 0, 2+8+64+128+BGSTRETCH); + + if (totalclock >= 1000000000 && totalclock < 1000000320) + { + switch (((int32_t) totalclock>>4)%15) + { + case 0: + if (bonuscnt == 6) + { + bonuscnt++; + S_PlaySound(RR ? 425 : SHOTGUN_COCK, CHAN_AUTO, CHANF_UI); + switch (rand()&3) + { + case 0: + S_PlaySound(BONUS_SPEECH1, CHAN_AUTO, CHANF_UI); + break; + case 1: + S_PlaySound(BONUS_SPEECH2, CHAN_AUTO, CHANF_UI); + break; + case 2: + S_PlaySound(BONUS_SPEECH3, CHAN_AUTO, CHANF_UI); + break; + case 3: + S_PlaySound(BONUS_SPEECH4, CHAN_AUTO, CHANF_UI); + break; + } + } + fallthrough__; + case 1: + case 4: + case 5: + if (!RR) + rotatesprite_fs(199<<16, 31<<16, 65536L, 0, 3+gfx_offset, 0, 0, 2+8+16+64+128+BGSTRETCH); + break; + case 2: + case 3: + if (!RR) + rotatesprite_fs(199<<16, 31<<16, 65536L, 0, 4+gfx_offset, 0, 0, 2+8+16+64+128+BGSTRETCH); + break; + } + } + else if (totalclock > (10240+120L)) break; + else + { + switch (((int32_t) totalclock>>5)&3) + { + case 1: + case 3: + if (!RR) + rotatesprite_fs(199<<16, 31<<16, 65536L, 0, 1+gfx_offset, 0, 0, 2+8+16+64+128+BGSTRETCH); + break; + case 2: + if (!RR) + rotatesprite_fs(199<<16, 31<<16, 65536L, 0, 2+gfx_offset, 0, 0, 2+8+16+64+128+BGSTRETCH); + break; + } + } + + if (!RR) + { + if (lastmapname) + menutext_center(20-6, lastmapname); + menutext_center(36-6, GStrings("Completed")); + + gametext_center_shade(192, GStrings("PRESSKEY"), quotepulseshade); + } + else + { + if (lastmapname) + menutext(80, 16, lastmapname); + + menutext(15, 192, GStrings("PRESSKEY")); + } + + const int yystep = RR ? 16 : 10; + if (totalclock > (60*3)) + { + yy = zz = RR ? 48 : 59; + + if (!RR) + gametext(10, yy+9, GStrings("TXT_YourTime")); + else + menutext(30, yy, GStrings("TXT_YerTime")); + + yy+= yystep; + if (!(ud.volume_number == 0 && ud.last_level-1 == 7 && boardfilename[0])) + { + if (currentLevel->parTime) + { + if (!RR) + gametext(10, yy+9, GStrings("TXT_ParTime")); + else + menutext(30, yy, GStrings("TXT_ParTime")); + yy+=yystep; + } + if (currentLevel->designerTime) + { + // EDuke 2.0 / NAM source suggests "Green Beret's Time:" + if (DUKE) + gametext(10, yy+9, GStrings("TXT_3DRTIME")); + else if (RR) + menutext(30, yy, GStrings("TXT_XTRTIME")); + yy+=yystep; + } + + } + if (ud.playerbest > 0) + { + if (!RR) + gametext(10, yy+9, (g_player[myconnectindex].ps->player_par > 0 && g_player[myconnectindex].ps->player_par < ud.playerbest) ? "Prev Best Time:" : "Your Best Time:"); + else + menutext(30, yy, (g_player[myconnectindex].ps->player_par > 0 && g_player[myconnectindex].ps->player_par < ud.playerbest) ? "Prev Best:" : "Yer Best:"); + yy += yystep; + } + + if (bonuscnt == 0) + bonuscnt++; + + yy = zz; + if (totalclock >(60*4)) + { + if (bonuscnt == 1) + { + bonuscnt++; + S_PlaySound(RR ? 404 : PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); + } + + if (g_player[myconnectindex].ps->player_par > 0) + { + G_PrintYourTime(); + if (!RR) + { + gametext_number((320>>2)+71, yy+9, tempbuf); + if (g_player[myconnectindex].ps->player_par < ud.playerbest) + gametext((320>>2)+89+(clockpad*24), yy+9, GStrings("TXT_NEWRECORD")); + } + else + { + menutext(191, yy, tempbuf); + //if (g_player[myconnectindex].ps->player_par < ud.playerbest) + // menutext(191 + 30 + (clockpad*24), yy, "New record!"); + } + } + else if (!RR) + gametext_pal((320>>2)+71, yy+9, GStrings("TXT_Cheated"), 2); + else + menutext(191, yy, GStrings("TXT_Cheated")); + yy+=yystep; + + if (!(ud.volume_number == 0 && ud.last_level-1 == 7 && boardfilename[0])) + { + if (currentLevel->parTime) + { + G_PrintParTime(); + if (!RR) + gametext_number((320>>2)+71, yy+9, tempbuf); + else + menutext(191, yy, tempbuf); + yy+=yystep; + } + if (currentLevel->designerTime) + { + G_PrintDesignerTime(); + if (DUKE) + gametext_number((320>>2)+71, yy+9, tempbuf); + else if (RR) + menutext(191, yy, tempbuf); + yy+=yystep; + } + } + + if (ud.playerbest > 0) + { + G_PrintBestTime(); + if (!RR) + gametext_number((320>>2)+71, yy+9, tempbuf); + else + menutext(191, yy, tempbuf); + yy+=yystep; + } + } + } + + zz = yy += RR ? 16 : 5; + if (totalclock > (60*6)) + { + if (!RR) + gametext(10, yy+9, GStrings("TXT_EnemiesKilled")); + else + menutext(30, yy, GStrings("TXT_VarmintsKilled")); + yy += yystep; + if (!RR) + gametext(10, yy+9, GStrings("TXT_EnemiesLeft")); + else + menutext(30, yy, GStrings("TXT_VarmintsLeft")); + yy += yystep; + + if (bonuscnt == 2) + { + bonuscnt++; + if (!RR) + S_PlaySound(FLY_BY, CHAN_AUTO, CHANF_UI); + } + + yy = zz; + + if (totalclock > (60*7)) + { + if (bonuscnt == 3) + { + bonuscnt++; + S_PlaySound(RR ? 422 : PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); + } + Bsprintf(tempbuf, "%-3d", g_player[myconnectindex].ps->actors_killed); + if (!RR) + gametext_number((320>>2)+70, yy+9, tempbuf); + else + menutext(231,yy,tempbuf); + yy += yystep; + if (ud.player_skill > 3 && !RR) + { + if (!RR) + gametext((320>>2)+70, yy+9, GStrings("TXT_N_A")); + else + menutext(231,yy, GStrings("TXT_N_A")); + yy += yystep; + } + else + { + if ((g_player[myconnectindex].ps->max_actors_killed-g_player[myconnectindex].ps->actors_killed) < 0) + Bsprintf(tempbuf, "%-3d", 0); + else Bsprintf(tempbuf, "%-3d", g_player[myconnectindex].ps->max_actors_killed-g_player[myconnectindex].ps->actors_killed); + if (!RR) + gametext_number((320>>2)+70, yy+9, tempbuf); + else + menutext(231, yy, tempbuf); + yy += yystep; + } + } + } + + zz = yy += RR ? 0 : 5; + if (totalclock > (60*9)) + { + if (!RR) + gametext(10, yy+9, GStrings("TXT_SECFND")); + else + menutext(30, yy, GStrings("TXT_SECFND")); + yy += yystep; + if (!RR) + gametext(10, yy+9, GStrings("TXT_SECMISS")); + else + menutext(30, yy, GStrings("TXT_SECMISS")); + yy += yystep; + if (bonuscnt == 4) bonuscnt++; + + yy = zz; + if (totalclock > (60*10)) + { + if (bonuscnt == 5) + { + bonuscnt++; + S_PlaySound(RR ? 404 : PIPEBOMB_EXPLODE, CHAN_AUTO, CHANF_UI); + } + Bsprintf(tempbuf, "%-3d", g_player[myconnectindex].ps->secret_rooms); + if (!RR) + gametext_number((320>>2)+70, yy+9, tempbuf); + else + menutext(231, yy, tempbuf); + yy += yystep; + Bsprintf(tempbuf, "%-3d", g_player[myconnectindex].ps->max_secret_rooms-g_player[myconnectindex].ps->secret_rooms); + if (!RR) + gametext_number((320>>2)+70, yy+9, tempbuf); + else + menutext(231, yy, tempbuf); + yy += yystep; + } + } + + if (totalclock > 10240 && totalclock < 10240+10240) + totalclock = 1024; + + if (inputState.CheckAllInput() && totalclock >(60*2)) // JBF 20030809 + { + if (totalclock < (60*13)) + { + totalclock = (60*13); + } + else if (totalclock < 1000000000) + totalclock = 1000000000; + } + } + else + break; + + videoNextPage(); + } + } while (1); + if (g_turdLevel) + g_turdLevel = 0; + if (g_vixenLevel) + g_vixenLevel = 0; +} + +void G_PlayMapAnim(void) +{ + const char *animFile; + if (ud.volume_number == 0) + { + switch (ud.level_number) + { + case 1: + animFile = "lvl1.anm"; + break; + case 2: + animFile = "lvl2.anm"; + break; + case 3: + animFile = "lvl3.anm"; + break; + case 4: + animFile = "lvl4.anm"; + break; + case 5: + animFile = "lvl5.anm"; + break; + case 6: + animFile = "lvl6.anm"; + break; + default: + animFile = "lvl7.anm"; + break; + } + } + else + { + switch (ud.level_number) + { + case 1: + animFile = "lvl8.anm"; + break; + case 2: + animFile = "lvl9.anm"; + break; + case 3: + animFile = "lvl10.anm"; + break; + case 4: + animFile = "lvl11.anm"; + break; + case 5: + animFile = "lvl12.anm"; + break; + case 6: + animFile = "lvl13.anm"; + break; + default: + animFile = NULL; + break; + } + } + + if (animFile == NULL) + return; + + Anim_Play(animFile); +} + +void G_ShowMapFrame(void) +{ + int frame = -1; + + if (ud.volume_number == 0) + { + switch (ud.level_number) + { + case 1: + frame = 0; + break; + case 2: + frame = 1; + break; + case 3: + frame = 2; + break; + case 4: + frame = 3; + break; + case 5: + frame = 4; + break; + case 6: + frame = 5; + break; + default: + frame = 6; + break; + } + } + else + { + switch (ud.level_number) + { + case 1: + frame = 7; + break; + case 2: + frame = 8; + break; + case 3: + frame = 9; + break; + case 4: + frame = 10; + break; + case 5: + frame = 11; + break; + case 6: + frame = 12; + break; + default: + frame = -1; + break; + } + } + rotatesprite_fs(160<<16,100<<16,65536L,0,RRTILE8624+frame,0,0,10+64+128); +} + +void G_BonusScreenRRRA(int32_t bonusonly) +{ + int32_t gfx_offset; + int32_t bonuscnt; + int32_t showMap = 0; + const char *lastmapname; + + //if (g_networkMode == NET_DEDICATED_SERVER) + // return; + + if (ud.volume_number == 0 && ud.last_level == 8 && boardfilename[0]) + { + lastmapname = Bstrrchr(boardfilename, '\\'); + if (!lastmapname) lastmapname = Bstrrchr(boardfilename, '/'); + if (!lastmapname) lastmapname = boardfilename; + } + else + { + lastmapname = currentLevel->DisplayName(); + } + + fadepal(0, 0, 0, 0, 252, 4); + videoSetViewableArea(0, 0, xdim-1, ydim-1); + videoClearScreen(0L); + videoNextPage(); + renderFlushPerms(); + + FX_StopAllSounds(); + S_ClearSoundLocks(); + FX_SetReverb(0L); + inputState.SetBindsEnabled(1); // so you can use your screenshot bind on the score screens + + if (boardfilename[0] == 0 && numplayers < 2) + { + if ((ud.eog == 0 || ud.volume_number != 1) && ud.volume_number <= 1) + { + showMap = 1; + Mus_Stop(); + inputState.keyFlushChars(); + + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); + G_ShowMapFrame(); + fadepal(0, 0, 0, 252, 0, -4); + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); + } + } + + if (!bonusonly) + G_BonusCutscenes(); + + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); // JBF 20040308 + //G_FadePalette(0, 0, 0, 252); // JBF 20031228 + inputState.keyFlushChars(); + totalclock = 0; + bonuscnt = 0; + + Mus_Stop(); + FX_StopAllSounds(); + S_ClearSoundLocks(); + + if (g_mostConcurrentPlayers > 1 && (g_gametypeFlags[ud.coop]&GAMETYPE_SCORESHEET)) + { + videoClearScreen(0); + G_DisplayMPResultsScreen(); + + PlayBonusMusic(); + + videoNextPage(); + inputState.ClearAllInput(); + fadepal(0, 0, 0, 252, 0, -4); + totalclock = 0; + + while (totalclock < TICRATE*10) + { + G_HandleAsync(); + + if (G_FPSLimit()) + { + videoClearScreen(0); + G_DisplayMPResultsScreen(); + videoNextPage(); + } + + if (inputState.CheckAllInput()) + { + break; + } + } + + fadepal(0, 0, 0, 0, 252, 4); + } + + if (bonusonly || (g_netServer || ud.multimode > 1)) return; + + gfx_offset = (ud.volume_number==0) ? RRTILE403 : RRTILE409; + gfx_offset += ud.level_number-1; + + if (g_lastLevel || g_vixenLevel) + gfx_offset = RRTILE409+7; + + if (boardfilename[0]) + gfx_offset = RRTILE403; + + if (!showMap) + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, gfx_offset, 0, 0, 2+8+64+128+BGSTRETCH); + if (lastmapname) + menutext(80,16, lastmapname); + + menutext(15, 192, "Press any key to continue"); + + inputState.ClearAllInput(); + if (!showMap) + { + videoNextPage(); + fadepal(0, 0, 0, 252, 0, -4); + } + bonuscnt = 0; + totalclock = 0; + + do + { + int32_t yy = 0, zz; + + G_HandleAsync(); + + if (G_FPSLimit()) + { + if (g_player[myconnectindex].ps->gm&MODE_EOL) + { + videoClearScreen(0); + if (showMap) + G_ShowMapFrame(); + else + rotatesprite_fs(160<<16, 100<<16, 65536L, 0, gfx_offset, 0, 0, 2+8+64+128+BGSTRETCH); + + if (showMap) + { + if (bonuscnt == 7) + { + bonuscnt++; + Mus_Stop(); + G_PlayMapAnim(); + break; + } + } + + if (totalclock >= 1000000000 && totalclock < 1000000320) + { + switch (((int32_t) totalclock>>4)%15) + { + case 0: + if (bonuscnt == 6) + { + bonuscnt++; + S_PlaySound(425, CHAN_AUTO, CHANF_UI); + switch (rand()&3) + { + case 0: + S_PlaySound(BONUS_SPEECH1, CHAN_AUTO, CHANF_UI); + break; + case 1: + S_PlaySound(BONUS_SPEECH2, CHAN_AUTO, CHANF_UI); + break; + case 2: + S_PlaySound(BONUS_SPEECH3, CHAN_AUTO, CHANF_UI); + break; + case 3: + S_PlaySound(BONUS_SPEECH4, CHAN_AUTO, CHANF_UI); + break; + } + } + fallthrough__; + case 1: + case 4: + case 5: + break; + case 2: + case 3: + break; + } + } + else if (totalclock > (10240+120L)) break; + else + { + switch (((int32_t) totalclock>>5)&3) + { + case 1: + case 3: + break; + case 2: + break; + } + } + + if (lastmapname) + menutext(80, 16, lastmapname); + + menutext(15, 192, GStrings("PRESSKEY")); + + const int yystep = 16; + if (totalclock > (60*3)) + { + yy = zz = 48; + + menutext(30, yy, GStrings("TXT_YERTIME")); + + yy+= yystep; + if (!(ud.volume_number == 0 && ud.last_level-1 == 7 && boardfilename[0])) + { + if (currentLevel->parTime) + { + menutext(30, yy, GStrings("TXT_PARTIME")); + yy+=yystep; + } + if (currentLevel->designerTime) + { + menutext(30, yy, GStrings("TXT_XTRTIME")); + yy+=yystep; + } + + } + if (ud.playerbest > 0) + { + menutext(30, yy, (g_player[myconnectindex].ps->player_par > 0 && g_player[myconnectindex].ps->player_par < ud.playerbest) ? "Prev Best:" : "Yer Best:"); + yy += yystep; + } + + if (bonuscnt == 0) + bonuscnt++; + + yy = zz; + if (totalclock >(60*4)) + { + if (bonuscnt == 1) + { + bonuscnt++; + S_PlaySound(404, CHAN_AUTO, CHANF_UI); + } + + if (g_player[myconnectindex].ps->player_par > 0) + { + G_PrintYourTime(); + menutext(191, yy, tempbuf); + //if (g_player[myconnectindex].ps->player_par < ud.playerbest) + // menutext(191 + 30 + (clockpad*24), yy, "New record!"); + } + else + menutext(191, yy, GStrings("TXT_Cheated")); + yy+=yystep; + + if (!(ud.volume_number == 0 && ud.last_level-1 == 7 && boardfilename[0])) + { + if (currentLevel->parTime) + { + G_PrintParTime(); + menutext(191, yy, tempbuf); + yy+=yystep; + } + if (currentLevel->designerTime) + { + G_PrintDesignerTime(); + menutext(191, yy, tempbuf); + yy+=yystep; + } + } + + if (ud.playerbest > 0) + { + G_PrintBestTime(); + menutext(191, yy, tempbuf); + yy+=yystep; + } + } + } + + zz = yy += 16; + if (totalclock > (60*6)) + { + menutext(30, yy, GStrings("TXT_VARMINTSKILLED")); + yy += yystep; + menutext(30, yy, GStrings("TXT_VARMINTSLEFT")); + yy += yystep; + + if (bonuscnt == 2) + bonuscnt++; + + yy = zz; + + if (totalclock > (60*7)) + { + if (bonuscnt == 3) + { + bonuscnt++; + S_PlaySound(422, CHAN_AUTO, CHANF_UI); + } + Bsprintf(tempbuf, "%-3d", g_player[myconnectindex].ps->actors_killed); + menutext(231,yy,tempbuf); + yy += yystep; + //if (ud.player_skill > 3) + //{ + // menutext(231,yy, "N/A"); + // yy += yystep; + //} + //else + { + if ((g_player[myconnectindex].ps->max_actors_killed-g_player[myconnectindex].ps->actors_killed) < 0) + Bsprintf(tempbuf, "%-3d", 0); + else Bsprintf(tempbuf, "%-3d", g_player[myconnectindex].ps->max_actors_killed-g_player[myconnectindex].ps->actors_killed); + menutext(231, yy, tempbuf); + yy += yystep; + } + } + } + + zz = yy += 0; + if (totalclock > (60*9)) + { + menutext(30, yy, GStrings("TXT_SECFND")); + yy += yystep; + menutext(30, yy, GStrings("TXT_SECMISS")); + yy += yystep; + if (bonuscnt == 4) bonuscnt++; + + yy = zz; + if (totalclock > (60*10)) + { + if (bonuscnt == 5) + { + bonuscnt++; + S_PlaySound(404, CHAN_AUTO, CHANF_UI); + } + Bsprintf(tempbuf, "%-3d", g_player[myconnectindex].ps->secret_rooms); + menutext(231, yy, tempbuf); + yy += yystep; + Bsprintf(tempbuf, "%-3d", g_player[myconnectindex].ps->max_secret_rooms-g_player[myconnectindex].ps->secret_rooms); + menutext(231, yy, tempbuf); + yy += yystep; + } + } + + if (totalclock > 10240 && totalclock < 10240+10240) + totalclock = 1024; + + if (inputState.CheckAllInput() && totalclock >(60*2)) // JBF 20030809 + { + if (totalclock < (60*13)) + { + totalclock = (60*13); + } + else if (totalclock < 1000000000) + totalclock = 1000000000; + } + } + else + break; + videoNextPage(); + } + } while (1); + if (ud.eog) + { + fadepal(0, 0, 0, 0, 252, 4); + videoClearScreen(0L); + videoNextPage(); + S_PlaySound(35, CHAN_AUTO, CHANF_UI); + G_FadePalette(0, 0, 0, 0); + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); + while (1) + { + switch (((int32_t) totalclock >> 4) & 1) + { + case 0: + rotatesprite(0,0,65536,0,RRTILE8677,0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + videoNextPage(); + G_FadePalette(0, 0, 0, 0); + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); + Net_GetPackets(); + break; + case 1: + rotatesprite(0,0,65536,0,RRTILE8677+1,0,0,2+8+16+64+128,0,0,xdim-1,ydim-1); + videoNextPage(); + G_FadePalette(0, 0, 0, 0); + P_SetGamePalette(g_player[myconnectindex].ps, BASEPAL, 0); + Net_GetPackets(); + break; + } + + if (!S_CheckSoundPlaying(-1,35)) break; + if (inputState.CheckAllInput()) + { + S_StopSound(35); + break; + } + } + } + if (g_RAendEpisode) + { + g_RAendEpisode = 0; + ud.m_volume_number = ud.volume_number = 1; + m_level_number = ud.level_number = 0; + ud.eog = 0; + } + if (g_turdLevel) + g_turdLevel = 0; + if (g_vixenLevel) + g_vixenLevel = 0; +} + +END_DUKE_NS diff --git a/source/duke/src/screens.h b/source/duke/src/screens.h new file mode 100644 index 000000000..8c4ad1fc1 --- /dev/null +++ b/source/duke/src/screens.h @@ -0,0 +1,44 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +BEGIN_DUKE_NS + +extern void G_DisplayExtraScreens(void); +extern void G_DisplayLogo(void); +extern void G_DoOrderScreen(void); + +#ifdef DEBUGGINGAIDS +typedef struct { + uint32_t lastgtic; + uint32_t lastnumins, numins; + int32_t numonscreen; +} sprstat_t; + +extern sprstat_t g_spriteStat; +#endif + +extern int32_t dr_yxaspect, dr_viewingrange; +extern int32_t g_noLogoAnim, g_noLogo; + +extern void G_FadePalette(int32_t r, int32_t g, int32_t b, int32_t e); + +END_DUKE_NS diff --git a/source/duke/src/sector.cpp b/source/duke/src/sector.cpp new file mode 100644 index 000000000..d23a09160 --- /dev/null +++ b/source/duke/src/sector.cpp @@ -0,0 +1,5312 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- +#include "ns.h" // Must come before everything else! + +#define sector_c_ + +#include "duke3d.h" + +#include "secrets.h" +#include "v_video.h" +#include "glbackend/glbackend.h" + +BEGIN_DUKE_NS + +// PRIMITIVE + +static int g_haltSoundHack = 0; + +uint8_t g_shadedSector[MAXSECTORS]; + +int S_FindMusicSFX(int sectNum, int *sndptr) +{ + for (bssize_t SPRITES_OF_SECT(sectNum, spriteNum)) + { + const int32_t snd = sprite[spriteNum].lotag; + EDUKE32_STATIC_ASSERT(MAXSOUNDS >= 1000); + + if (PN(spriteNum) == MUSICANDSFX && (unsigned)snd < 1000) // XXX: in other places, 999 + { + *sndptr = snd; + return spriteNum; + } + } + + *sndptr = -1; + return -1; +} + +void A_CallSound2(int soundNum, int playerNum) +{ + A_PlaySound(soundNum, g_player[playerNum].ps->i); +} + +// this function activates a sector's MUSICANDSFX sprite +int A_CallSound(int sectNum, int spriteNum) +{ + if (!RR && g_haltSoundHack) + { + g_haltSoundHack = 0; + return -1; + } + + int soundNum; + int const SFXsprite = S_FindMusicSFX(sectNum, &soundNum); + + if (SFXsprite >= 0) + { + if (spriteNum == -1) + spriteNum = SFXsprite; + + auto flags = S_GetUserFlags(soundNum); + if (T1(SFXsprite) == 0) + { + if ((flags & (SF_GLOBAL | SF_DTAG)) != SF_GLOBAL) + { + if (soundNum) + { + A_PlaySound(soundNum, spriteNum); + + if (SHT(SFXsprite) && soundNum != SHT(SFXsprite) && SHT(SFXsprite) < MAXSOUNDS) + S_StopEnvSound(SHT(SFXsprite),T6(SFXsprite)); + + T6(SFXsprite) = spriteNum; + } + + if ((sector[SECT(SFXsprite)].lotag&0xff) != ST_22_SPLITTING_DOOR) + T1(SFXsprite) = 1; + } + } + else if (SHT(SFXsprite) < MAXSOUNDS) + { + if (SHT(SFXsprite)) + A_PlaySound(SHT(SFXsprite), spriteNum); + + if ((flags & SF_LOOP) || (SHT(SFXsprite) && SHT(SFXsprite) != soundNum)) + S_StopEnvSound(soundNum, T6(SFXsprite)); + + T6(SFXsprite) = spriteNum; + T1(SFXsprite) = 0; + } + + return soundNum; + } + + return -1; +} + +int G_CheckActivatorMotion(int lotag) +{ + int spriteNum = headspritestat[STAT_ACTIVATOR]; + + while (spriteNum >= 0) + { + if (sprite[spriteNum].lotag == lotag) + { + spritetype *const pSprite = &sprite[spriteNum]; + + for (bssize_t j = g_animateCnt - 1; j >= 0; j--) + if (pSprite->sectnum == g_animateSect[j]) + return 1; + + int sectorEffector = headspritestat[STAT_EFFECTOR]; + + while (sectorEffector >= 0) + { + if (pSprite->sectnum == sprite[sectorEffector].sectnum) + { + switch (sprite[sectorEffector].lotag) + { + case SE_11_SWINGING_DOOR: + case SE_30_TWO_WAY_TRAIN: + if (actor[sectorEffector].t_data[4]) + return 1; + break; + case SE_18_INCREMENTAL_SECTOR_RISE_FALL: + if (RRRA) + break; + fallthrough__; + case SE_20_STRETCH_BRIDGE: + case SE_31_FLOOR_RISE_FALL: + case SE_32_CEILING_RISE_FALL: + if (actor[sectorEffector].t_data[0]) + return 1; + break; + } + } + + sectorEffector = nextspritestat[sectorEffector]; + } + } + spriteNum = nextspritestat[spriteNum]; + } + return 0; +} + +int CheckDoorTile(int tileNum) +{ + switch (DYNAMICTILEMAP(tileNum)) + { + case DOORTILE23__STATIC: + return !RR; + case DOORTILE1__STATIC: + case DOORTILE2__STATIC: + case DOORTILE3__STATIC: + case DOORTILE4__STATIC: + case DOORTILE5__STATIC: + case DOORTILE6__STATIC: + case DOORTILE7__STATIC: + case DOORTILE8__STATIC: + case DOORTILE9__STATIC: + case DOORTILE10__STATIC: + case DOORTILE11__STATIC: + case DOORTILE12__STATIC: + case DOORTILE14__STATIC: + case DOORTILE15__STATIC: + case DOORTILE16__STATIC: + case DOORTILE17__STATIC: + case DOORTILE18__STATIC: + case DOORTILE19__STATIC: + case DOORTILE20__STATIC: + case DOORTILE21__STATIC: + case DOORTILE22__STATIC: + case RRTILE1856__STATICRR: + case RRTILE1877__STATICRR: + return 1; + } + return 0; +} + +int CheckBlockDoorTile(int tileNum) +{ + if (tileNum == RRTILE3643) + return 0; + if (tileNum >= RRTILE3643+2 && tileNum <= RRTILE3643+3) + tileNum = RRTILE3643; + + switch (DYNAMICTILEMAP(tileNum)) + { + case RRTILE1996__STATICRR: + case RRTILE2382__STATICRR: + case RRTILE2961__STATICRR: + case RRTILE3804__STATICRR: + case RRTILE7430__STATICRR: + case RRTILE7467__STATICRR: + case RRTILE7469__STATICRR: + case RRTILE7470__STATICRR: + case RRTILE7475__STATICRR: + case RRTILE7566__STATICRR: + case RRTILE7576__STATICRR: + case RRTILE7716__STATICRR: + case RRTILE8063__STATICRR: + case RRTILE8067__STATICRR: + case RRTILE8076__STATICRR: + case RRTILE8106__STATICRR: + case RRTILE8379__STATICRR: + case RRTILE8380__STATICRR: + case RRTILE8565__STATICRR: + case RRTILE8605__STATICRR: + return RRRA; + case RRTILE1792__STATICRR: + case RRTILE1801__STATICRR: + case RRTILE1805__STATICRR: + case RRTILE1807__STATICRR: + case RRTILE1808__STATICRR: + case RRTILE1812__STATICRR: + case RRTILE1821__STATICRR: + case RRTILE1826__STATICRR: + case RRTILE1850__STATICRR: + case RRTILE1851__STATICRR: + case RRTILE1856__STATICRR: + case RRTILE1877__STATICRR: + case RRTILE1938__STATICRR: + case RRTILE1942__STATICRR: + case RRTILE1944__STATICRR: + case RRTILE1945__STATICRR: + case RRTILE1951__STATICRR: + case RRTILE1961__STATICRR: + case RRTILE1964__STATICRR: + case RRTILE1985__STATICRR: + case RRTILE1995__STATICRR: + case RRTILE2022__STATICRR: + case RRTILE2052__STATICRR: + case RRTILE2053__STATICRR: + case RRTILE2060__STATICRR: + case RRTILE2074__STATICRR: + case RRTILE2132__STATICRR: + case RRTILE2136__STATICRR: + case RRTILE2139__STATICRR: + case RRTILE2150__STATICRR: + case RRTILE2178__STATICRR: + case RRTILE2186__STATICRR: + case RRTILE2319__STATICRR: + case RRTILE2321__STATICRR: + case RRTILE2326__STATICRR: + case RRTILE2329__STATICRR: + case RRTILE2578__STATICRR: + case RRTILE2581__STATICRR: + case RRTILE2610__STATICRR: + case RRTILE2613__STATICRR: + case RRTILE2621__STATICRR: + case RRTILE2622__STATICRR: + case RRTILE2676__STATICRR: + case RRTILE2732__STATICRR: + case RRTILE2831__STATICRR: + case RRTILE2832__STATICRR: + case RRTILE2842__STATICRR: + case RRTILE2940__STATICRR: + case RRTILE2970__STATICRR: + case RRTILE3083__STATICRR: + case RRTILE3100__STATICRR: + case RRTILE3155__STATICRR: + case RRTILE3195__STATICRR: + case RRTILE3232__STATICRR: + case RRTILE3600__STATICRR: + case RRTILE3631__STATICRR: + case RRTILE3635__STATICRR: + case RRTILE3637__STATICRR: + case RRTILE3643__STATICRR: + case RRTILE3647__STATICRR: + case RRTILE3652__STATICRR: + case RRTILE3653__STATICRR: + case RRTILE3671__STATICRR: + case RRTILE3673__STATICRR: + case RRTILE3684__STATICRR: + case RRTILE3708__STATICRR: + case RRTILE3714__STATICRR: + case RRTILE3716__STATICRR: + case RRTILE3723__STATICRR: + case RRTILE3725__STATICRR: + case RRTILE3737__STATICRR: + case RRTILE3754__STATICRR: + case RRTILE3762__STATICRR: + case RRTILE3763__STATICRR: + case RRTILE3764__STATICRR: + case RRTILE3765__STATICRR: + case RRTILE3767__STATICRR: + case RRTILE3793__STATICRR: + case RRTILE3814__STATICRR: + case RRTILE3815__STATICRR: + case RRTILE3819__STATICRR: + case RRTILE3827__STATICRR: + case RRTILE3837__STATICRR: + return 1; + } + return 0; +} + +int isanunderoperator(int lotag) +{ + switch (lotag & 0xff) + { + case ST_22_SPLITTING_DOOR: + if (RR) return 0; + fallthrough__; + case ST_15_WARP_ELEVATOR: + case ST_16_PLATFORM_DOWN: + case ST_17_PLATFORM_UP: + case ST_18_ELEVATOR_DOWN: + case ST_19_ELEVATOR_UP: + case ST_26_SPLITTING_ST_DOOR: + return 1; + } + return 0; +} + +int isanearoperator(int lotag) +{ + switch (lotag & 0xff) + { + case 41: + if (!RR) return 0; + fallthrough__; + case ST_9_SLIDING_ST_DOOR: + case ST_15_WARP_ELEVATOR: + case ST_16_PLATFORM_DOWN: + case ST_17_PLATFORM_UP: + case ST_18_ELEVATOR_DOWN: + case ST_19_ELEVATOR_UP: + case ST_20_CEILING_DOOR: + case ST_21_FLOOR_DOOR: + case ST_22_SPLITTING_DOOR: + case ST_23_SWINGING_DOOR: + case ST_25_SLIDING_DOOR: + case ST_26_SPLITTING_ST_DOOR: + case ST_29_TEETH_DOOR: + return 1; + } + return 0; +} + +static inline int32_t A_FP_ManhattanDist(const DukePlayer_t *pPlayer, const spritetype *pSprite) +{ + return klabs(pPlayer->opos.x - pSprite->x) + + klabs(pPlayer->opos.y - pSprite->y) + + ((klabs(pPlayer->opos.z - pSprite->z + (28 << 8))) >> 4); +} + +int __fastcall A_FindPlayer(const spritetype *pSprite, int32_t *dist) +{ + if (!g_netServer && ud.multimode < 2) + { + DukePlayer_t *const pPlayer = g_player[myconnectindex].ps; + + if (dist) + *dist = A_FP_ManhattanDist(pPlayer, pSprite); + + return myconnectindex; + } + + int closestPlayer = 0; + int32_t closestPlayerDist = INT32_MAX; + + for (bssize_t TRAVERSE_CONNECT(j)) + { + DukePlayer_t *const pPlayer = g_player[j].ps; + int32_t playerDist = A_FP_ManhattanDist(pPlayer, pSprite); + + if (playerDist < closestPlayerDist && sprite[pPlayer->i].extra > 0) + { + closestPlayer = j; + closestPlayerDist = playerDist; + } + } + + if (dist) + *dist = closestPlayerDist; + + return closestPlayer; +} + +void G_DoSectorAnimations(void) +{ + for (bssize_t animNum=g_animateCnt-1; animNum>=0; animNum--) + { + int animPos = *g_animatePtr[animNum]; + int const animVel = g_animateVel[animNum] * TICSPERFRAME; + int const animSect = g_animateSect[animNum]; + + if (animPos == g_animateGoal[animNum]) + { + G_StopInterpolation(g_animatePtr[animNum]); + + g_animateCnt--; + + g_animatePtr[animNum] = g_animatePtr[g_animateCnt]; + g_animateGoal[animNum] = g_animateGoal[g_animateCnt]; + g_animateVel[animNum] = g_animateVel[g_animateCnt]; + g_animateSect[animNum] = g_animateSect[g_animateCnt]; + + if ((sector[g_animateSect[animNum]].lotag == ST_18_ELEVATOR_DOWN || sector[g_animateSect[animNum]].lotag == ST_19_ELEVATOR_UP) + && (g_animatePtr[animNum] == §or[g_animateSect[animNum]].ceilingz)) + continue; + + if ((sector[animSect].lotag&0xff) != ST_22_SPLITTING_DOOR) + A_CallSound(animSect,-1); + + continue; + } + + animPos = (animVel > 0) ? min(animPos + animVel, g_animateGoal[animNum]) + : max(animPos + animVel, g_animateGoal[animNum]); + + if (g_animatePtr[animNum] == §or[g_animateSect[animNum]].floorz) + { + for (bssize_t TRAVERSE_CONNECT(playerNum)) + { + if ((g_player[playerNum].ps->cursectnum == animSect) + && ((sector[animSect].floorz - g_player[playerNum].ps->pos.z) < (64 << 8)) + && (sprite[g_player[playerNum].ps->i].owner >= 0)) + { + g_player[playerNum].ps->pos.z += animVel; + g_player[playerNum].ps->vel.z = 0; + /* + if (p == myconnectindex) + { + my.z += v; + myvel.z = 0; + } + */ + } + } + + for (bssize_t j=headspritesect[animSect]; j>=0; j=nextspritesect[j]) + { + if (sprite[j].statnum != STAT_EFFECTOR) + { + actor[j].bpos.z = sprite[j].z; + sprite[j].z += animVel; + actor[j].floorz = sector[animSect].floorz+animVel; + } + } + } + + *g_animatePtr[animNum] = animPos; + } +} + +int GetAnimationGoal(const int32_t *animPtr) +{ + for (bssize_t i = 0; i < g_animateCnt; i++) + if (animPtr == g_animatePtr[i]) + return i; + return -1; +} + +int SetAnimation(int sectNum, int32_t *animPtr, int goalVal, int animVel) +{ + if (g_animateCnt >= MAXANIMATES) + return -1; + + int animNum = g_animateCnt; + + for (bssize_t i = 0; i < g_animateCnt; i++) + { + if (animPtr == g_animatePtr[i]) + { + animNum = i; + break; + } + } + + g_animateSect[animNum] = sectNum; + g_animatePtr[animNum] = animPtr; + g_animateGoal[animNum] = goalVal; + g_animateVel[animNum] = (goalVal >= *animPtr) ? animVel : -animVel; + + if (animNum == g_animateCnt) + g_animateCnt++; + + G_SetInterpolation(animPtr); + + return animNum; +} + +static void G_SetupCamTile(int spriteNum, int tileNum, int smoothRatio) +{ + vec3_t const camera = G_GetCameraPosition(spriteNum, smoothRatio); + int const saveMirror = display_mirror; + + renderSetTarget(tileNum, tilesiz[tileNum].y, tilesiz[tileNum].x); + + yax_preparedrawrooms(); + drawrooms(camera.x, camera.y, camera.z, SA(spriteNum), 100 + sprite[spriteNum].shade, SECT(spriteNum)); + yax_drawrooms(G_DoSpriteAnimations, SECT(spriteNum), 0, smoothRatio); + + display_mirror = 3; + G_DoSpriteAnimations(camera.x, camera.y, camera.z, SA(spriteNum), smoothRatio); + display_mirror = saveMirror; + renderDrawMasks(); + + renderRestoreTarget(); +} + +void G_AnimateCamSprite(int smoothRatio) +{ +#ifdef DEBUG_VALGRIND_NO_SMC + return; +#endif + + if (g_curViewscreen < 0) + return; + + int const spriteNum = g_curViewscreen; + + if (totalclock >= T1(spriteNum) + ud.camera_time) + { + DukePlayer_t const *const pPlayer = g_player[screenpeek].ps; + + if (pPlayer->newowner >= 0) + OW(spriteNum) = pPlayer->newowner; + + if (OW(spriteNum) >= 0 && dist(&sprite[pPlayer->i], &sprite[spriteNum]) < VIEWSCREEN_ACTIVE_DISTANCE) + { + int const viewscrTile = TILE_VIEWSCR; + TileFiles.MakeCanvas(viewscrTile, tilesiz[PN(spriteNum)].x, tilesiz[PN(spriteNum)].y); + + G_SetupCamTile(OW(spriteNum), viewscrTile, smoothRatio); +#ifdef POLYMER + // Force texture update on viewscreen sprite in Polymer! + if (videoGetRenderMode() == REND_POLYMER) + polymer_invalidatesprite(spriteNum); +#endif + } + + T1(spriteNum) = (int32_t) totalclock; + } +} + +void G_AnimateWalls(void) +{ + if (RRRA && g_player[screenpeek].ps->sea_sick_stat == 1) + { + for (bssize_t i = 0; i < MAXWALLS; i++) + { + if (wall[i].picnum == RRTILE7873 || wall[i].picnum == RRTILE7870) + wall[i].xpanning += 6; + } + } + for (bssize_t animwallNum = 0; animwallNum < g_animWallCnt; animwallNum++) + { + int const wallNum = animwall[animwallNum].wallnum; + + switch (DYNAMICTILEMAP(wall[wallNum].picnum)) + { + case SCREENBREAK14__STATIC: + case SCREENBREAK15__STATIC: + case SCREENBREAK16__STATIC: + case SCREENBREAK17__STATIC: + case SCREENBREAK18__STATIC: + case SCREENBREAK19__STATIC: + if (RR) continue; + fallthrough__; + case SCREENBREAK1__STATIC: + case SCREENBREAK2__STATIC: + case SCREENBREAK3__STATIC: + case SCREENBREAK4__STATIC: + case SCREENBREAK5__STATIC: + + case SCREENBREAK9__STATIC: + case SCREENBREAK10__STATIC: + case SCREENBREAK11__STATIC: + case SCREENBREAK12__STATIC: + case SCREENBREAK13__STATIC: + if ((krand2()&255) < 16) + { + animwall[animwallNum].tag = wall[wallNum].picnum; + wall[wallNum].picnum = SCREENBREAK6; + } + continue; + + case SCREENBREAK6__STATIC: + case SCREENBREAK7__STATIC: + case SCREENBREAK8__STATIC: + if (animwall[animwallNum].tag >= 0 && (RR || (wall[wallNum].extra != FEMPIC2 && wall[wallNum].extra != FEMPIC3))) + wall[wallNum].picnum = animwall[animwallNum].tag; + else + { + wall[wallNum].picnum++; + if (wall[wallNum].picnum == (SCREENBREAK6+3)) + wall[wallNum].picnum = SCREENBREAK6; + } + continue; + } + + if ((wall[wallNum].cstat&16) && G_GetForcefieldPicnum(wallNum)==W_FORCEFIELD) + { + int const wallTag = animwall[animwallNum].tag; + + if (wall[wallNum].cstat&254) + { + wall[wallNum].xpanning -= wallTag>>10; // sintable[(t+512)&2047]>>12; + wall[wallNum].ypanning -= wallTag>>10; // sintable[t&2047]>>12; + + if (wall[wallNum].extra == 1) + { + wall[wallNum].extra = 0; + animwall[animwallNum].tag = 0; + } + else animwall[animwallNum].tag += 128; + + if (animwall[animwallNum].tag < (128 << 4)) + { + wall[wallNum].overpicnum = (animwall[animwallNum].tag & 128) ? W_FORCEFIELD : W_FORCEFIELD + 1; + } + else + { + if ((krand2()&255) < 32) + animwall[animwallNum].tag = 128<<(krand2()&3); + else wall[wallNum].overpicnum = W_FORCEFIELD+1; + } + } + } + } +} + +int G_ActivateWarpElevators(int spriteNum, int warpDir) +{ + bssize_t i; + int const sectNum = sprite[spriteNum].sectnum; + + for (SPRITES_OF(STAT_EFFECTOR, i)) + if ((SLT(i) == SE_17_WARP_ELEVATOR || (RRRA && SLT(i) == 18)) && SHT(i) == sprite[spriteNum].hitag) + { + if (klabs(sector[sectNum].floorz - actor[spriteNum].t_data[2]) > SP(i) || + sector[SECT(i)].hitag == sector[sectNum].hitag - warpDir) + break; + } + + if (i == -1) + return 1; // No find + + A_PlaySound(warpDir ? ELEVATOR_ON : ELEVATOR_OFF, spriteNum); + + for (SPRITES_OF(STAT_EFFECTOR, i)) + if ((SLT(i) == SE_17_WARP_ELEVATOR || (RRRA && SLT(i) == 18)) && SHT(i) == sprite[spriteNum].hitag) + T1(i) = T2(i) = warpDir; //Make all check warp + + return 0; +} + +void G_OperateSectors(int sectNum, int spriteNum) +{ + int32_t j=0; + int32_t i; + sectortype *const pSector = §or[sectNum]; + + switch (pSector->lotag & (uint16_t)~49152u) + { + case 41: + if (!RR) break; + for (bsize_t i = 0; i < g_jailDoorCnt; i++) + { + if (g_jailDoorSecHitag[i] == pSector->hitag) + { + if (g_jailDoorOpen[i] == 0) + { + g_jailDoorOpen[i] = 1; + g_jailDoorDrag[i] = g_jailDoorDist[i]; + if (!RRRA || g_jailDoorSound[i] != 0) + A_CallSound2(g_jailDoorSound[i], screenpeek); + } + if (g_jailDoorOpen[i] == 2) + { + g_jailDoorOpen[i] = 3; + g_jailDoorDrag[i] = g_jailDoorDist[i]; + if (!RRRA || g_jailDoorSound[i] != 0) + A_CallSound2(g_jailDoorSound[i], screenpeek); + } + } + } + break; + case 7: + { + if (!RR) break; + int const startwall = pSector->wallptr; + int const endwall = startwall + pSector->wallnum; + for (bssize_t j = startwall; j < endwall; j++) + { + SetAnimation(sectNum, &wall[j].x, wall[j].x + 1024, 4); + SetAnimation(sectNum, &wall[wall[j].nextwall].x, wall[wall[j].nextwall].x + 1024, 4); + } + break; + } + case ST_30_ROTATE_RISE_BRIDGE: + j = sector[sectNum].hitag; + + if (E_SpriteIsValid(j)) + { + if (actor[j].tempang == 0 || actor[j].tempang == 256) + A_CallSound(sectNum,spriteNum); + sprite[j].extra = (sprite[j].extra == 1) ? 3 : 1; + } + break; + + case ST_31_TWO_WAY_TRAIN: + j = sector[sectNum].hitag; + + if (E_SpriteIsValid(j)) + { + if (actor[j].t_data[4] == 0) + actor[j].t_data[4] = 1; + + A_CallSound(sectNum,spriteNum); + } + break; + + case ST_26_SPLITTING_ST_DOOR: //The split doors + if (GetAnimationGoal(&pSector->ceilingz) == -1) //if the door has stopped + { + g_haltSoundHack = 1; + pSector->lotag &= 0xFF00u; + pSector->lotag |= ST_22_SPLITTING_DOOR; + G_OperateSectors(sectNum,spriteNum); + pSector->lotag &= 0xFF00u; + pSector->lotag |= ST_9_SLIDING_ST_DOOR; + G_OperateSectors(sectNum,spriteNum); + pSector->lotag &= 0xFF00u; + pSector->lotag |= ST_26_SPLITTING_ST_DOOR; + } + return; + + case ST_9_SLIDING_ST_DOOR: + { + int const startWall = pSector->wallptr; + int const endWall = startWall + pSector->wallnum - 1; + int const doorSpeed = pSector->extra >> 4; + + //first find center point by averaging all points + + vec2_t vect = { 0, 0 }; + + for (i = startWall; i <= endWall; i++) + { + vect.x += wall[i].x; + vect.y += wall[i].y; + } + + vect.x = tabledivide32_noinline(vect.x, (endWall-startWall+1)); + vect.y = tabledivide32_noinline(vect.y, (endWall-startWall+1)); + + //find any points with either same x or same y coordinate + // as center (dax, day) - should be 2 points found. + + int wallfind[2] = { -1, -1 }; + + for (i = startWall; i <= endWall; i++) + { + if (wall[i].x == vect.x || wall[i].y == vect.y) + { + if (wallfind[0] == -1) + wallfind[0] = i; + else + wallfind[1] = i; + } + } + + if (wallfind[1] == -1) + return; + + for (j=0; j<2; j++) + { + int const foundWall = wallfind[j]; + + i = foundWall - 1; + + if (i < startWall) + i = endWall; + + vec2_t vect2 = { ((wall[i].x + wall[wall[foundWall].point2].x) >> 1) - wall[foundWall].x, + ((wall[i].y + wall[wall[foundWall].point2].y) >> 1) - wall[foundWall].y }; + + if (wall[foundWall].x == vect.x && wall[foundWall].y == vect.y) + { + //find what direction door should open by averaging the + // 2 neighboring points of wallfind[0] & wallfind[1]. + if (vect2.x != 0) + { + vect2.x = wall[wall[wall[foundWall].point2].point2].x; + vect2.x -= wall[wall[foundWall].point2].x; + SetAnimation(sectNum, &wall[foundWall].x, wall[foundWall].x + vect2.x, doorSpeed); + SetAnimation(sectNum, &wall[i].x, wall[i].x + vect2.x, doorSpeed); + SetAnimation(sectNum, &wall[wall[foundWall].point2].x, wall[wall[foundWall].point2].x + vect2.x, doorSpeed); + A_CallSound(sectNum, spriteNum); + } + else if (vect2.y != 0) + { + vect2.y = wall[wall[wall[foundWall].point2].point2].y; + vect2.y -= wall[wall[foundWall].point2].y; + SetAnimation(sectNum, &wall[foundWall].y, wall[foundWall].y + vect2.y, doorSpeed); + SetAnimation(sectNum, &wall[i].y, wall[i].y + vect2.y, doorSpeed); + SetAnimation(sectNum, &wall[wall[foundWall].point2].y, wall[wall[foundWall].point2].y + vect2.y, doorSpeed); + A_CallSound(sectNum, spriteNum); + } + } + else + { + if (vect2.x != 0) + { + SetAnimation(sectNum, &wall[foundWall].x, vect.x, doorSpeed); + SetAnimation(sectNum, &wall[i].x, vect.x + vect2.x, doorSpeed); + SetAnimation(sectNum, &wall[wall[foundWall].point2].x, vect.x + vect2.x, doorSpeed); + A_CallSound(sectNum, spriteNum); + } + else if (vect2.y != 0) + { + SetAnimation(sectNum, &wall[foundWall].y, vect.y, doorSpeed); + SetAnimation(sectNum, &wall[i].y, vect.y + vect2.y, doorSpeed); + SetAnimation(sectNum, &wall[wall[foundWall].point2].y, vect.y + vect2.y, doorSpeed); + A_CallSound(sectNum, spriteNum); + } + } + } + } + return; + + case ST_15_WARP_ELEVATOR://Warping elevators + + if (sprite[spriteNum].picnum != APLAYER) + return; + + for (SPRITES_OF_SECT(sectNum, i)) + if (PN(i)==SECTOREFFECTOR && SLT(i) == SE_17_WARP_ELEVATOR) + break; + + if (i < 0) + return; + + if (sprite[spriteNum].sectnum == sectNum) + { + if (G_ActivateWarpElevators(i,-1)) + G_ActivateWarpElevators(i,1); + else if (G_ActivateWarpElevators(i,1)) + G_ActivateWarpElevators(i,-1); + } + else + { + if (pSector->floorz > SZ(i)) + G_ActivateWarpElevators(i,-1); + else + G_ActivateWarpElevators(i,1); + } + + return; + + case ST_16_PLATFORM_DOWN: + case ST_17_PLATFORM_UP: + + i = GetAnimationGoal(&pSector->floorz); + + if (i == -1) + { + i = nextsectorneighborz(sectNum,pSector->floorz,1,1); + if (i == -1) + { + i = nextsectorneighborz(sectNum,pSector->floorz,1,-1); + if (i == -1) return; + j = sector[i].floorz; + SetAnimation(sectNum,&pSector->floorz,j,pSector->extra); + } + else + { + j = sector[i].floorz; + SetAnimation(sectNum,&pSector->floorz,j,pSector->extra); + } + A_CallSound(sectNum,spriteNum); + } + + return; + + case ST_18_ELEVATOR_DOWN: + case ST_19_ELEVATOR_UP: + + i = GetAnimationGoal(&pSector->floorz); + + if (i==-1) + { + i = nextsectorneighborz(sectNum, pSector->floorz, 1, -1); + + if (i == -1) + i = nextsectorneighborz(sectNum, pSector->floorz, 1, 1); + + if (i == -1) + return; + + j = sector[i].floorz; + + int const sectorExtra = pSector->extra; + int const zDiff = pSector->ceilingz - pSector->floorz; + + SetAnimation(sectNum, &pSector->floorz, j, sectorExtra); + SetAnimation(sectNum, &pSector->ceilingz, j + zDiff, sectorExtra); + A_CallSound(sectNum, spriteNum); + } + return; + + case ST_29_TEETH_DOOR: + + for (SPRITES_OF(STAT_EFFECTOR, i)) + if (SLT(i) == SE_22_TEETH_DOOR && SHT(i) == pSector->hitag) + { + sector[SECT(i)].extra = -sector[SECT(i)].extra; + + T1(i) = sectNum; + T2(i) = 1; + } + + A_CallSound(sectNum, spriteNum); + + pSector->lotag ^= 0x8000u; + + if (pSector->lotag & 0x8000u) + { + j = nextsectorneighborz(sectNum,pSector->ceilingz,-1,-1); + //if (j == -1) j = nextsectorneighborz(sectNum,pSector->ceilingz,1,1); + if (j == -1) + { + Printf("WARNING: ST29: null sector!\n"); + return; + } + j = sector[j].ceilingz; + } + else + { + j = nextsectorneighborz(sectNum,pSector->ceilingz,1,1); + //if (j == -1) j = nextsectorneighborz(sectNum,pSector->ceilingz,-1,-1); + if (j == -1) + { + Printf("WARNING: ST29: null sector!\n"); + return; + } + j = sector[j].floorz; + } + + SetAnimation(sectNum,&pSector->ceilingz,j,pSector->extra); + + return; + + case ST_20_CEILING_DOOR: +REDODOOR: + + if (pSector->lotag & 0x8000u) + { + for (SPRITES_OF_SECT(sectNum, i)) + if (sprite[i].statnum == STAT_EFFECTOR && SLT(i)==SE_9_DOWN_OPEN_DOOR_LIGHTS) + { + j = SZ(i); + break; + } + + if (i==-1) + j = pSector->floorz; + } + else + { + j = nextsectorneighborz(sectNum,pSector->ceilingz,-1,-1); + + if (j >= 0) j = sector[j].ceilingz; + else + { + pSector->lotag |= 32768u; + goto REDODOOR; + } + } + + pSector->lotag ^= 0x8000u; + + SetAnimation(sectNum,&pSector->ceilingz,j,pSector->extra); + A_CallSound(sectNum,spriteNum); + + return; + + case ST_21_FLOOR_DOOR: + i = GetAnimationGoal(&pSector->floorz); + if (i >= 0) + { + if (g_animateGoal[sectNum] == pSector->ceilingz) + g_animateGoal[i] = sector[nextsectorneighborz(sectNum,pSector->ceilingz,1,1)].floorz; + else g_animateGoal[i] = pSector->ceilingz; + } + else + { + if (pSector->ceilingz == pSector->floorz) + j = sector[nextsectorneighborz(sectNum,pSector->ceilingz,1,1)].floorz; + else j = pSector->ceilingz; + + pSector->lotag ^= 0x8000u; + + if (SetAnimation(sectNum,&pSector->floorz,j,pSector->extra) >= 0) + A_CallSound(sectNum,spriteNum); + } + return; + + case ST_22_SPLITTING_DOOR: + + if (pSector->lotag & 0x8000u) + { + int const q = (pSector->ceilingz + pSector->floorz) >> 1; + SetAnimation(sectNum, &pSector->floorz, q, pSector->extra); + SetAnimation(sectNum, &pSector->ceilingz, q, pSector->extra); + } + else + { + int const floorNeighbor = nextsectorneighborz(sectNum, pSector->floorz, 1, 1); + int const ceilingNeighbor = nextsectorneighborz(sectNum, pSector->ceilingz, -1, -1); + + if (floorNeighbor>=0 && ceilingNeighbor>=0) + { + SetAnimation(sectNum, &pSector->floorz, sector[floorNeighbor].floorz, pSector->extra); + SetAnimation(sectNum, &pSector->ceilingz, sector[ceilingNeighbor].ceilingz, pSector->extra); + } + else + { + Printf("WARNING: ST_22_SPLITTING_DOOR: null sector: floor neighbor=%d, ceiling neighbor=%d!\n", + floorNeighbor, ceilingNeighbor); + pSector->lotag ^= 0x8000u; + } + } + + pSector->lotag ^= 0x8000u; + + A_CallSound(sectNum,spriteNum); + + return; + + case ST_23_SWINGING_DOOR: //Swingdoor + { + j = -1; + + for (SPRITES_OF(STAT_EFFECTOR, i)) + if (SLT(i) == SE_11_SWINGING_DOOR && SECT(i) == sectNum && !T5(i)) + { + j = i; + break; + } + + if (i < 0) + return; + + uint16_t const tag = sector[SECT(i)].lotag & 0x8000u; + + if (j >= 0) + { + int soundPlayed = 0; + + for (SPRITES_OF(STAT_EFFECTOR, i)) + { + if (tag == (sector[SECT(i)].lotag & 0x8000u) && SLT(i) == SE_11_SWINGING_DOOR && sprite[j].hitag == SHT(i) && !T5(i)) + { + if (sector[SECT(i)].lotag & 0x8000u) sector[SECT(i)].lotag &= 0x7fff; + else sector[SECT(i)].lotag |= 0x8000u; + + T5(i) = 1; + T4(i) = -T4(i); + + if (!soundPlayed) + { + A_CallSound(sectNum, i); + soundPlayed = 1; + } + } + } + } + } + return; + + case ST_25_SLIDING_DOOR: //Subway type sliding doors + + for (SPRITES_OF(STAT_EFFECTOR, j)) + if (sprite[j].lotag == SE_15_SLIDING_DOOR && sprite[j].sectnum == sectNum) + break; //Found the sectoreffector. + + if (j < 0) + return; + + for (SPRITES_OF(STAT_EFFECTOR, i)) + if (SHT(i)==sprite[j].hitag) + { + if (SLT(i) == SE_15_SLIDING_DOOR) + { + sector[SECT(i)].lotag ^= 0x8000u; // Toggle the open or close + SA(i) += 1024; + + if (T5(i)) + A_CallSound(SECT(i),i); + A_CallSound(SECT(i),i); + + T5(i) = (sector[SECT(i)].lotag & 0x8000u) ? 1 : 2; + } + } + + return; + + case ST_27_STRETCH_BRIDGE: //Extended bridge + + for (SPRITES_OF(STAT_EFFECTOR, j)) + if ((sprite[j].lotag&0xff)==SE_20_STRETCH_BRIDGE && sprite[j].sectnum == sectNum) //Bridge + { + sector[sectNum].lotag ^= 0x8000u; + // Highest bit now set means we're opening. + + actor[j].t_data[0] = (sector[sectNum].lotag & 0x8000u) ? 1 : 2; + A_CallSound(sectNum,spriteNum); + break; + } + + return; + + case ST_28_DROP_FLOOR: + //activate the rest of them + + for (SPRITES_OF_SECT(sectNum, j)) + if (sprite[j].statnum==STAT_EFFECTOR && (sprite[j].lotag&0xff)==SE_21_DROP_FLOOR) + break; + + if (j >= 0) // PK: The matching SE21 might have gone, see SE_21_KILLIT in actors.c + { + j = sprite[j].hitag; + + for (bssize_t SPRITES_OF(STAT_EFFECTOR, l)) + { + if ((sprite[l].lotag&0xff)==SE_21_DROP_FLOOR && !actor[l].t_data[0] && + sprite[l].hitag == j) + actor[l].t_data[0] = 1; + } + + A_CallSound(sectNum,spriteNum); + } + + return; + } +} + +void G_OperateRespawns(int lotag) +{ + for (bssize_t nextSprite, SPRITES_OF_STAT_SAFE(STAT_FX, spriteNum, nextSprite)) + { + spritetype * const pSprite = &sprite[spriteNum]; + + if (pSprite->lotag == lotag && pSprite->picnum == RESPAWN) + { + if (!ud.monsters_off || !A_CheckEnemyTile(pSprite->hitag)) + { + int const j = A_Spawn(spriteNum, TRANSPORTERSTAR); + sprite[j].z -= ZOFFSET5; + + // Just a way to killit (see G_MoveFX(): RESPAWN__STATIC) + pSprite->extra = 66-12; + } + } + if (RRRA && pSprite->lotag == lotag && pSprite->picnum == RRTILE7424) + { + if (!ud.monsters_off) + changespritestat(spriteNum, 119); + } + } +} + +void G_OperateActivators(int lotag, int playerNum) +{ + for (bssize_t spriteNum=g_cyclerCnt-1; spriteNum>=0; spriteNum--) + { + int16_t *const pCycler = &g_cyclers[spriteNum][0]; + + if (pCycler[4] == lotag) + { + pCycler[5] = !pCycler[5]; + sector[pCycler[0]].floorshade = pCycler[3]; + sector[pCycler[0]].ceilingshade = pCycler[3]; + walltype *pWall = &wall[sector[pCycler[0]].wallptr]; + + for (bsize_t j = sector[pCycler[0]].wallnum; j > 0; j--, pWall++) + pWall->shade = pCycler[3]; + } + } + + int soundPlayed = -1; + + for (bssize_t nextSprite, SPRITES_OF_STAT_SAFE(STAT_ACTIVATOR, spriteNum, nextSprite)) + { + if (sprite[spriteNum].lotag == lotag) + { + if (sprite[spriteNum].picnum == ACTIVATORLOCKED) + { + sector[SECT(spriteNum)].lotag ^= 16384; + + if (playerNum >= 0 && playerNum < ud.multimode) + P_DoQuote((sector[SECT(spriteNum)].lotag & 16384) ? QUOTE_LOCKED : QUOTE_UNLOCKED, g_player[playerNum].ps); + } + else + { + switch (SHT(spriteNum)) + { + case 1: + if (sector[SECT(spriteNum)].floorz != sector[SECT(spriteNum)].ceilingz) + continue; + break; + case 2: + if (sector[SECT(spriteNum)].floorz == sector[SECT(spriteNum)].ceilingz) + continue; + break; + } + + // ST_2_UNDERWATER + if (sector[sprite[spriteNum].sectnum].lotag < 3) + { + for (bssize_t SPRITES_OF_SECT(sprite[spriteNum].sectnum, foundSprite)) + { + if (sprite[foundSprite].statnum == STAT_EFFECTOR) + { + switch (sprite[foundSprite].lotag) + { + case SE_18_INCREMENTAL_SECTOR_RISE_FALL: + if (RRRA) break; + fallthrough__; + case SE_36_PROJ_SHOOTER: + case SE_31_FLOOR_RISE_FALL: + case SE_32_CEILING_RISE_FALL: + actor[foundSprite].t_data[0] = 1 - actor[foundSprite].t_data[0]; + A_CallSound(SECT(spriteNum), foundSprite); + break; + } + } + } + } + + if (soundPlayed == -1 && (sector[SECT(spriteNum)].lotag&0xff) == ST_22_SPLITTING_DOOR) + soundPlayed = A_CallSound(SECT(spriteNum),spriteNum); + + G_OperateSectors(SECT(spriteNum),spriteNum); + } + } + } + + G_OperateRespawns(lotag); +} + +void G_OperateMasterSwitches(int lotag) +{ + for (bssize_t SPRITES_OF(STAT_STANDABLE, i)) + if (PN(i) == MASTERSWITCH && SLT(i) == lotag && SP(i) == 0) + SP(i) = 1; +} + +void G_OperateForceFields(int spriteNum, int wallTag) +{ + for (bssize_t animwallNum = 0; animwallNum < g_animWallCnt; ++animwallNum) + { + int const wallNum = animwall[animwallNum].wallnum; + + if ((wallTag == wall[wallNum].lotag || wallTag == -1) + && ((!RR && G_GetForcefieldPicnum(wallNum) == W_FORCEFIELD) || (wall[wallNum].overpicnum == BIGFORCE))) + { + animwall[animwallNum].tag = 0; + + if (wall[wallNum].cstat) + { + wall[wallNum].cstat = 0; + + if (spriteNum >= 0 && sprite[spriteNum].picnum == SECTOREFFECTOR && sprite[spriteNum].lotag == SE_30_TWO_WAY_TRAIN) + wall[wallNum].lotag = 0; + } + else + wall[wallNum].cstat = FORCEFIELD_CSTAT; + } + } +} + +// List of switches that function like dip (combination lock) switches. +#define DIPSWITCH_LIKE_CASES \ + DIPSWITCH__STATIC: \ + case TECHSWITCH__STATIC: \ + case ALIENSWITCH__STATIC + +// List of access switches. +#define ACCESSSWITCH_CASES \ + ACCESSSWITCH__STATIC: \ + case ACCESSSWITCH2__STATIC + +// List of switches that don't fit the two preceding categories, and are not +// the MULTISWITCH. 13 cases. +#define REST_SWITCH_CASES \ + DIPSWITCH2__STATIC: \ + case DIPSWITCH3__STATIC: \ + case FRANKENSTINESWITCH__STATIC: \ + case HANDSWITCH__STATIC: \ + case LIGHTSWITCH2__STATIC: \ + case LIGHTSWITCH__STATIC: \ + case LOCKSWITCH1__STATIC: \ + case POWERSWITCH1__STATIC: \ + case POWERSWITCH2__STATIC: \ + case PULLSWITCH__STATIC: \ + case SLOTDOOR__STATIC: \ + case SPACEDOORSWITCH__STATIC: \ + case SPACELIGHTSWITCH__STATIC: \ + case RRTILE2697__STATICRR: \ + case RRTILE2707__STATICRR + + +// Returns: +// 0: is not a dipswitch-like switch +// 1: is one, off +// 2: is one, on +static int G_IsLikeDipswitch(int switchPic) +{ + for (bssize_t i=0; i<2; i++) + if (switchPic == DIPSWITCH+i || switchPic == TECHSWITCH+i || switchPic == ALIENSWITCH+i) + return 1+i; + + return 0; +} + +// Get base (unpressed) tile number for switch. +static int G_GetBaseSwitch(int switchPic) +{ + if (switchPic > MULTISWITCH && switchPic <= MULTISWITCH+3) + return MULTISWITCH; + + if (RRRA && switchPic > MULTISWITCH2 && switchPic <= MULTISWITCH2+3) + return MULTISWITCH2; + + if (RR) + { + if (switchPic == NUKEBUTTON+1 || switchPic == RRTILE2697+1 || switchPic == RRTILE2707+1) + return switchPic-1; + } + + return ((RR && (switchPic == NUKEBUTTON+1 || switchPic == RRTILE2697+1 || switchPic == RRTILE2707+1)) || + switchPic == DIPSWITCH + 1 || switchPic == DIPSWITCH2 + 1 || switchPic == DIPSWITCH3 + 1 || + switchPic == TECHSWITCH + 1 || switchPic == ALIENSWITCH + 1 || switchPic == PULLSWITCH + 1 || + switchPic == HANDSWITCH + 1 || switchPic == SLOTDOOR + 1 || switchPic == SPACEDOORSWITCH + 1 || + switchPic == SPACELIGHTSWITCH + 1 || switchPic == LIGHTSWITCH + 1 || switchPic == LIGHTSWITCH2 + 1 || + switchPic == FRANKENSTINESWITCH + 1 || switchPic == POWERSWITCH1 + 1 || switchPic == POWERSWITCH2 + 1 || + switchPic == LOCKSWITCH1 + 1) ? + switchPic-1 : switchPic; +} + +enum { SWITCH_WALL, SWITCH_SPRITE }; + +int P_ActivateSwitch(int playerNum, int wallOrSprite, int switchType) +{ + if (wallOrSprite < 0) + return 0; + + vec3_t davector; + int16_t lotag, hitag; + int16_t nSwitchPicnum; + uint8_t nSwitchPal; + + if (switchType == SWITCH_SPRITE) // A wall sprite + { + if (sprite[wallOrSprite].lotag == 0) + return 0; + + lotag = sprite[wallOrSprite].lotag; + hitag = sprite[wallOrSprite].hitag; + davector = *(vec3_t *)&sprite[wallOrSprite]; + nSwitchPicnum = sprite[wallOrSprite].picnum; + nSwitchPal = sprite[wallOrSprite].pal; + } + else + { + if (wall[wallOrSprite].lotag == 0) + return 0; + + lotag = wall[wallOrSprite].lotag; + hitag = wall[wallOrSprite].hitag; + davector = *(vec3_t *)&wall[wallOrSprite]; + davector.z = g_player[playerNum].ps->pos.z; + nSwitchPicnum = wall[wallOrSprite].picnum; + nSwitchPal = wall[wallOrSprite].pal; + } + + // Printf("P_ActivateSwitch called picnum=%i switchissprite=%i\n",picnum,switchissprite); + + int basePicnum = G_GetBaseSwitch(nSwitchPicnum); + int correctDips = 1; + int numDips = 0; + + switch (DYNAMICTILEMAP(basePicnum)) + { + case DIPSWITCH_LIKE_CASES: + break; + + case ACCESSSWITCH_CASES: + if (g_player[playerNum].ps->access_incs == 0) + { + static const int32_t key_switchpal[3] = { 0, 21, 23 }; + static const int32_t need_key_quote[3] = { QUOTE_NEED_BLUE_KEY, QUOTE_NEED_RED_KEY, QUOTE_NEED_YELLOW_KEY }; + + for (bssize_t nKeyPal = 0; nKeyPal < 3; nKeyPal++) + { + if (nSwitchPal == key_switchpal[nKeyPal]) + { + if ((!RR && (g_player[playerNum].ps->got_access & (1 << nKeyPal))) + || (RR && g_player[playerNum].ps->keys[nKeyPal+1])) + g_player[playerNum].ps->access_incs = 1; + else + { + P_DoQuote(need_key_quote[nKeyPal], g_player[playerNum].ps); + if (RRRA) + { + if (switchType == SWITCH_SPRITE) + A_PlaySound(99, wallOrSprite); + else + A_PlaySound(99, g_player[playerNum].ps->i); + } + } + + break; + } + } + + if (g_player[playerNum].ps->access_incs == 1) + { + if (switchType == SWITCH_WALL) + g_player[playerNum].ps->access_wallnum = wallOrSprite; + else + g_player[playerNum].ps->access_spritenum = wallOrSprite; + } + + return 0; + } + fallthrough__; + case RRTILE2214__STATICRR: + case RRTILE8464__STATICRR: + case RRTILE8660__STATICRR: + case NUKEBUTTON__STATIC: + case MULTISWITCH__STATIC: + case MULTISWITCH2__STATICRR: + case REST_SWITCH_CASES: + if (!RR && nSwitchPicnum == NUKEBUTTON) goto default_case; + if (RR && !RRRA && (nSwitchPicnum == MULTISWITCH2 || nSwitchPicnum == RRTILE8464 || nSwitchPicnum == RRTILE8660)) goto default_case; + if (G_CheckActivatorMotion(lotag)) + return 0; + break; + + default: +default_case: + if (CheckDoorTile(nSwitchPicnum) == 0) + return 0; + break; + } + + for (bssize_t SPRITES_OF(STAT_DEFAULT, spriteNum)) + { + if (lotag == SLT(spriteNum)) + { + // Put the tile number into a variable so later switches don't + // trigger on the result of changes: + int const spritePic = PN(spriteNum); + + if (spritePic >= MULTISWITCH && spritePic <= MULTISWITCH+3) + { + sprite[spriteNum].picnum++; + if (sprite[spriteNum].picnum > MULTISWITCH+3) + sprite[spriteNum].picnum = MULTISWITCH; + } + + if (RRRA && spritePic >= MULTISWITCH2 && spritePic <= MULTISWITCH2+3) + { + sprite[spriteNum].picnum++; + if (sprite[spriteNum].picnum > MULTISWITCH2+3) + sprite[spriteNum].picnum = MULTISWITCH2; + } + + switch (DYNAMICTILEMAP(spritePic)) + { + case DIPSWITCH_LIKE_CASES: + if (switchType == SWITCH_SPRITE && wallOrSprite == spriteNum) + PN(spriteNum)++; + else if (SHT(spriteNum) == 0) + correctDips++; + numDips++; + break; + + case RRTILE2214__STATICRR: + if (ud.level_number > 6) + ud.level_number = 0; + sprite[spriteNum].picnum++; + break; + + case ACCESSSWITCH_CASES: + case REST_SWITCH_CASES: + case NUKEBUTTON__STATIC: + case RRTILE8660__STATICRR: + if (!RR && spritePic == NUKEBUTTON) + break; + if (RR && !RRRA && spritePic == RRTILE8660) + break; + if (RR) + { + if (PN(spriteNum) == DIPSWITCH3 && SHT(spriteNum) == 999) + { + int j = headspritestat[107]; + while (j >= 0) + { + int const nextj = nextspritestat[j]; + if (sprite[j].picnum == RRTILE3410) + { + sprite[j].picnum++; + sprite[j].hitag = 100; + sprite[j].extra = 0; + A_PlaySound(474, j); + } + else if (sprite[j].picnum == RRTILE295) + A_DeleteSprite(j); + j = nextj; + } + sprite[spriteNum].picnum++; + break; + } + if (PN(spriteNum) == NUKEBUTTON) + g_chickenPlant = 0; + if (RRRA && PN(spriteNum) == RRTILE8660) + { + g_bellTime = 132; + g_bellSprite = spriteNum; + } + } + sprite[spriteNum].picnum++; + break; + + default: + if (spritePic <= 0) // oob safety + break; + + switch (DYNAMICTILEMAP(spritePic - 1)) + { + case DIPSWITCH_LIKE_CASES: + if (switchType == SWITCH_SPRITE && wallOrSprite == spriteNum) + PN(spriteNum)--; + else if (SHT(spriteNum) == 1) + correctDips++; + numDips++; + break; + + case REST_SWITCH_CASES: + case NUKEBUTTON__STATIC: + if (!RR && spritePic == NUKEBUTTON+1) + break; + if (RR && PN(spriteNum) == NUKEBUTTON+1) + g_chickenPlant = 1; + if (!RR || SHT(spriteNum) != 999) + sprite[spriteNum].picnum--; + break; + } + break; + } + } + } + + for (bssize_t wallNum=numwalls-1; wallNum>=0; wallNum--) + { + if (lotag == wall[wallNum].lotag) + { + if (wall[wallNum].picnum >= MULTISWITCH && wall[wallNum].picnum <= MULTISWITCH+3) + { + wall[wallNum].picnum++; + if (wall[wallNum].picnum > MULTISWITCH+3) + wall[wallNum].picnum = MULTISWITCH; + } + if (RRRA && wall[wallNum].picnum >= MULTISWITCH2 && wall[wallNum].picnum <= MULTISWITCH2+3) + { + wall[wallNum].picnum++; + if (wall[wallNum].picnum > MULTISWITCH2+3) + wall[wallNum].picnum = MULTISWITCH2; + } + + switch (DYNAMICTILEMAP(wall[wallNum].picnum)) + { + case DIPSWITCH_LIKE_CASES: + if (switchType == SWITCH_WALL && wallNum == wallOrSprite) + wall[wallNum].picnum++; + else if (wall[wallNum].hitag == 0) + correctDips++; + numDips++; + break; + + case ACCESSSWITCH_CASES: + case REST_SWITCH_CASES: + case RRTILE8464__STATICRR: + case RRTILE8660__STATICRR: + if (RR && !RRRA && wall[wallNum].picnum == RRTILE8660) break; + wall[wallNum].picnum++; + break; + + default: + if (wall[wallNum].picnum <= 0) // oob safety + break; + + switch (DYNAMICTILEMAP(wall[wallNum].picnum - 1)) + { + case DIPSWITCH_LIKE_CASES: + if (switchType == SWITCH_WALL && wallNum == wallOrSprite) + wall[wallNum].picnum--; + else if (wall[wallNum].hitag == 1) + correctDips++; + numDips++; + break; + + case REST_SWITCH_CASES: + wall[wallNum].picnum--; + break; + } + break; + } + } + } + + if ((uint16_t)lotag == UINT16_MAX) + { + P_EndLevel(); + return 1; + } + + basePicnum = G_GetBaseSwitch(nSwitchPicnum); + + switch (DYNAMICTILEMAP(basePicnum)) + { + default: + if (CheckDoorTile(nSwitchPicnum) == 0) + break; + fallthrough__; + case DIPSWITCH_LIKE_CASES: + if (G_IsLikeDipswitch(nSwitchPicnum)) + { + S_PlaySound3D((nSwitchPicnum == ALIENSWITCH || nSwitchPicnum == ALIENSWITCH + 1) ? ALIEN_SWITCH1 : SWITCH_ON, + (switchType == SWITCH_SPRITE) ? wallOrSprite : g_player[playerNum].ps->i, &davector); + + if (numDips != correctDips) + break; + + S_PlaySound3D(END_OF_LEVEL_WARN, g_player[playerNum].ps->i, &davector); + } + fallthrough__; + case ACCESSSWITCH_CASES: + case MULTISWITCH__STATIC: + case MULTISWITCH2__STATICRR: + case REST_SWITCH_CASES: + case RRTILE8464__STATICRR: + case RRTILE8660__STATICRR: + { + if (RR && !RRRA && (basePicnum == MULTISWITCH2 || basePicnum == RRTILE8464 || basePicnum == RRTILE8660)) break; + if (RRRA && switchType == SWITCH_SPRITE) + { + if (nSwitchPicnum == RRTILE8660) + { + g_bellTime = 132; + g_bellSprite = wallOrSprite; + sprite[wallOrSprite].picnum++; + } + else if (nSwitchPicnum == RRTILE8464) + { + sprite[wallOrSprite].picnum = sprite[wallOrSprite].picnum+1; + if (hitag == 10001) + { + if (g_player[playerNum].ps->sea_sick == 0) + g_player[playerNum].ps->sea_sick = 350; + G_OperateActivators(668, playerNum); + G_OperateMasterSwitches(668); + A_PlaySound(328,g_player[playerNum].ps->i); + return 1; + } + } + else if (hitag == 10000) + { + if( nSwitchPicnum == MULTISWITCH || nSwitchPicnum == (MULTISWITCH+1) || + nSwitchPicnum == (MULTISWITCH+2) || nSwitchPicnum == (MULTISWITCH+3) || + nSwitchPicnum == MULTISWITCH2 || nSwitchPicnum == (MULTISWITCH2+1) || + nSwitchPicnum == (MULTISWITCH2+2) || nSwitchPicnum == (MULTISWITCH2+3) ) + { + int var6c[3], var54; + int jpn, jht; + var54 = 0; + S_PlaySound3D(SWITCH_ON, wallOrSprite, &davector); + for (bssize_t j = 0; j < MAXSPRITES; j++) + { + jpn = sprite[j].picnum; + jht = sprite[j].hitag; + if ((jpn == MULTISWITCH || jpn == MULTISWITCH2) && jht == 10000) + { + if (var54 < 3) + { + var6c[var54] = j; + var54++; + } + } + } + if (var54 == 3) + { + S_PlaySound3D(SWITCH_ON, wallOrSprite, &davector); + for (bssize_t j = 0; j < var54; j++) + { + sprite[var6c[j]].hitag = 0; + if (nSwitchPicnum >= MULTISWITCH2) + sprite[var6c[j]].picnum = MULTISWITCH2+3; + else + sprite[var6c[j]].picnum = MULTISWITCH+3; + P_ActivateSwitch(playerNum,var6c[j],1); + } + } + return 1; + } + } + } + if (nSwitchPicnum >= MULTISWITCH && nSwitchPicnum <= MULTISWITCH + 3) + lotag += nSwitchPicnum - MULTISWITCH; + + if (RRRA && nSwitchPicnum >= MULTISWITCH2 && nSwitchPicnum <= MULTISWITCH2 + 3) + lotag += nSwitchPicnum - MULTISWITCH2; + + for (bssize_t SPRITES_OF(STAT_EFFECTOR, spriteNum)) + { + if (sprite[spriteNum].hitag == lotag) + { + switch (sprite[spriteNum].lotag) + { + case 46: + case 47: + case 48: + if (!RRRA) break; + fallthrough__; + case SE_12_LIGHT_SWITCH: + sector[sprite[spriteNum].sectnum].floorpal = 0; + actor[spriteNum].t_data[0]++; + if (actor[spriteNum].t_data[0] == 2) + actor[spriteNum].t_data[0]++; + break; + + case SE_24_CONVEYOR: + case SE_34: + case SE_25_PISTON: + actor[spriteNum].t_data[4] = !actor[spriteNum].t_data[4]; + P_DoQuote(actor[spriteNum].t_data[4] ? QUOTE_DEACTIVATED : QUOTE_ACTIVATED, g_player[playerNum].ps); + break; + + case SE_21_DROP_FLOOR: + P_DoQuote(QUOTE_ACTIVATED, g_player[screenpeek].ps); + break; + } + } + } + + G_OperateActivators(lotag, playerNum); + G_OperateForceFields(g_player[playerNum].ps->i, lotag); + G_OperateMasterSwitches(lotag); + + if (G_IsLikeDipswitch(nSwitchPicnum)) + return 1; + + if (!hitag && CheckDoorTile(nSwitchPicnum) == 0) + S_PlaySound3D(SWITCH_ON, (switchType == SWITCH_SPRITE) ? wallOrSprite : g_player[playerNum].ps->i, &davector); + else if (hitag) + { + auto flags = S_GetUserFlags(hitag); + + if (switchType == SWITCH_SPRITE && (flags & SF_TALK) == 0) + S_PlaySound3D(hitag, wallOrSprite, &davector); + else + A_PlaySound(hitag, g_player[playerNum].ps->i); + } + + return 1; + } + } + + return 0; +} + +void G_ActivateBySector(int sectNum, int spriteNum) +{ + int activatedSectors = 0; + + for (bssize_t SPRITES_OF_SECT(sectNum, i)) + if (PN(i) == ACTIVATOR) + { + G_OperateActivators(SLT(i),-1); + ++activatedSectors; + } + + if ((!RR && !activatedSectors) || (RR && sector[sectNum].lotag != SE_22_TEETH_DOOR)) + G_OperateSectors(sectNum, spriteNum); +} + +static void G_BreakWall(int tileNum, int spriteNum, int wallNum) +{ + wall[wallNum].picnum = tileNum; + A_PlaySound(VENT_BUST,spriteNum); + A_PlaySound(GLASS_HEAVYBREAK,spriteNum); + A_SpawnWallGlass(spriteNum,wallNum,10); +} + +void A_DamageWall(int spriteNum, int wallNum, const vec3_t *vPos, int weaponNum) +{ + int16_t sectNum = -1; + walltype *pWall = &wall[wallNum]; + + if (pWall->overpicnum == MIRROR) + { + switch (DYNAMICTILEMAP(weaponNum)) + { + case RPG2__STATICRR: + if (!RRRA) break; + fallthrough__; + case RADIUSEXPLOSION__STATIC: + case SEENINE__STATIC: + case HEAVYHBOMB__STATIC: + case RPG__STATIC: + case HYDRENT__STATIC: + case OOZFILTER__STATIC: + case EXPLODINGBARREL__STATIC: + A_SpawnWallGlass(spriteNum, wallNum, 70); + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + pWall->cstat &= ~16; + pWall->overpicnum = MIRRORBROKE; + return; + + } + } + + if ((((pWall->cstat & 16) || pWall->overpicnum == BIGFORCE) && pWall->nextsector >= 0) && + (sector[pWall->nextsector].floorz > vPos->z) && + (sector[pWall->nextsector].floorz != sector[pWall->nextsector].ceilingz)) + { + int const switchPic = G_GetForcefieldPicnum(wallNum); + + switch (DYNAMICTILEMAP(switchPic)) + { + case W_FORCEFIELD__STATIC: + pWall->extra = 1; // tell the forces to animate + fallthrough__; + case BIGFORCE__STATIC: + { + if (RR) break; + updatesector(vPos->x, vPos->y, §Num); + if (sectNum < 0) + return; + + int xRepeat = 32; + int yRepeat = 32; + + if (weaponNum == -1) + xRepeat = yRepeat = 8; + else if (weaponNum == CHAINGUN) + { + xRepeat = 16 + sprite[spriteNum].xrepeat; + yRepeat = 16 + sprite[spriteNum].yrepeat; + } + + int const i = A_InsertSprite(sectNum, vPos->x, vPos->y, vPos->z, FORCERIPPLE, -127, xRepeat, yRepeat, 0, + 0, 0, spriteNum, 5); + + CS(i) |= 18 + 128; + SA(i) = getangle(pWall->x - wall[pWall->point2].x, pWall->y - wall[pWall->point2].y) - 512; + + A_PlaySound(SOMETHINGHITFORCE, i); + } + return; + + case FANSPRITE__STATIC: + pWall->overpicnum = FANSPRITEBROKE; + pWall->cstat &= 65535 - 65; + if (pWall->nextwall >= 0) + { + wall[pWall->nextwall].overpicnum = FANSPRITEBROKE; + wall[pWall->nextwall].cstat &= 65535 - 65; + } + A_PlaySound(VENT_BUST, spriteNum); + A_PlaySound(GLASS_BREAKING, spriteNum); + return; + + case RRTILE1973__STATICRR: + updatesector(vPos->x, vPos->y, §Num); + if (sectNum < 0) + return; + pWall->overpicnum = GLASS2; + A_SpawnWallPopcorn(spriteNum, wallNum, 64); + pWall->cstat = 0; + + if (pWall->nextwall >= 0) + wall[pWall->nextwall].cstat = 0; + + { + int const i = A_InsertSprite(sectNum, vPos->x, vPos->y, vPos->z, SECTOREFFECTOR, 0, 0, 0, + fix16_to_int(g_player[0].ps->q16ang), 0, 0, spriteNum, 3); + SLT(i) = 128; + T2(i) = 2; + T3(i) = wallNum; + A_PlaySound(GLASS_BREAKING, i); + } + return; + + case GLASS__STATIC: + updatesector(vPos->x, vPos->y, §Num); + if (sectNum < 0) + return; + pWall->overpicnum = GLASS2; + A_SpawnWallGlass(spriteNum, wallNum, 10); + pWall->cstat = 0; + + if (pWall->nextwall >= 0) + wall[pWall->nextwall].cstat = 0; + + { + int const i = A_InsertSprite(sectNum, vPos->x, vPos->y, vPos->z, SECTOREFFECTOR, 0, 0, 0, + fix16_to_int(g_player[0].ps->q16ang), 0, 0, spriteNum, 3); + SLT(i) = 128; + T2(i) = RR ? 2 : 5; + T3(i) = wallNum; + A_PlaySound(GLASS_BREAKING, i); + } + return; + + case STAINGLASS1__STATIC: + updatesector(vPos->x, vPos->y, §Num); + if (sectNum < 0) + return; + A_SpawnRandomGlass(spriteNum, wallNum, 80); + pWall->cstat = 0; + if (pWall->nextwall >= 0) + wall[pWall->nextwall].cstat = 0; + A_PlaySound(VENT_BUST, spriteNum); + A_PlaySound(GLASS_BREAKING, spriteNum); + return; + } + } + + int wallPicnum = pWall->picnum; + + if (RR && wallPicnum >= RRTILE3643 && wallPicnum <= RRTILE3643+3) + wallPicnum = RRTILE3643; + + switch (DYNAMICTILEMAP(wallPicnum)) + { + case RRTILE3643__STATICRR: + { + int jj = headspritesect[wall[pWall->nextwall].nextsector]; + while (jj != -1) + { + int const nextjj = nextspritesect[jj]; + spritetype *pSprite = &sprite[jj]; + if (pSprite->lotag == 6) + { + for (bssize_t j = 0; j < 16; j++) RANDOMSCRAP(pSprite,jj); + g_spriteExtra[jj]++; + if (g_spriteExtra[jj] == 25) + { + int const startwall = sector[pSprite->sectnum].wallptr; + int const endwall = startwall+sector[pSprite->sectnum].wallnum; + for(bssize_t i=startwall;isectnum].lotag = 0; + S_StopSound(sprite[jj].lotag); + A_PlaySound(400,jj); + A_DeleteSprite(jj); + } + } + jj = nextjj; + } + return; + } + case RRTILE7555__STATICRR: + if (!RRRA) break; + pWall->picnum = SBMOVE; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7441__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5016; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7559__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5017; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7433__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5018; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7557__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5019; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7553__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5020; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7552__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5021; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7568__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5022; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7540__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5023; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7558__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5024; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7554__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5025; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7579__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5026; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7561__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5027; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7580__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5037; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE8227__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5070; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE8503__STATICRR: + if (!RRRA) break; + pWall->picnum = RRTILE5079; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE8567__STATICRR: + case RRTILE8568__STATICRR: + case RRTILE8569__STATICRR: + case RRTILE8570__STATICRR: + case RRTILE8571__STATICRR: + pWall->picnum = RRTILE5082; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE7859__STATICRR: + pWall->picnum = RRTILE5081; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE8496__STATICRR: + pWall->picnum = RRTILE5061; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE8617__STATICRR: + if (numplayers < 2) + { + pWall->picnum = RRTILE8618; + A_PlaySound(47, spriteNum); + } + return; + case RRTILE8620__STATICRR: + pWall->picnum = RRTILE8621; + A_PlaySound(47, spriteNum); + return; + case RRTILE8622__STATICRR: + pWall->picnum = RRTILE8623; + A_PlaySound(495, spriteNum); + return; + case RRTILE7657__STATICRR: + pWall->picnum = RRTILE7659; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + return; + case RRTILE8497__STATICRR: + pWall->picnum = RRTILE5076; + A_PlaySound(495, spriteNum); + return; + case RRTILE7533__STATICRR: + pWall->picnum = RRTILE5035; + A_PlaySound(495, spriteNum); + return; + case COLAMACHINE__STATIC: + case VENDMACHINE__STATIC: + G_BreakWall(pWall->picnum + 2, spriteNum, wallNum); + A_PlaySound(RR ? GLASS_BREAKING : VENT_BUST, spriteNum); + return; + + case FEMPIC2__STATIC: + case FEMPIC3__STATIC: + + case SCREENBREAK1__STATIC: + case SCREENBREAK2__STATIC: + case SCREENBREAK3__STATIC: + case SCREENBREAK4__STATIC: + case SCREENBREAK5__STATIC: + + case SCREENBREAK9__STATIC: + case SCREENBREAK10__STATIC: + case SCREENBREAK11__STATIC: + case SCREENBREAK12__STATIC: + case SCREENBREAK13__STATIC: + case SCREENBREAK14__STATIC: + case SCREENBREAK15__STATIC: + case SCREENBREAK16__STATIC: + case SCREENBREAK17__STATIC: + case SCREENBREAK18__STATIC: + case SCREENBREAK19__STATIC: + case BORNTOBEWILDSCREEN__STATIC: + if (RR) break; + fallthrough__; + case OJ__STATIC: + + case SCREENBREAK6__STATIC: + case SCREENBREAK7__STATIC: + case SCREENBREAK8__STATIC: + A_SpawnWallGlass(spriteNum, wallNum, 30); + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + pWall->picnum = W_SCREENBREAK + (krand2() % (RRRA ? 2: 3)); + return; + + case W_TECHWALL5__STATIC: + case W_TECHWALL6__STATIC: + case W_TECHWALL7__STATIC: + case W_TECHWALL8__STATIC: + case W_TECHWALL9__STATIC: + if (RR) break; + G_BreakWall(pWall->picnum + 1, spriteNum, wallNum); + return; + + case W_MILKSHELF__STATIC: + if (RR) break; + G_BreakWall(W_MILKSHELFBROKE, spriteNum, wallNum); + return; + + case W_TECHWALL10__STATIC: + if (RR) break; + G_BreakWall(W_HITTECHWALL10, spriteNum, wallNum); + return; + + case W_TECHWALL1__STATIC: + case W_TECHWALL11__STATIC: + case W_TECHWALL12__STATIC: + case W_TECHWALL13__STATIC: + case W_TECHWALL14__STATIC: + if (RR) break; + G_BreakWall(W_HITTECHWALL1, spriteNum, wallNum); + return; + + case W_TECHWALL15__STATIC: + if (RR) break; + G_BreakWall(W_HITTECHWALL15, spriteNum, wallNum); + return; + + case W_TECHWALL16__STATIC: + if (RR) break; + G_BreakWall(W_HITTECHWALL16, spriteNum, wallNum); + return; + + case W_TECHWALL2__STATIC: + if (RR) break; + G_BreakWall(W_HITTECHWALL2, spriteNum, wallNum); + return; + + case W_TECHWALL3__STATIC: + if (RR) break; + G_BreakWall(W_HITTECHWALL3, spriteNum, wallNum); + return; + + case W_TECHWALL4__STATIC: + if (RR) break; + G_BreakWall(W_HITTECHWALL4, spriteNum, wallNum); + return; + + case ATM__STATIC: + pWall->picnum = ATMBROKE; + A_SpawnMultiple(spriteNum, MONEY, 1 + (krand2() & 7)); + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + + case WALLLIGHT2__STATIC: + if (RR) break; + fallthrough__; + case WALLLIGHT1__STATIC: + case WALLLIGHT3__STATIC: + case WALLLIGHT4__STATIC: + case TECHLIGHT2__STATIC: + case TECHLIGHT4__STATIC: + case RRTILE1814__STATICRR: + case RRTILE1939__STATICRR: + case RRTILE1986__STATICRR: + case RRTILE1988__STATICRR: + case RRTILE2123__STATICRR: + case RRTILE2125__STATICRR: + case RRTILE2636__STATICRR: + case RRTILE2878__STATICRR: + case RRTILE2898__STATICRR: + case RRTILE3200__STATICRR: + case RRTILE3202__STATICRR: + case RRTILE3204__STATICRR: + case RRTILE3206__STATICRR: + case RRTILE3208__STATICRR: + { + A_PlaySound(rnd(128) ? GLASS_HEAVYBREAK : GLASS_BREAKING, spriteNum); + A_SpawnWallGlass(spriteNum, wallNum, 30); + + if (RR) + { + if (pWall->picnum == RRTILE1814) + pWall->picnum = RRTILE1817; + + if (pWall->picnum == RRTILE1986) + pWall->picnum = RRTILE1987; + + if (pWall->picnum == RRTILE1939) + pWall->picnum = RRTILE2004; + + if (pWall->picnum == RRTILE1988) + pWall->picnum = RRTILE2005; + + if (pWall->picnum == RRTILE2898) + pWall->picnum = RRTILE2899; + + if (pWall->picnum == RRTILE2878) + pWall->picnum = RRTILE2879; + + if (pWall->picnum == RRTILE2123) + pWall->picnum = RRTILE2124; + + if (pWall->picnum == RRTILE2125) + pWall->picnum = RRTILE2126; + + if (pWall->picnum == RRTILE3200) + pWall->picnum = RRTILE3201; + + if (pWall->picnum == RRTILE3202) + pWall->picnum = RRTILE3203; + + if (pWall->picnum == RRTILE3204) + pWall->picnum = RRTILE3205; + + if (pWall->picnum == RRTILE3206) + pWall->picnum = RRTILE3207; + + if (pWall->picnum == RRTILE3208) + pWall->picnum = RRTILE3209; + + if (pWall->picnum == RRTILE2636) + pWall->picnum = RRTILE2637; + } + + if (pWall->picnum == WALLLIGHT1) + pWall->picnum = WALLLIGHTBUST1; + + if (!RR && pWall->picnum == WALLLIGHT2) + pWall->picnum = WALLLIGHTBUST2; + + if (pWall->picnum == WALLLIGHT3) + pWall->picnum = WALLLIGHTBUST3; + + if (pWall->picnum == WALLLIGHT4) + pWall->picnum = WALLLIGHTBUST4; + + if (pWall->picnum == TECHLIGHT2) + pWall->picnum = TECHLIGHTBUST2; + + if (pWall->picnum == TECHLIGHT4) + pWall->picnum = TECHLIGHTBUST4; + + if (pWall->lotag == 0) + return; + + sectNum = pWall->nextsector; + + if (sectNum < 0) + return; + + int darkestWall = 0; + + pWall = &wall[sector[sectNum].wallptr]; + + for (bssize_t i = sector[sectNum].wallnum; i > 0; i--, pWall++) + if (pWall->shade > darkestWall) + darkestWall = pWall->shade; + + int const random = krand2() & 1; + + for (bssize_t SPRITES_OF(STAT_EFFECTOR, i)) + if (SHT(i) == wall[wallNum].lotag && SLT(i) == SE_3_RANDOM_LIGHTS_AFTER_SHOT_OUT) + { + T3(i) = random; + T4(i) = darkestWall; + T5(i) = 1; + } + + break; + } + } +} + +void Sect_DamageCeiling(int const sectNum) +{ + int16_t * const pPicnum = §or[sectNum].ceilingpicnum; + + switch (DYNAMICTILEMAP(*pPicnum)) + { + case RRTILE1939__STATICRR: *pPicnum = RRTILE2004; goto GLASSBREAK_CODE; + case RRTILE1986__STATICRR: *pPicnum = RRTILE1987; goto GLASSBREAK_CODE; + case RRTILE1988__STATICRR: *pPicnum = RRTILE2005; goto GLASSBREAK_CODE; + case RRTILE2123__STATICRR: *pPicnum = RRTILE2124; goto GLASSBREAK_CODE; + case RRTILE2125__STATICRR: *pPicnum = RRTILE2126; goto GLASSBREAK_CODE; + case RRTILE2878__STATICRR: *pPicnum = RRTILE2879; goto GLASSBREAK_CODE; + case RRTILE2898__STATICRR: *pPicnum = RRTILE2899; goto GLASSBREAK_CODE; + case WALLLIGHT1__STATIC: *pPicnum = WALLLIGHTBUST1; goto GLASSBREAK_CODE; + case WALLLIGHT2__STATIC: if (RR) break; *pPicnum = WALLLIGHTBUST2; goto GLASSBREAK_CODE; + case WALLLIGHT3__STATIC: *pPicnum = WALLLIGHTBUST3; goto GLASSBREAK_CODE; + case WALLLIGHT4__STATIC: *pPicnum = WALLLIGHTBUST4; goto GLASSBREAK_CODE; + case TECHLIGHT2__STATIC: *pPicnum = TECHLIGHTBUST2; goto GLASSBREAK_CODE; + case TECHLIGHT4__STATIC: *pPicnum = TECHLIGHTBUST4; + GLASSBREAK_CODE: + A_SpawnCeilingGlass(g_player[myconnectindex].ps->i, sectNum, 10); + A_PlaySound(GLASS_BREAKING, g_player[screenpeek].ps->i); + if (sector[sectNum].hitag == 0) + { + for (bssize_t SPRITES_OF_SECT(sectNum, i)) + { + if (PN(i) == SECTOREFFECTOR && (SLT(i) == SE_12_LIGHT_SWITCH || (RRRA && (SLT(i) == 47 || SLT(i) == 48)))) + { + for (bssize_t SPRITES_OF(STAT_EFFECTOR, j)) + if (sprite[j].hitag == SHT(i)) + actor[j].t_data[3] = 1; + break; + } + } + } + + int j = krand2() & 1; + + for (bssize_t SPRITES_OF(STAT_EFFECTOR, i)) + { + if (SHT(i) == sector[sectNum].hitag && SLT(i) == SE_3_RANDOM_LIGHTS_AFTER_SHOT_OUT) + { + T3(i) = j; + T5(i) = 1; + } + } + } +} + +// hard coded props... :( +void A_DamageObject(int spriteNum, int const dmgSrc) +{ + //if (g_netClient) + // return; + + spriteNum &= (MAXSPRITES-1); + + int spritePicnum = PN(spriteNum); + if (RR) + { + if (spritePicnum == HENSTAND+1) + spritePicnum = HENSTAND; + if (spritePicnum == RRTILE3440+1) + spritePicnum = RRTILE3440; + } + + if (spritePicnum > WATERFOUNTAIN && spritePicnum <= WATERFOUNTAIN+3) + spritePicnum = WATERFOUNTAIN; + + switch (DYNAMICTILEMAP(spritePicnum)) + { + case RRTILE8487__STATICRR: + case RRTILE8489__STATICRR: + if (!RRRA) goto default_case; + A_PlaySound(471, spriteNum); + PN(spriteNum)++; + break; + case RRTILE7638__STATICRR: + case RRTILE7644__STATICRR: + case RRTILE7646__STATICRR: + case RRTILE7650__STATICRR: + case RRTILE7653__STATICRR: + case RRTILE7655__STATICRR: + case RRTILE7691__STATICRR: + case RRTILE7876__STATICRR: + case RRTILE7881__STATICRR: + case RRTILE7883__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum)++; + A_PlaySound(VENT_BUST, spriteNum); + break; + case RRTILE7879__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum)++; + A_PlaySound(495, spriteNum); + A_RadiusDamage(spriteNum, 10, 0, 0, 1, 1); + break; + case RRTILE7648__STATICRR: + case RRTILE7694__STATICRR: + case RRTILE7700__STATICRR: + case RRTILE7702__STATICRR: + case RRTILE7711__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum)++; + A_PlaySound(47, spriteNum); + break; + case RRTILE7636__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) += 3; + A_PlaySound(VENT_BUST, spriteNum); + break; + case RRTILE7875__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) += 3; + A_PlaySound(VENT_BUST, spriteNum); + break; + case RRTILE7640__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) += 2; + A_PlaySound(VENT_BUST, spriteNum); + break; + case RRTILE7595__STATICRR: + case RRTILE7704__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE7705; + A_PlaySound(495, spriteNum); + break; + case RRTILE8579__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5014; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7441__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5016; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7534__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5029; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7545__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5030; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7547__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5031; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7574__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5032; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7575__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5033; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7578__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5034; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7478__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5035; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8525__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5036; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8537__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5062; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8215__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5064; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8216__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5065; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8217__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5066; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8218__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5067; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8220__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5068; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8221__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5069; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8312__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5071; + A_PlaySound(472, spriteNum); + break; + case RRTILE8395__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5072; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8423__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5073; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE3462__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5074; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case UWHIP__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5075; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8608__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5083; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8609__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5084; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8567__STATICRR: + case RRTILE8568__STATICRR: + case RRTILE8569__STATICRR: + case RRTILE8570__STATICRR: + case RRTILE8571__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5082; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8640__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5085; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8611__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5086; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case TECHLIGHTBUST2__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = TECHLIGHTBUST4; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8497__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5076; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8162__STATICRR: + case RRTILE8163__STATICRR: + case RRTILE8164__STATICRR: + case RRTILE8165__STATICRR: + case RRTILE8166__STATICRR: + case RRTILE8167__STATICRR: + case RRTILE8168__STATICRR: + if (!RRRA) goto default_case; + changespritestat(spriteNum, 5); + PN(spriteNum) = RRTILE5063; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8589__STATICRR: + case RRTILE8590__STATICRR: + case RRTILE8591__STATICRR: + case RRTILE8592__STATICRR: + case RRTILE8593__STATICRR: + case RRTILE8594__STATICRR: + case RRTILE8595__STATICRR: + if (!RRRA) goto default_case; + changespritestat(spriteNum, 5); + PN(spriteNum) = RRTILE8588; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE3497__STATICRR: + PN(spriteNum) = RRTILE5076; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE3498__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5077; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE3499__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5078; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8503__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5079; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7901__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5080; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7696__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE7697; + A_PlaySound(47, spriteNum); + break; + case RRTILE7806__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5043; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7885__STATICRR: + case RRTILE7890__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5045; + A_PlaySound(495, spriteNum); + A_RadiusDamage(spriteNum, 10, 0, 0, 1, 1); + break; + case RRTILE7886__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5046; + A_PlaySound(495, spriteNum); + A_RadiusDamage(spriteNum, 10, 0, 0, 1, 1); + break; + case RRTILE7887__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5044; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + A_RadiusDamage(spriteNum, 10, 0, 0, 1, 1); + break; + case RRTILE7900__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5047; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7906__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5048; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7912__STATICRR: + case RRTILE7913__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5049; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8047__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5050; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8596__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE8598; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8059__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5051; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8060__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5052; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8222__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5053; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8223__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5054; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8224__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5055; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8370__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5056; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8371__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5057; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8372__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5058; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8373__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5059; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8396__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5038; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8397__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5039; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8398__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5040; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8399__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5041; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8385__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE8386; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8387__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE8388; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8389__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE8390; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8391__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE8392; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE7553__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5035; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8475__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5075; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8498__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5077; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8499__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5078; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE2445__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE2450; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE2123__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE2124; + A_PlaySound(GLASS_BREAKING, spriteNum); + A_SpawnWallGlass(spriteNum, -1, 10); + break; + case RRTILE3773__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE8651; + A_PlaySound(GLASS_BREAKING, spriteNum); + A_SpawnWallGlass(spriteNum, -1, 10); + break; + case RRTILE7533__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5035; + A_PlaySound(495, spriteNum); + A_RadiusDamage(spriteNum, 10, 0, 0, 1, 1); + break; + case RRTILE8394__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5072; + A_PlaySound(495, spriteNum); + break; + case RRTILE8461__STATICRR: + case RRTILE8462__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE5074; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8679__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE8680; + A_PlaySound(47, spriteNum); + A_RadiusDamage(spriteNum, 10, 0, 0, 1, 1); + if (SLT(spriteNum) != 0) + { + for (bssize_t j = 0; j < MAXSPRITES; j++) + { + if (sprite[j].picnum == RRTILE8679 && sprite[j].pal == 4) + { + if (sprite[j].lotag == SLT(spriteNum)) + sprite[j].picnum = RRTILE8680; + } + } + } + break; + case RRTILE3584__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE8681; + A_PlaySound(495, spriteNum); + A_RadiusDamage(spriteNum, 250, 0, 0, 1, 1); + break; + case RRTILE8682__STATICRR: + if (!RRRA) goto default_case; + PN(spriteNum) = RRTILE8683; + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + break; + case RRTILE8099__STATICRR: + if (!RRRA) goto default_case; + if (SLT(spriteNum) == 5) + { + SLT(spriteNum) = 0; + PN(spriteNum) = RRTILE5087; + A_PlaySound(340, spriteNum); + for (bssize_t j = 0; j < MAXSPRITES; j++) + { + if (sprite[j].picnum == RRTILE8094) + sprite[j].picnum = RRTILE5088; + } + } + break; + case RRTILE2431__STATICRR: + if (!RRRA) goto default_case; + if (sprite[spriteNum].pal != 4) + { + PN(spriteNum) = RRTILE2451; + if (SLT(spriteNum) != 0) + { + for (bssize_t j = 0; j < MAXSPRITES; j++) + { + if (sprite[j].picnum == RRTILE2431 && sprite[j].pal == 4) + { + if (SLT(spriteNum) == sprite[j].lotag) + sprite[j].picnum = RRTILE2451; + } + } + } + } + break; + case RRTILE2443__STATICRR: + if (!RRRA) goto default_case; + if (sprite[spriteNum].pal != 19) + PN(spriteNum) = RRTILE2455; + break; + case RRTILE2455__STATICRR: + if (!RRRA) goto default_case; + A_PlaySound(SQUISHED, spriteNum); + A_DoGuts(spriteNum, RRTILE2465, 3); + deletesprite(spriteNum); + break; + case RRTILE2451__STATICRR: + if (!RRRA) goto default_case; + if (sprite[spriteNum].pal != 4) + { + A_PlaySound(SQUISHED, spriteNum); + if (SLT(spriteNum) != 0) + { + for (bssize_t j = 0; j < MAXSPRITES; j++) + { + if (sprite[j].picnum == RRTILE2451 && sprite[j].pal == 4) + { + if (SLT(spriteNum) == sprite[j].lotag) + { + A_DoGuts(spriteNum, RRTILE2460, 12); + A_DoGuts(spriteNum, RRTILE2465, 3); + sprite[j].xrepeat = 0; + sprite[j].yrepeat = 0; + sprite[spriteNum].xrepeat = 0; + sprite[spriteNum].yrepeat = 0; + } + } + } + } + else + { + A_DoGuts(spriteNum, RRTILE2460, 12); + A_DoGuts(spriteNum, RRTILE2465, 3); + sprite[spriteNum].xrepeat = 0; + sprite[spriteNum].yrepeat = 0; + } + } + break; + case RRTILE2437__STATICRR: + if (!RRRA) goto default_case; + A_PlaySound(439, spriteNum); + break; + case RRTILE3114__STATICRR: + PN(spriteNum) = RRTILE3117; + break; + case RRTILE2876__STATICRR: + PN(spriteNum) = RRTILE2990; + break; + case RRTILE3152__STATICRR: + PN(spriteNum) = RRTILE3218; + break; + case RRTILE3153__STATICRR: + PN(spriteNum) = RRTILE3219; + break; + case RRTILE2030__STATICRR: + PN(spriteNum) = RRTILE2034; + A_PlaySound(GLASS_BREAKING, spriteNum); + A_SpawnWallGlass(spriteNum, -1, 10); + break; + case RRTILE2893__STATICRR: + case RRTILE2915__STATICRR: + case RRTILE3115__STATICRR: + case RRTILE3171__STATICRR: + switch (DYNAMICTILEMAP(PN(spriteNum))) + { + case RRTILE2915__STATICRR: + PN(spriteNum) = RRTILE2977; + break; + case RRTILE2893__STATICRR: + PN(spriteNum) = RRTILE2978; + break; + case RRTILE3115__STATICRR: + PN(spriteNum) = RRTILE3116; + break; + case RRTILE3171__STATICRR: + PN(spriteNum) = RRTILE3216; + break; + } + A_PlaySound(GLASS_BREAKING, spriteNum); + A_SpawnWallGlass(spriteNum, -1, 10); + break; + case RRTILE2156__STATICRR: + case RRTILE2158__STATICRR: + case RRTILE2160__STATICRR: + case RRTILE2175__STATICRR: + PN(spriteNum)++; + A_PlaySound(GLASS_BREAKING, spriteNum); + A_SpawnWallGlass(spriteNum, -1, 10); + break; + case RRTILE2137__STATICRR: + case RRTILE2151__STATICRR: + case RRTILE2152__STATICRR: + A_PlaySound(GLASS_BREAKING, spriteNum); + A_SpawnWallGlass(spriteNum, -1, 10); + PN(spriteNum)++; + for (int k = 0; k < 6; k++) + { + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(), r4 = krand2(); + A_InsertSprite(SECT(spriteNum), SX(spriteNum), SY(spriteNum), SZ(spriteNum) - ZOFFSET3, SCRAP6 + (r4 & 15), -8, 48, 48, r3 & 2047, (r2 & 63) + 64, -(r1 & 4095) - (sprite[spriteNum].zvel >> 2), spriteNum, STAT_MISC); + } + break; + case BOWLINGBALL__STATICRR: + sprite[dmgSrc].xvel = (sprite[spriteNum].xvel >> 1) + (sprite[spriteNum].xvel >> 2); + sprite[dmgSrc].ang -= (krand2() & 16); + A_PlaySound(355, spriteNum); + break; + case OCEANSPRITE1__STATIC: + case OCEANSPRITE2__STATIC: + case OCEANSPRITE3__STATIC: + case OCEANSPRITE4__STATIC: + case OCEANSPRITE5__STATIC: + if (RR) goto default_case; + A_Spawn(spriteNum,SMALLSMOKE); + A_DeleteSprite(spriteNum); + break; + + case QUEBALL__STATIC: + case STRIPEBALL__STATIC: + case RRTILE3440__STATICRR: + case HENSTAND__STATICRR: + if (sprite[dmgSrc].picnum == QUEBALL || sprite[dmgSrc].picnum == STRIPEBALL) + { + sprite[dmgSrc].xvel = (sprite[spriteNum].xvel>>1)+(sprite[spriteNum].xvel>>2); + sprite[dmgSrc].ang -= (SA(spriteNum)<<1)+1024; + SA(spriteNum) = getangle(SX(spriteNum)-sprite[dmgSrc].x,SY(spriteNum)-sprite[dmgSrc].y)-512; + if (S_CheckSoundPlaying(POOLBALLHIT) < 2) + A_PlaySound(POOLBALLHIT, spriteNum); + } + else if (RR && (sprite[dmgSrc].picnum == RRTILE3440 || sprite[dmgSrc].picnum == RRTILE3440+1)) + { + sprite[dmgSrc].xvel = (sprite[spriteNum].xvel>>1)+(sprite[spriteNum].xvel>>2); + sprite[dmgSrc].ang -= ((SA(spriteNum)<<1)+krand2())&64; + SA(spriteNum) = (SA(spriteNum)+krand2())&16; + A_PlaySound(355,spriteNum); + } + else if (RR && (sprite[dmgSrc].picnum == HENSTAND || sprite[dmgSrc].picnum == HENSTAND+1)) + { + sprite[dmgSrc].xvel = (sprite[spriteNum].xvel>>1)+(sprite[spriteNum].xvel>>2); + sprite[dmgSrc].ang -= ((SA(spriteNum)<<1)+krand2())&16; + SA(spriteNum) = (SA(spriteNum)+krand2())&16; + A_PlaySound(355,spriteNum); + } + else + { + if (krand2()&3) + { + sprite[spriteNum].xvel = 164; + sprite[spriteNum].ang = sprite[dmgSrc].ang; + } + else if (!RR) + { + A_SpawnWallGlass(spriteNum,-1,3); + A_DeleteSprite(spriteNum); + } + } + break; + + case CONE__STATIC: + if (RR) goto default_case; + fallthrough__; + case TREE1__STATIC: + case TREE2__STATIC: + case TIRE__STATIC: + case BOX__STATIC: + { + switch (DYNAMICTILEMAP(sprite[dmgSrc].picnum)) + { + case RPG2__STATICRR: + if (!RRRA) break; + fallthrough__; + case OWHIP__STATICRR: + case UWHIP__STATICRR: + case TRIPBOMBSPRITE__STATIC: + case COOLEXPLOSION1__STATIC: + if (!RR) break; + fallthrough__; + case RADIUSEXPLOSION__STATIC: + case RPG__STATIC: + case FIRELASER__STATIC: + case HYDRENT__STATIC: + case HEAVYHBOMB__STATIC: + if (T1(spriteNum) == 0) + { + CS(spriteNum) &= ~257; + T1(spriteNum) = 1; + A_Spawn(spriteNum,BURNING); + } + break; + } + break; + } + + case CACTUS__STATIC: + { + switch (DYNAMICTILEMAP(sprite[dmgSrc].picnum)) + { + case RPG2__STATICRR: + if (!RRRA) break; + fallthrough__; + case OWHIP__STATICRR: + case UWHIP__STATICRR: + case TRIPBOMBSPRITE__STATIC: + case COOLEXPLOSION1__STATIC: + if (!RR) break; + fallthrough__; + case RADIUSEXPLOSION__STATIC: + case RPG__STATIC: + case FIRELASER__STATIC: + case HYDRENT__STATIC: + case HEAVYHBOMB__STATIC: + for (bssize_t k=64; k>0; k--) + { + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(), r4 = krand2(), r5 = krand2(); + int newSprite = + A_InsertSprite(SECT(spriteNum), SX(spriteNum), SY(spriteNum), SZ(spriteNum) - (r5 % (48 << 8)), SCRAP3 + (r4 & 3), -8, 48, 48, + r3 & 2047, (r2 & 63) + 64, -(r1 & 4095) - (sprite[spriteNum].zvel >> 2), spriteNum, 5); + sprite[newSprite].pal = 8; + } + // case CACTUSBROKE: + if (PN(spriteNum) == CACTUS) + PN(spriteNum) = CACTUSBROKE; + CS(spriteNum) &= ~257; + break; + } + break; + } + + case HANGLIGHT__STATIC: + case GENERICPOLE2__STATIC: + if (RR) goto default_case; + for (bssize_t k=6; k>0; k--) + { + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(), r4 = krand2(); + A_InsertSprite(SECT(spriteNum),SX(spriteNum),SY(spriteNum),SZ(spriteNum)-ZOFFSET3,SCRAP1+(r4&15),-8,48,48,r3&2047,(r2&63)+64,-(r1&4095)-(sprite[spriteNum].zvel>>2),spriteNum,5); + } + A_PlaySound(GLASS_HEAVYBREAK,spriteNum); + A_DeleteSprite(spriteNum); + break; + + case FANSPRITE__STATIC: + PN(spriteNum) = FANSPRITEBROKE; + CS(spriteNum) &= (65535-257); + if (!RR && sector[SECT(spriteNum)].floorpicnum == FANSHADOW) + sector[SECT(spriteNum)].floorpicnum = FANSHADOWBROKE; + + A_PlaySound(GLASS_HEAVYBREAK, spriteNum); + + for (bssize_t j=16; j>0; j--) + { + spritetype * const pSprite = &sprite[spriteNum]; + RANDOMSCRAP(pSprite, spriteNum); + } + break; + + case WATERFOUNTAIN__STATIC: + // case WATERFOUNTAIN+1: + // case WATERFOUNTAIN+2: + if (!RR) + PN(spriteNum) = WATERFOUNTAINBROKE; + A_Spawn(spriteNum,TOILETWATER); + break; + + case SATELITE__STATIC: + case FUELPOD__STATIC: + case SOLARPANNEL__STATIC: + case ANTENNA__STATIC: + if (sprite[dmgSrc].extra != G_DefaultActorHealth(SHOTSPARK1)) + { + for (bssize_t j=0; j<15; j++) + { + int32_t const r1 = krand2(), r2 = krand2(), r3 = krand2(), r4 = krand2(); + A_InsertSprite(SECT(spriteNum),SX(spriteNum),SY(spriteNum),sector[SECT(spriteNum)].floorz-ZOFFSET4-(j<<9),SCRAP1+(r4&15),-8,64,64, + r3&2047,(r2&127)+64,-(r1&511)-256,spriteNum,5); + } + A_Spawn(spriteNum,EXPLOSION2); + A_DeleteSprite(spriteNum); + } + break; + + case WATERFOUNTAINBROKE__STATIC: + if (RR) goto default_case; + fallthrough__; + case BOTTLE1__STATIC: + case BOTTLE2__STATIC: + case BOTTLE3__STATIC: + case BOTTLE4__STATIC: + case BOTTLE5__STATIC: + case BOTTLE6__STATIC: + case BOTTLE8__STATIC: + case BOTTLE10__STATIC: + case BOTTLE11__STATIC: + case BOTTLE12__STATIC: + case BOTTLE13__STATIC: + case BOTTLE14__STATIC: + case BOTTLE15__STATIC: + case BOTTLE16__STATIC: + case BOTTLE17__STATIC: + case BOTTLE18__STATIC: + case BOTTLE19__STATIC: + case DOMELITE__STATIC: + case SUSHIPLATE1__STATIC: + case SUSHIPLATE2__STATIC: + case SUSHIPLATE3__STATIC: + case SUSHIPLATE4__STATIC: + case SUSHIPLATE5__STATIC: + case WAITTOBESEATED__STATIC: + case VASE__STATIC: + case STATUEFLASH__STATIC: + case STATUE__STATIC: + case RRTILE1824__STATICRR: + if (RR && !RRRA && PN(spriteNum) == RRTILE1824) goto default_case; + if (PN(spriteNum) == BOTTLE10) + A_SpawnMultiple(spriteNum, MONEY, 4+(krand2()&3)); + else if (PN(spriteNum) == STATUE || PN(spriteNum) == STATUEFLASH) + { + A_SpawnRandomGlass(spriteNum,-1,40); + A_PlaySound(GLASS_HEAVYBREAK,spriteNum); + } + else if (PN(spriteNum) == VASE) + A_SpawnWallGlass(spriteNum,-1,40); + + A_PlaySound(GLASS_BREAKING,spriteNum); + SA(spriteNum) = krand2()&2047; + A_SpawnWallGlass(spriteNum,-1,8); + A_DeleteSprite(spriteNum); + break; + + case FETUS__STATIC: + if (RR) goto default_case; + PN(spriteNum) = FETUSBROKE; + A_PlaySound(GLASS_BREAKING,spriteNum); + A_SpawnWallGlass(spriteNum,-1,10); + break; + + case FETUSBROKE__STATIC: + if (RR) goto default_case; + for (bssize_t j=48; j>0; j--) + { + A_Shoot(spriteNum,BLOODSPLAT1); + SA(spriteNum) += 333; + } + A_PlaySound(GLASS_HEAVYBREAK,spriteNum); + A_PlaySound(SQUISHED,spriteNum); + fallthrough__; + case BOTTLE7__STATIC: + A_PlaySound(GLASS_BREAKING,spriteNum); + A_SpawnWallGlass(spriteNum,-1,10); + A_DeleteSprite(spriteNum); + break; + case RRTILE2654__STATICRR: + case RRTILE2656__STATICRR: + case RRTILE3172__STATICRR: + if (!RRRA) goto default_case; + A_PlaySound(GLASS_BREAKING,spriteNum); + A_SpawnWallGlass(spriteNum,-1,10); + A_DeleteSprite(spriteNum); + break; + + case HYDROPLANT__STATIC: + if (RR) goto default_case; + PN(spriteNum) = BROKEHYDROPLANT; + A_PlaySound(GLASS_BREAKING,spriteNum); + A_SpawnWallGlass(spriteNum,-1,10); + break; + + case FORCESPHERE__STATIC: + sprite[spriteNum].xrepeat = 0; + actor[OW(spriteNum)].t_data[0] = 32; + actor[OW(spriteNum)].t_data[1] = !actor[OW(spriteNum)].t_data[1]; + actor[OW(spriteNum)].t_data[2] ++; + A_Spawn(spriteNum,EXPLOSION2); + break; + + case BROKEHYDROPLANT__STATIC: + if (RR) goto default_case; + if (CS(spriteNum)&1) + { + A_PlaySound(GLASS_BREAKING,spriteNum); + SZ(spriteNum) += ZOFFSET2; + CS(spriteNum) = 0; + A_SpawnWallGlass(spriteNum,-1,5); + } + break; + + case TOILET__STATIC: + PN(spriteNum) = TOILETBROKE; + CS(spriteNum) |= (krand2()&1)<<2; + CS(spriteNum) &= ~257; + A_Spawn(spriteNum,TOILETWATER); + A_PlaySound(GLASS_BREAKING,spriteNum); + break; + + case STALL__STATIC: + PN(spriteNum) = STALLBROKE; + CS(spriteNum) |= (krand2()&1)<<2; + CS(spriteNum) &= ~257; + A_Spawn(spriteNum,TOILETWATER); + A_PlaySound(GLASS_HEAVYBREAK,spriteNum); + break; + + case HYDRENT__STATIC: + PN(spriteNum) = BROKEFIREHYDRENT; + A_Spawn(spriteNum,TOILETWATER); + + // for(k=0;k<5;k++) + // { + // j = A_InsertSprite(SECT,SX,SY,SZ-(krand2()%(48<<8)),SCRAP3+(krand2()&3),-8,48,48,krand2()&2047,(krand2()&63)+64,-(krand2()&4095)-(sprite[i].zvel>>2),i,5); + // sprite[j].pal = 2; + // } + A_PlaySound(GLASS_HEAVYBREAK,spriteNum); + break; + + case GRATE1__STATIC: + PN(spriteNum) = BGRATE1; + CS(spriteNum) &= (65535-256-1); + A_PlaySound(VENT_BUST, spriteNum); + break; + + case CIRCLEPANNEL__STATIC: + PN(spriteNum) = CIRCLEPANNELBROKE; + CS(spriteNum) &= (65535-256-1); + A_PlaySound(VENT_BUST,spriteNum); + break; + + case PANNEL1__STATIC: + case PANNEL2__STATIC: + if (RR) goto default_case; + PN(spriteNum) = BPANNEL1; + CS(spriteNum) &= (65535-256-1); + A_PlaySound(VENT_BUST,spriteNum); + break; + + case PANNEL3__STATIC: + if (RR) goto default_case; + PN(spriteNum) = BPANNEL3; + CS(spriteNum) &= (65535-256-1); + A_PlaySound(VENT_BUST,spriteNum); + break; + + case PIPE1__STATIC: + case PIPE2__STATIC: + case PIPE3__STATIC: + case PIPE4__STATIC: + case PIPE5__STATIC: + case PIPE6__STATIC: + { + switch (DYNAMICTILEMAP(PN(spriteNum))) + { + case PIPE1__STATIC: + PN(spriteNum)=PIPE1B; + break; + case PIPE2__STATIC: + PN(spriteNum)=PIPE2B; + break; + case PIPE3__STATIC: + PN(spriteNum)=PIPE3B; + break; + case PIPE4__STATIC: + PN(spriteNum)=PIPE4B; + break; + case PIPE5__STATIC: + PN(spriteNum)=PIPE5B; + break; + case PIPE6__STATIC: + PN(spriteNum)=PIPE6B; + break; + } + + int newSprite = A_Spawn(spriteNum, STEAM); + sprite[newSprite].z = sector[SECT(spriteNum)].floorz-ZOFFSET5; + break; + } + + case MONK__STATIC: + case LUKE__STATIC: + case INDY__STATIC: + case JURYGUY__STATIC: + if (RR) goto default_case; + A_PlaySound(SLT(spriteNum),spriteNum); + A_Spawn(spriteNum,SHT(spriteNum)); + fallthrough__; + case SPACEMARINE__STATIC: + if (RR) goto default_case; + sprite[spriteNum].extra -= sprite[dmgSrc].extra; + if (sprite[spriteNum].extra > 0) break; + SA(spriteNum) = krand2()&2047; + A_Shoot(spriteNum,BLOODSPLAT1); + SA(spriteNum) = krand2()&2047; + A_Shoot(spriteNum,BLOODSPLAT2); + SA(spriteNum) = krand2()&2047; + A_Shoot(spriteNum,BLOODSPLAT3); + SA(spriteNum) = krand2()&2047; + A_Shoot(spriteNum,BLOODSPLAT4); + SA(spriteNum) = krand2()&2047; + A_Shoot(spriteNum,BLOODSPLAT1); + SA(spriteNum) = krand2()&2047; + A_Shoot(spriteNum,BLOODSPLAT2); + SA(spriteNum) = krand2()&2047; + A_Shoot(spriteNum,BLOODSPLAT3); + SA(spriteNum) = krand2()&2047; + A_Shoot(spriteNum,BLOODSPLAT4); + A_DoGuts(spriteNum,JIBS1,1); + A_DoGuts(spriteNum,JIBS2,2); + A_DoGuts(spriteNum,JIBS3,3); + A_DoGuts(spriteNum,JIBS4,4); + A_DoGuts(spriteNum,JIBS5,1); + A_DoGuts(spriteNum,JIBS3,6); + S_PlaySound(SQUISHED); + A_DeleteSprite(spriteNum); + break; + + case CHAIR1__STATIC: + case CHAIR2__STATIC: + PN(spriteNum) = BROKENCHAIR; + CS(spriteNum) = 0; + break; + + case TRIPODCAMERA__STATIC: + if (RR) goto default_case; + fallthrough__; + case CHAIR3__STATIC: + case MOVIECAMERA__STATIC: + case SCALE__STATIC: + case VACUUM__STATIC: + case CAMERALIGHT__STATIC: + case IVUNIT__STATIC: + case POT1__STATIC: + case POT2__STATIC: + case POT3__STATIC: + A_PlaySound(GLASS_HEAVYBREAK,spriteNum); + for (bssize_t j=16; j>0; j--) + { + spritetype * const pSprite = &sprite[spriteNum]; + RANDOMSCRAP(pSprite, spriteNum); + } + A_DeleteSprite(spriteNum); + break; + + case PLAYERONWATER__STATIC: + spriteNum = OW(spriteNum); + fallthrough__; + default: +default_case: + if ((sprite[spriteNum].cstat&16) && SHT(spriteNum) == 0 && SLT(spriteNum) == 0 && sprite[spriteNum].statnum == STAT_DEFAULT) + break; + + if (((RR && sprite[dmgSrc].picnum == SHRINKSPARK) || sprite[dmgSrc].picnum == FREEZEBLAST || sprite[dmgSrc].owner != spriteNum) && sprite[spriteNum].statnum != STAT_PROJECTILE) + { + if (A_CheckEnemySprite(&sprite[spriteNum]) == 1) + { + if (sprite[dmgSrc].picnum == RPG || (RRRA && sprite[dmgSrc].picnum == RPG2)) + sprite[dmgSrc].extra <<= 1; + + if ((PN(spriteNum) != DRONE) && (RR || ((PN(spriteNum) != ROTATEGUN) && (PN(spriteNum) != COMMANDER) && (PN(spriteNum) < GREENSLIME || PN(spriteNum) > GREENSLIME+7)))) + if (sprite[dmgSrc].picnum != FREEZEBLAST) + if (!A_CheckSpriteFlags(spriteNum, SFLAG_BADGUY)) + { + int const newSprite = A_Spawn(dmgSrc, JIBS6); + sprite[newSprite].z += ZOFFSET6; + if (sprite[dmgSrc].pal == 6) + sprite[newSprite].pal = 6; + sprite[newSprite].xvel = 16; + sprite[newSprite].xrepeat = sprite[newSprite].yrepeat = 24; + sprite[newSprite].ang += 32 - (krand2() & 63); + } + + int const damageOwner = sprite[dmgSrc].owner; + + if (damageOwner >= 0 && sprite[damageOwner].picnum == APLAYER && (RR || PN(spriteNum) != ROTATEGUN) && PN(spriteNum) != DRONE) + if (g_player[P_Get(damageOwner)].ps->curr_weapon == SHOTGUN_WEAPON) + { + A_Shoot(spriteNum, BLOODSPLAT3); + A_Shoot(spriteNum, BLOODSPLAT1); + A_Shoot(spriteNum, BLOODSPLAT2); + A_Shoot(spriteNum, BLOODSPLAT4); + } + + if (!RR && !A_CheckSpriteFlags(spriteNum, SFLAG_NODAMAGEPUSH)) + { + if ((sprite[spriteNum].cstat & 48) == 0) + SA(spriteNum) = (sprite[dmgSrc].ang + 1024) & 2047; + sprite[spriteNum].xvel = -(sprite[dmgSrc].extra << 2); + int16_t sectNum = SECT(spriteNum); + if ((unsigned)sectNum < MAXSECTORS) + { + pushmove((vec3_t *)&sprite[spriteNum], §Num, 128L, (4L << 8), (4L << 8), CLIPMASK0); + if (sectNum != SECT(spriteNum) && (unsigned)sectNum < MAXSECTORS) + changespritesect(spriteNum, sectNum); + } + } + + if (sprite[spriteNum].statnum == STAT_ZOMBIEACTOR) + { + changespritestat(spriteNum, STAT_ACTOR); + actor[spriteNum].timetosleep = SLEEPTIME; + } + + if (!RR && (sprite[spriteNum].xrepeat < 24 || PN(spriteNum) == SHARK) && sprite[dmgSrc].picnum == SHRINKSPARK) + return; + } + + if (sprite[spriteNum].statnum != STAT_ZOMBIEACTOR) + { + if (sprite[dmgSrc].picnum == FREEZEBLAST && ((PN(spriteNum) == APLAYER && sprite[spriteNum].pal == 1) || (g_freezerSelfDamage == 0 && sprite[dmgSrc].owner == spriteNum))) + return; + actor[spriteNum].picnum = sprite[dmgSrc].picnum; + actor[spriteNum].extra += sprite[dmgSrc].extra; + if (!RR || PN(spriteNum) != COW) + actor[spriteNum].ang = sprite[dmgSrc].ang; + actor[spriteNum].owner = sprite[dmgSrc].owner; + } + + if (sprite[spriteNum].statnum == STAT_PLAYER) + { + DukePlayer_t *ps = g_player[P_Get(spriteNum)].ps; + + if (ps->newowner >= 0) + G_ClearCameraView(ps); + + if (!RR && sprite[spriteNum].xrepeat < 24 && sprite[dmgSrc].picnum == SHRINKSPARK) + return; + + if (sprite[actor[spriteNum].owner].picnum != APLAYER) + if (ud.player_skill >= 3) + sprite[dmgSrc].extra += (sprite[dmgSrc].extra>>1); + } + } + + break; + } +} + +void G_AlignWarpElevators(void) +{ + for (bssize_t SPRITES_OF(STAT_EFFECTOR, i)) + { + if (SLT(i) == SE_17_WARP_ELEVATOR && SS(i) > 16) + { + for (bssize_t SPRITES_OF(STAT_EFFECTOR, j)) + { + if (i != j && sprite[j].lotag == SE_17_WARP_ELEVATOR && SHT(i) == sprite[j].hitag) + { + sector[sprite[j].sectnum].floorz = sector[SECT(i)].floorz; + sector[sprite[j].sectnum].ceilingz = sector[SECT(i)].ceilingz; + } + } + } + } +} + +void P_HandleSharedKeys(int playerNum) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + if (pPlayer->cheat_phase == 1) return; + + uint32_t playerBits = g_player[playerNum].input->bits; + int32_t weaponNum; + + // 1<<0 = jump + // 1<<1 = crouch + // 1<<2 = fire + // 1<<3 = aim up + // 1<<4 = aim down + // 1<<5 = run + // 1<<6 = look left + // 1<<7 = look right + // 15<<8 = !weapon selection (bits 8-11) + // 1<<12 = !steroids + // 1<<13 = look up + // 1<<14 = look down + // 1<<15 = !nightvis + // 1<<16 = !medkit + // 1<<17 = (multiflag==1) ? changes meaning of bits 18 and 19 + // 1<<18 = centre view + // 1<<19 = !holster weapon + // 1<<20 = !inventory left + // 1<<21 = !pause + // 1<<22 = !quick kick + // 1<<23 = aim mode + // 1<<24 = !holoduke + // 1<<25 = !jetpack + // 1<<26 = g_gameQuit + // 1<<27 = !inventory right + // 1<<28 = !turn around + // 1<<29 = !open + // 1<<30 = !inventory + // 1<<31 = !escape + + int const aimMode = pPlayer->aim_mode; + + pPlayer->aim_mode = (playerBits>>SK_AIMMODE)&1; + if (pPlayer->aim_mode < aimMode) + pPlayer->return_to_center = 9; + + if (RR) + { + if (TEST_SYNC_KEY(playerBits, SK_QUICK_KICK) && pPlayer->last_pissed_time == 0 + && (!RRRA || sprite[pPlayer->i].extra > 0)) + { + pPlayer->last_pissed_time = 4000; + if (!adult_lockout) + A_PlaySound(437, pPlayer->i); + if (sprite[pPlayer->i].extra <= pPlayer->max_player_health - pPlayer->max_player_health / 10) + { + sprite[pPlayer->i].extra += 2; + pPlayer->last_extra = sprite[pPlayer->i].extra; + } + else if (sprite[pPlayer->i].extra < pPlayer->max_player_health) + sprite[pPlayer->i].extra = pPlayer->max_player_health; + } + } + else + { + + if (TEST_SYNC_KEY(playerBits, SK_QUICK_KICK) && pPlayer->quick_kick == 0) + if (pPlayer->curr_weapon != KNEE_WEAPON || pPlayer->kickback_pic == 0) + { + if (VM_OnEvent(EVENT_QUICKKICK,g_player[playerNum].ps->i,playerNum) == 0) + { + pPlayer->quick_kick = 14; + if (pPlayer->fta == 0 || pPlayer->ftq == 80) + P_DoQuote(QUOTE_MIGHTY_FOOT,pPlayer); + } + } + } + + if (!(playerBits & ((15u<interface_toggle_flag = 0; + else if (pPlayer->interface_toggle_flag == 0) + { + pPlayer->interface_toggle_flag = 1; + + if (paused) return; + + if (sprite[pPlayer->i].extra <= 0) return; // if dead... + + if (TEST_SYNC_KEY(playerBits, SK_INVENTORY) && pPlayer->newowner == -1) // inventory button generates event for selected item + { + if (VM_OnEvent(EVENT_INVENTORY,g_player[playerNum].ps->i,playerNum) == 0) + { + switch (pPlayer->inven_icon) + { + case ICON_JETPACK: playerBits |= BIT(SK_JETPACK); break; + case ICON_HOLODUKE: playerBits |= BIT(SK_HOLODUKE); break; + case ICON_HEATS: playerBits |= BIT(SK_NIGHTVISION); break; + case ICON_FIRSTAID: playerBits |= BIT(SK_MEDKIT); break; + case ICON_STEROIDS: playerBits |= BIT(SK_STEROIDS); break; + } + } + } + + if (!RR && TEST_SYNC_KEY(playerBits, SK_NIGHTVISION)) + { + if (VM_OnEvent(EVENT_USENIGHTVISION,g_player[playerNum].ps->i,playerNum) == 0 + && pPlayer->inv_amount[GET_HEATS] > 0) + { + pPlayer->heat_on = !pPlayer->heat_on; + P_UpdateScreenPal(pPlayer); + pPlayer->inven_icon = ICON_HEATS; + A_PlaySound(NITEVISION_ONOFF,pPlayer->i); + P_DoQuote(QUOTE_NVG_OFF-!!pPlayer->heat_on,pPlayer); + } + } + + if (TEST_SYNC_KEY(playerBits, SK_STEROIDS)) + { + if (VM_OnEvent(EVENT_USESTEROIDS,g_player[playerNum].ps->i,playerNum) == 0) + { + if (pPlayer->inv_amount[GET_STEROIDS] == 400) + { + pPlayer->inv_amount[GET_STEROIDS]--; + A_PlaySound(DUKE_TAKEPILLS,pPlayer->i); + P_DoQuote(QUOTE_USED_STEROIDS,pPlayer); + } + if (pPlayer->inv_amount[GET_STEROIDS] > 0) + pPlayer->inven_icon = ICON_STEROIDS; + } + return; // is there significance to returning? + } + if (WW2GI && pPlayer->refresh_inventory) + playerBits |= BIT(SK_INV_LEFT); // emulate move left... + + if (pPlayer->newowner == -1 && (TEST_SYNC_KEY(playerBits, SK_INV_LEFT) || TEST_SYNC_KEY(playerBits, SK_INV_RIGHT)) || (!WW2GI && pPlayer->refresh_inventory)) + { + pPlayer->invdisptime = GAMETICSPERSEC*2; + + int const inventoryRight = !!(TEST_SYNC_KEY(playerBits, SK_INV_RIGHT)); + + if (pPlayer->refresh_inventory) pPlayer->refresh_inventory = 0; + int32_t inventoryIcon = pPlayer->inven_icon; + + int i = 0; + +CHECKINV1: + if (i < 9) + { + i++; + + switch (inventoryIcon) + { + case ICON_JETPACK: + case ICON_SCUBA: + case ICON_STEROIDS: + case ICON_HOLODUKE: + case ICON_HEATS: + if (pPlayer->inv_amount[icon_to_inv[inventoryIcon]] > 0 && i > 1) + break; + if (inventoryRight) + inventoryIcon++; + else + inventoryIcon--; + goto CHECKINV1; + case ICON_NONE: + case ICON_FIRSTAID: + if (pPlayer->inv_amount[GET_FIRSTAID] > 0 && i > 1) + break; + inventoryIcon = inventoryRight ? 2 : 7; + goto CHECKINV1; + case ICON_BOOTS: + if (pPlayer->inv_amount[GET_BOOTS] > 0 && i > 1) + break; + inventoryIcon = inventoryRight ? 1 : 6; + goto CHECKINV1; + } + } + else inventoryIcon = 0; + + if (TEST_SYNC_KEY(playerBits, SK_INV_LEFT)) // Inventory_Left + { + /*Gv_SetVar(g_iReturnVarID,dainv,g_player[snum].ps->i,snum);*/ + inventoryIcon = VM_OnEventWithReturn(EVENT_INVENTORYLEFT,g_player[playerNum].ps->i,playerNum, inventoryIcon); + } + else if (TEST_SYNC_KEY(playerBits, SK_INV_RIGHT)) // Inventory_Right + { + /*Gv_SetVar(g_iReturnVarID,dainv,g_player[snum].ps->i,snum);*/ + inventoryIcon = VM_OnEventWithReturn(EVENT_INVENTORYRIGHT,g_player[playerNum].ps->i,playerNum, inventoryIcon); + } + + if (inventoryIcon >= 1) + { + pPlayer->inven_icon = inventoryIcon; + + if (inventoryIcon || pPlayer->inv_amount[GET_FIRSTAID]) + { + static const int32_t invQuotes[7] = { QUOTE_MEDKIT, QUOTE_STEROIDS, QUOTE_HOLODUKE, + QUOTE_JETPACK, QUOTE_NVG, QUOTE_SCUBA, QUOTE_BOOTS }; + if (inventoryIcon-1 < ARRAY_SSIZE(invQuotes)) + P_DoQuote(invQuotes[inventoryIcon-1], pPlayer); + } + } + } + + weaponNum = ((playerBits&(15<>SK_WEAPON_BITS) - 1; + if (weaponNum > 0 && pPlayer->kickback_pic > 0) + { + pPlayer->wantweaponfire = weaponNum; + } + + if (pPlayer->last_pissed_time <= (GAMETICSPERSEC * 218) && pPlayer->show_empty_weapon == 0 && + pPlayer->kickback_pic == 0 && pPlayer->quick_kick == 0 && sprite[pPlayer->i].xrepeat > (RR ? 8 :32) && pPlayer->access_incs == 0 && + pPlayer->knee_incs == 0) + { + if( (pPlayer->weapon_pos == 0 || (pPlayer->holster_weapon && pPlayer->weapon_pos == WEAPON_POS_LOWER ) )) + { + if (weaponNum == 10 || weaponNum == 11) + { + int currentWeapon = pPlayer->curr_weapon; + + if (RRRA) + { + if (currentWeapon == CHICKEN_WEAPON) currentWeapon = RPG_WEAPON; + else if (currentWeapon == GROW_WEAPON) currentWeapon = SHRINKER_WEAPON; + else if (currentWeapon == SLINGBLADE_WEAPON) currentWeapon = KNEE_WEAPON; + } + + weaponNum = (weaponNum == 10 ? -1 : 1); // JBF: prev (-1) or next (1) weapon choice + int i = 0; + + while ((currentWeapon >= 0 && currentWeapon < 10) || (!RR && currentWeapon == GROW_WEAPON && (pPlayer->subweapon&(1 << GROW_WEAPON)))) + { + if (!RR) + { + if (currentWeapon == GROW_WEAPON) + { + if (weaponNum == -1) + currentWeapon = HANDBOMB_WEAPON; + else currentWeapon = DEVISTATOR_WEAPON; + + } + else + { + currentWeapon += weaponNum; + if (currentWeapon == SHRINKER_WEAPON && pPlayer->subweapon&(1 << GROW_WEAPON)) + currentWeapon = GROW_WEAPON; + } + } + else + currentWeapon += weaponNum; + + if (currentWeapon == -1) currentWeapon = FREEZE_WEAPON; + else if (currentWeapon == 10) currentWeapon = KNEE_WEAPON; + + if ((pPlayer->gotweapon & (1<ammo_amount[currentWeapon] > 0) + { + if (!RR && currentWeapon == SHRINKER_WEAPON && pPlayer->subweapon&(1<ammo_amount[GROW_WEAPON] == 0 + && (pPlayer->gotweapon & (1<ammo_amount[SHRINKER_WEAPON] > 0) + { + weaponNum = SHRINKER_WEAPON; + pPlayer->subweapon &= ~(1<ammo_amount[SHRINKER_WEAPON] == 0 + && (pPlayer->gotweapon & (1<ammo_amount[GROW_WEAPON] > 0) + { + weaponNum = GROW_WEAPON; + pPlayer->subweapon |= (1<ammo_amount[HANDBOMB_WEAPON] == 0) + { + int spriteNum = headspritestat[1]; + while (spriteNum >= 0) + { + if (sprite[spriteNum].picnum == HEAVYHBOMB && sprite[spriteNum].owner == pPlayer->i) + { + pPlayer->gotweapon |= 1<curr_weapon == KNEE_WEAPON) + { + pPlayer->subweapon = 2; + weaponNum = SLINGBLADE_WEAPON; + } + else if(pPlayer->subweapon&2) + { + pPlayer->subweapon = 0; + weaponNum = KNEE_WEAPON; + } + } + else if (weaponNum == RPG_WEAPON) + { + if(screenpeek == playerNum) pus = NUMPAGES; + + if (pPlayer->curr_weapon == RPG_WEAPON || pPlayer->ammo_amount[RPG_WEAPON] == 0) + { + if (pPlayer->ammo_amount[CHICKEN_WEAPON] == 0) + return; + pPlayer->subweapon = 4; + weaponNum = CHICKEN_WEAPON; + } + else if((pPlayer->subweapon&4) || pPlayer->ammo_amount[CHICKEN_WEAPON] == 0) + { + pPlayer->subweapon = 0; + weaponNum = RPG_WEAPON; + } + } + } + if (RR) + { + if(weaponNum == SHRINKER_WEAPON) + { + if(screenpeek == playerNum) pus = NUMPAGES; + + if (pPlayer->curr_weapon == SHRINKER_WEAPON || pPlayer->ammo_amount[SHRINKER_WEAPON] == 0) + { + pPlayer->subweapon = (1<subweapon&(1<ammo_amount[GROW_WEAPON] == 0) + { + pPlayer->subweapon = 0; + weaponNum = SHRINKER_WEAPON; + } + } + else if(weaponNum == TRIPBOMB_WEAPON) + { + if(screenpeek == playerNum) pus = NUMPAGES; + + if (pPlayer->curr_weapon == TRIPBOMB_WEAPON || pPlayer->ammo_amount[TRIPBOMB_WEAPON] == 0) + { + pPlayer->subweapon = (1<subweapon&(1<ammo_amount[BOWLINGBALL_WEAPON] == 0) + { + pPlayer->subweapon = 0; + weaponNum = TRIPBOMB_WEAPON; + } + } + } + + if (!RR && weaponNum == SHRINKER_WEAPON) + { + if (screenpeek == playerNum) pus = NUMPAGES; + + if (pPlayer->curr_weapon != GROW_WEAPON && pPlayer->curr_weapon != SHRINKER_WEAPON) + { + if (pPlayer->ammo_amount[GROW_WEAPON] > 0) + { + if ((pPlayer->subweapon&(1 << GROW_WEAPON)) == (1 << GROW_WEAPON)) + weaponNum = GROW_WEAPON; + else if (pPlayer->ammo_amount[SHRINKER_WEAPON] == 0) + { + weaponNum = GROW_WEAPON; + pPlayer->subweapon |= (1 << GROW_WEAPON); + } + } + else if (pPlayer->ammo_amount[SHRINKER_WEAPON] > 0) + pPlayer->subweapon &= ~(1 << GROW_WEAPON); + } + else if (pPlayer->curr_weapon == SHRINKER_WEAPON) + { + pPlayer->subweapon |= (1 << GROW_WEAPON); + weaponNum = GROW_WEAPON; + } + else + pPlayer->subweapon &= ~(1 << GROW_WEAPON); + } + + if (pPlayer->holster_weapon) + { + playerBits |= BIT(SK_HOLSTER); + pPlayer->weapon_pos = WEAPON_POS_LOWER; + } + else if ((uint32_t)weaponNum < MAX_WEAPONS && (pPlayer->gotweapon & (1<curr_weapon != weaponNum) + switch (DYNAMICWEAPONMAP(weaponNum)) + { + case SLINGBLADE_WEAPON__STATIC: + if (!RRRA) break; + A_PlaySound(496,g_player[screenpeek].ps->i); + P_AddWeapon(pPlayer, weaponNum); + break; + case CHICKEN_WEAPON__STATIC: + if (!RRRA) break; + fallthrough__; + case BOWLINGBALL_WEAPON__STATIC: + if (!RR) break; + fallthrough__; + case PISTOL_WEAPON__STATIC: + case SHOTGUN_WEAPON__STATIC: + case CHAINGUN_WEAPON__STATIC: + case RPG_WEAPON__STATIC: + case DEVISTATOR_WEAPON__STATIC: + case FREEZE_WEAPON__STATIC: + case GROW_WEAPON__STATIC: + case SHRINKER_WEAPON__STATIC: +rrtripbomb_case: + if (pPlayer->ammo_amount[weaponNum] == 0 && pPlayer->show_empty_weapon == 0) + { + pPlayer->last_full_weapon = pPlayer->curr_weapon; + pPlayer->show_empty_weapon = 32; + } + fallthrough__; + case KNEE_WEAPON__STATIC: + P_AddWeapon(pPlayer, weaponNum); + break; + case HANDREMOTE_WEAPON__STATIC: + pPlayer->curr_weapon = HANDREMOTE_WEAPON; + pPlayer->last_weapon = -1; + pPlayer->weapon_pos = WEAPON_POS_RAISE; + break; + case HANDBOMB_WEAPON__STATIC: + case TRIPBOMB_WEAPON__STATIC: + if (RR && weaponNum == TRIPBOMB) goto rrtripbomb_case; + if (pPlayer->ammo_amount[weaponNum] > 0 && (pPlayer->gotweapon & (1<ammo_amount[weaponNum] == 0 && pPlayer->show_empty_weapon == 0) + pPlayer->show_empty_weapon = 32; + P_AddWeapon(pPlayer, weaponNum); + break; + } + } + + if (TEST_SYNC_KEY(playerBits, SK_HOLSTER)) + { + if (pPlayer->curr_weapon > KNEE_WEAPON) + { + if (pPlayer->holster_weapon == 0 && pPlayer->weapon_pos == 0) + { + pPlayer->holster_weapon = 1; + pPlayer->weapon_pos = -1; + P_DoQuote(QUOTE_WEAPON_LOWERED, pPlayer); + } + else if (pPlayer->holster_weapon == 1 && pPlayer->weapon_pos == WEAPON_POS_LOWER) + { + pPlayer->holster_weapon = 0; + pPlayer->weapon_pos = WEAPON_POS_RAISE; + P_DoQuote(QUOTE_WEAPON_RAISED, pPlayer); + } + } + } + } + + if (TEST_SYNC_KEY(playerBits, SK_HOLODUKE) && (RR || pPlayer->newowner == -1)) + { + if (RR) + { + if (pPlayer->inv_amount[GET_HOLODUKE] > 0 && sprite[pPlayer->i].extra < pPlayer->max_player_health) + { + pPlayer->inv_amount[GET_HOLODUKE] -= 400; + sprite[pPlayer->i].extra += 5; + if (sprite[pPlayer->i].extra > pPlayer->max_player_health) + sprite[pPlayer->i].extra = pPlayer->max_player_health; + + pPlayer->drink_amt += 5; + pPlayer->inven_icon = 3; + if (pPlayer->inv_amount[GET_HOLODUKE] == 0) + P_SelectNextInvItem(pPlayer); + + if (pPlayer->drink_amt < 99) + if (!A_CheckSoundPlaying(pPlayer->i, 425)) + A_PlaySound(425, pPlayer->i); + } + } + else + { + if (pPlayer->holoduke_on == -1) + { + if (VM_OnEvent(EVENT_HOLODUKEON, g_player[playerNum].ps->i, playerNum) == 0) + { + if (pPlayer->inv_amount[GET_HOLODUKE] > 0) + { + pPlayer->inven_icon = ICON_HOLODUKE; + + if (pPlayer->cursectnum > -1) + { + int const i = A_InsertSprite(pPlayer->cursectnum, pPlayer->pos.x, pPlayer->pos.y, + pPlayer->pos.z+(30<<8), APLAYER, -64, 0, 0, fix16_to_int(pPlayer->q16ang), 0, 0, -1, 10); + pPlayer->holoduke_on = i; + T4(i) = T5(i) = 0; + sprite[i].yvel = playerNum; + sprite[i].extra = 0; + P_DoQuote(QUOTE_HOLODUKE_ON,pPlayer); + A_PlaySound(TELEPORTER,pPlayer->holoduke_on); + } + } + else P_DoQuote(QUOTE_HOLODUKE_NOT_FOUND,pPlayer); + } + } + else + { + if (VM_OnEvent(EVENT_HOLODUKEOFF,g_player[playerNum].ps->i,playerNum) == 0) + { + A_PlaySound(TELEPORTER,pPlayer->holoduke_on); + pPlayer->holoduke_on = -1; + P_DoQuote(QUOTE_HOLODUKE_OFF,pPlayer); + } + } + } + } + + if (RR && TEST_SYNC_KEY(playerBits, SK_NIGHTVISION) && pPlayer->newowner == -1 && pPlayer->yehaa_timer == 0) + { + pPlayer->yehaa_timer = 126; + A_PlaySound(390, pPlayer->i); + pPlayer->noise_radius = 16384; + P_MadeNoise(playerNum); + if (sector[pPlayer->cursectnum].lotag == 857) + { + if (sprite[pPlayer->i].extra <= pPlayer->max_player_health) + { + sprite[pPlayer->i].extra += 10; + if (sprite[pPlayer->i].extra >= pPlayer->max_player_health) + sprite[pPlayer->i].extra = pPlayer->max_player_health; + } + } + else + { + if (sprite[pPlayer->i].extra + 1 <= pPlayer->max_player_health) + { + sprite[pPlayer->i].extra++; + } + } + } + + if (TEST_SYNC_KEY(playerBits, SK_MEDKIT)) + { + if (VM_OnEvent(EVENT_USEMEDKIT,g_player[playerNum].ps->i,playerNum) == 0) + { + if (pPlayer->inv_amount[GET_FIRSTAID] > 0 && sprite[pPlayer->i].extra < pPlayer->max_player_health) + { + int healthDiff = pPlayer->max_player_health-sprite[pPlayer->i].extra; + + if (RR) healthDiff = 10; + + if (pPlayer->inv_amount[GET_FIRSTAID] > healthDiff) + { + pPlayer->inv_amount[GET_FIRSTAID] -= healthDiff; + if (RR) + sprite[pPlayer->i].extra += healthDiff; + if (!RR || sprite[pPlayer->i].extra > pPlayer->max_player_health) + sprite[pPlayer->i].extra = pPlayer->max_player_health; + pPlayer->inven_icon = ICON_FIRSTAID; + } + else + { + sprite[pPlayer->i].extra += pPlayer->inv_amount[GET_FIRSTAID]; + pPlayer->inv_amount[GET_FIRSTAID] = 0; + P_SelectNextInvItem(pPlayer); + } + if (RR) + { + if (sprite[pPlayer->i].extra > pPlayer->max_player_health) + sprite[pPlayer->i].extra = pPlayer->max_player_health; + pPlayer->drink_amt += 10; + } + if (!RR || (pPlayer->drink_amt <= 100 && !A_CheckSoundPlaying(pPlayer->i, DUKE_USEMEDKIT))) + A_PlaySound(DUKE_USEMEDKIT,pPlayer->i); + } + } + } + + if ((pPlayer->newowner == -1 || RR) && TEST_SYNC_KEY(playerBits, SK_JETPACK)) + { + if (RR) + { + if (VM_OnEvent(EVENT_USEJETPACK,g_player[playerNum].ps->i,playerNum) == 0) + { + if (pPlayer->inv_amount[GET_JETPACK] > 0 && sprite[pPlayer->i].extra < pPlayer->max_player_health) + { + if (!A_CheckSoundPlaying(pPlayer->i, 429)) + A_PlaySound(429, pPlayer->i); + + pPlayer->inv_amount[GET_JETPACK] -= 100; + if (pPlayer->drink_amt > 0) + { + pPlayer->drink_amt -= 5; + if (pPlayer->drink_amt < 0) + pPlayer->drink_amt = 0; + } + + if (pPlayer->eat_amt < 100) + { + pPlayer->eat_amt += 5; + if (pPlayer->eat_amt > 100) + pPlayer->eat_amt = 100; + } + + sprite[pPlayer->i].extra += 5; + + pPlayer->inven_icon = 4; + + if (sprite[pPlayer->i].extra > pPlayer->max_player_health) + sprite[pPlayer->i].extra = pPlayer->max_player_health; + + if (pPlayer->inv_amount[GET_JETPACK] <= 0) + P_SelectNextInvItem(pPlayer); + } + } + } + else + { + if (pPlayer->inv_amount[GET_JETPACK] > 0) + { + pPlayer->jetpack_on = !pPlayer->jetpack_on; + if (pPlayer->jetpack_on) + { + pPlayer->inven_icon = ICON_JETPACK; + S_StopEnvSound(-1, pPlayer->i, CHAN_VOICE); + + A_PlaySound(DUKE_JETPACK_ON,pPlayer->i); + + P_DoQuote(QUOTE_JETPACK_ON,pPlayer); + } + else + { + pPlayer->hard_landing = 0; + pPlayer->vel.z = 0; + A_PlaySound(DUKE_JETPACK_OFF,pPlayer->i); + S_StopEnvSound(DUKE_JETPACK_IDLE,pPlayer->i); + S_StopEnvSound(DUKE_JETPACK_ON,pPlayer->i); + P_DoQuote(QUOTE_JETPACK_OFF,pPlayer); + } + } + else P_DoQuote(QUOTE_JETPACK_NOT_FOUND,pPlayer); + } + } + + if (TEST_SYNC_KEY(playerBits, SK_TURNAROUND) && pPlayer->one_eighty_count == 0) + if (VM_OnEvent(EVENT_TURNAROUND,pPlayer->i,playerNum) == 0) + { + pPlayer->one_eighty_count = -1024; + pPlayer->one_eighty_target = fix16_sadd(pPlayer->q16ang, -fix16_from_int(pPlayer->one_eighty_count)) & 0x7FFFFFF; + } + } +} + +int A_CheckHitSprite(int spriteNum, int16_t *hitSprite) +{ + hitdata_t hitData; + int32_t zOffset = 0; + + if (A_CheckEnemySprite(&sprite[spriteNum])) + zOffset = (42 << 8); + else if (PN(spriteNum) == APLAYER) + zOffset = (39 << 8); + + SZ(spriteNum) -= zOffset; + hitscan((const vec3_t *)&sprite[spriteNum], SECT(spriteNum), sintable[(SA(spriteNum) + 512) & 2047], + sintable[SA(spriteNum) & 2047], 0, &hitData, CLIPMASK1); + SZ(spriteNum) += zOffset; + + if (hitSprite) + *hitSprite = hitData.sprite; + + if (hitData.wall >= 0 && (wall[hitData.wall].cstat&16) && A_CheckEnemySprite( &sprite[spriteNum])) + return 1<<30; + + return FindDistance2D(hitData.pos.x-SX(spriteNum),hitData.pos.y-SY(spriteNum)); +} + +static int P_FindWall(DukePlayer_t *pPlayer, int *hitWall) +{ + hitdata_t hitData; + + hitscan((const vec3_t *)pPlayer, pPlayer->cursectnum, sintable[(fix16_to_int(pPlayer->q16ang) + 512) & 2047], + sintable[fix16_to_int(pPlayer->q16ang) & 2047], 0, &hitData, CLIPMASK0); + + *hitWall = hitData.wall; + + if (hitData.wall < 0) + return INT32_MAX; + + return FindDistance2D(hitData.pos.x - pPlayer->pos.x, hitData.pos.y - pPlayer->pos.y); +} + +// returns 1 if sprite i should not be considered by neartag +static int32_t our_neartag_blacklist(int32_t UNUSED(spriteNum)) +{ + return 0; +} + +static void G_ClearCameras(DukePlayer_t *p) +{ + G_ClearCameraView(p); +} + +void P_CheckSectors(int playerNum) +{ + DukePlayer_t *const pPlayer = g_player[playerNum].ps; + + if (pPlayer->cursectnum > -1) + { + sectortype *const pSector = §or[pPlayer->cursectnum]; + switch ((uint16_t)pSector->lotag) + { + case 32767: + pSector->lotag = 0; + if (RR && !RRRA) + g_canSeePlayer = 0; + P_DoQuote(QUOTE_FOUND_SECRET, pPlayer); + SECRET_Trigger(pPlayer->cursectnum); + pPlayer->secret_rooms++; + return; + + case UINT16_MAX: + pSector->lotag = 0; + for (bssize_t TRAVERSE_CONNECT(playerNum)) + g_player[playerNum].ps->gm = MODE_EOL; + + if (!RRRA || !g_RAendLevel) + { + if (ud.from_bonus) + { + ud.level_number = ud.from_bonus; + m_level_number = ud.level_number; + ud.from_bonus = 0; + } + else + { + if (RRRA && ud.level_number == 6 && ud.volume_number == 0) + g_RAendEpisode = 1; + ud.level_number = (++ud.level_number < MAXLEVELS) ? ud.level_number : 0; + m_level_number = ud.level_number; + } + g_RAendLevel = 1; + } + return; + + case UINT16_MAX-1: + pSector->lotag = 0; + pPlayer->timebeforeexit = GAMETICSPERSEC * 8; + pPlayer->customexitsound = pSector->hitag; + return; + + default: + if (pSector->lotag >= 10000 && (RR || pSector->lotag < 16383)) + { + if (playerNum == screenpeek || (g_gametypeFlags[ud.coop] & GAMETYPE_COOPSOUND)) + { + if (RR && !RRRA) + g_canSeePlayer = -1; + A_PlaySound(pSector->lotag - 10000, pPlayer->i); + } + pSector->lotag = 0; + } + break; + } + } + + //After this point the the player effects the map with space + + if (pPlayer->gm &MODE_TYPE || sprite[pPlayer->i].extra <= 0) + return; + + if (ud.cashman && TEST_SYNC_KEY(g_player[playerNum].input->bits, SK_OPEN)) + { + if (RR && !RRRA) + g_canSeePlayer = -1; + A_SpawnMultiple(pPlayer->i, MONEY, 2); + } + + if (!RR && pPlayer->newowner >= 0) + { + if (klabs(g_player[playerNum].input->svel) > 768 || klabs(g_player[playerNum].input->fvel) > 768) + { + G_ClearCameras(pPlayer); + return; + } + } + + if (!TEST_SYNC_KEY(g_player[playerNum].input->bits, SK_OPEN) && !TEST_SYNC_KEY(g_player[playerNum].input->bits, SK_ESCAPE)) + pPlayer->toggle_key_flag = 0; + else if (!pPlayer->toggle_key_flag) + { + int foundWall; + + int16_t nearSector, nearWall, nearSprite; + int32_t nearDist; + + if (!RR && TEST_SYNC_KEY(g_player[playerNum].input->bits, SK_ESCAPE)) + { + if (pPlayer->newowner >= 0) + G_ClearCameras(pPlayer); + return; + } + + nearSprite = -1; + pPlayer->toggle_key_flag = 1; + foundWall = -1; + + if (RR && !RRRA) + { + hitdata_t hitData; + hitscan((const vec3_t *)pPlayer, pPlayer->cursectnum, sintable[(fix16_to_int(pPlayer->q16ang) + 512) & 2047], + sintable[fix16_to_int(pPlayer->q16ang) & 2047], 0, &hitData, CLIPMASK0); + g_canSeePlayer &= ~0xffff; + g_canSeePlayer |= hitData.sect; + } + + int wallDist = P_FindWall(pPlayer, &foundWall); + + if (RRRA) + { + if (foundWall >= 0 && wall[foundWall].overpicnum == MIRROR && playerNum == screenpeek) + if (!g_netServer && numplayers == 1) + { + if (A_CheckSoundPlaying(pPlayer->i,27) == 0 && A_CheckSoundPlaying(pPlayer->i,28) == 0 && A_CheckSoundPlaying(pPlayer->i,29) == 0 + && A_CheckSoundPlaying(pPlayer->i,257) == 0 && A_CheckSoundPlaying(pPlayer->i,258) == 0) + { + int snd = krand2() % 5; + if (snd == 0) + A_PlaySound(27, pPlayer->i); + else if (snd == 1) + A_PlaySound(28, pPlayer->i); + else if (snd == 2) + A_PlaySound(29, pPlayer->i); + else if (snd == 3) + A_PlaySound(257, pPlayer->i); + else if (snd == 4) + A_PlaySound(258, pPlayer->i); + } + return; + } + } + else if (foundWall >= 0 && (RR || wallDist < 1280) && wall[foundWall].overpicnum == MIRROR) + if (wall[foundWall].lotag > 0 && !A_CheckSoundPlaying(pPlayer->i,wall[foundWall].lotag) && playerNum == screenpeek) + { + if (RR) + g_canSeePlayer = -1; + A_PlaySound(wall[foundWall].lotag,pPlayer->i); + return; + } + + if (foundWall >= 0 && (wall[foundWall].cstat&16)) + { + if (RRRA) + g_canSeePlayer = foundWall*32; + if (wall[foundWall].lotag) + return; + } + + int const intang = fix16_to_int(pPlayer->oq16ang); + + if (RRRA) + { + if (pPlayer->on_motorcycle) + { + if (pPlayer->moto_speed < 20) + G_OffMotorcycle(pPlayer); + return; + } + if (pPlayer->on_boat) + { + if (pPlayer->moto_speed < 20) + G_OffBoat(pPlayer); + return; + } + neartag(pPlayer->opos.x, pPlayer->opos.y, pPlayer->opos.z, sprite[pPlayer->i].sectnum, intang, &nearSector, + &nearWall, &nearSprite, &nearDist, 1280, 1, our_neartag_blacklist); + } + + if (RR && !RRRA) + g_canSeePlayer = -1; + + if (pPlayer->newowner >= 0) + neartag(pPlayer->opos.x, pPlayer->opos.y, pPlayer->opos.z, sprite[pPlayer->i].sectnum, intang, &nearSector, + &nearWall, &nearSprite, &nearDist, 1280, 1, our_neartag_blacklist); + else + { + neartag(pPlayer->pos.x, pPlayer->pos.y, pPlayer->pos.z, sprite[pPlayer->i].sectnum, intang, &nearSector, + &nearWall, &nearSprite, &nearDist, 1280, 1, our_neartag_blacklist); + if (nearSprite == -1 && nearWall == -1 && nearSector == -1) + neartag(pPlayer->pos.x, pPlayer->pos.y, pPlayer->pos.z+ZOFFSET3, sprite[pPlayer->i].sectnum, intang, &nearSector, + &nearWall, &nearSprite, &nearDist, 1280, 1, our_neartag_blacklist); + if (nearSprite == -1 && nearWall == -1 && nearSector == -1) + neartag(pPlayer->pos.x, pPlayer->pos.y, pPlayer->pos.z+ZOFFSET2, sprite[pPlayer->i].sectnum, intang, &nearSector, + &nearWall, &nearSprite, &nearDist, 1280, 1, our_neartag_blacklist); + if (nearSprite == -1 && nearWall == -1 && nearSector == -1) + { + neartag(pPlayer->pos.x, pPlayer->pos.y, pPlayer->pos.z+ZOFFSET2, sprite[pPlayer->i].sectnum, intang, &nearSector, + &nearWall, &nearSprite, &nearDist, 1280, 3, our_neartag_blacklist); + if (nearSprite >= 0) + { + switch (DYNAMICTILEMAP(sprite[nearSprite].picnum)) + { + case PODFEM1__STATIC: + case FEM1__STATIC: + case FEM2__STATIC: + case FEM3__STATIC: + case FEM4__STATIC: + case FEM5__STATIC: + case FEM6__STATIC: + case FEM7__STATIC: + case FEM8__STATIC: + case FEM9__STATIC: + if (RR) break; + fallthrough__; + case FEM10__STATIC: + case NAKED1__STATIC: + case STATUE__STATIC: + case TOUGHGAL__STATIC: return; + case COW__STATICRR: + g_spriteExtra[nearSprite] = 1; + return; + } + } + + nearSprite = -1; + nearWall = -1; + nearSector = -1; + } + } + + if (pPlayer->newowner == -1 && nearSprite == -1 && nearSector == -1 && nearWall == -1) + { + if (isanunderoperator(sector[sprite[pPlayer->i].sectnum].lotag)) + nearSector = sprite[pPlayer->i].sectnum; + } + + if (nearSector >= 0 && (sector[nearSector].lotag&16384)) + return; + + if (nearSprite == -1 && nearWall == -1) + { + if (pPlayer->cursectnum >= 0 && sector[pPlayer->cursectnum].lotag == 2) + { + if (A_CheckHitSprite(pPlayer->i, &nearSprite) > 1280) + nearSprite = -1; + } + } + + if (nearSprite >= 0) + { + if (RR && !RRRA) + g_canSeePlayer = playerNum; + if (P_ActivateSwitch(playerNum, nearSprite, 1)) + return; + + switch (DYNAMICTILEMAP(sprite[nearSprite].picnum)) + { + case RRTILE8448__STATICRR: + if (!RRRA) break; + if (!A_CheckSoundPlaying(nearSprite, 340)) + A_PlaySound(340, nearSprite); + return; + case RRTILE8704__STATICRR: + if (!RRRA) break; + if (!g_netServer && numplayers == 1) + { + static int soundPlayed = 0; + if (S_CheckSoundPlaying(nearSprite, 445) == 0 && soundPlayed == 0) + { + A_PlaySound(445, nearSprite); + soundPlayed = 1; + } + else if (S_CheckSoundPlaying(nearSprite, 445) == 0 && S_CheckSoundPlaying(nearSprite, 446) == 0 + && S_CheckSoundPlaying(nearSprite, 447) == 0 && soundPlayed == 0) + { + if ((krand2()%2) == 1) + A_PlaySound(446, nearSprite); + else + A_PlaySound(447, nearSprite); + } + } + return; + case EMPTYBIKE__STATICRR: + if (!RRRA) break; + G_OnMotorcycle(pPlayer, nearSprite); + return; + case EMPTYBOAT__STATICRR: + if (!RRRA) break; + G_OnBoat(pPlayer, nearSprite); + return; + case RRTILE8164__STATICRR: + case RRTILE8165__STATICRR: + case RRTILE8166__STATICRR: + case RRTILE8167__STATICRR: + case RRTILE8168__STATICRR: + case RRTILE8591__STATICRR: + case RRTILE8592__STATICRR: + case RRTILE8593__STATICRR: + case RRTILE8594__STATICRR: + case RRTILE8595__STATICRR: + if (!RRRA) break; + sprite[nearSprite].extra = 60; + A_PlaySound(235, nearSprite); + return; + case TOILET__STATIC: + case STALL__STATIC: + case RRTILE2121__STATICRR: + case RRTILE2122__STATICRR: + if (pPlayer->last_pissed_time == 0) + { + if (adult_lockout == 0) + A_PlaySound(RR ? 435 : DUKE_URINATE, pPlayer->i); + + pPlayer->last_pissed_time = GAMETICSPERSEC * 220; + pPlayer->transporter_hold = 29 * 2; + + if (pPlayer->holster_weapon == 0) + { + pPlayer->holster_weapon = 1; + pPlayer->weapon_pos = -1; + } + + if (sprite[pPlayer->i].extra <= (pPlayer->max_player_health - (pPlayer->max_player_health / 10))) + { + sprite[pPlayer->i].extra += pPlayer->max_player_health / 10; + pPlayer->last_extra = sprite[pPlayer->i].extra; + } + else if (sprite[pPlayer->i].extra < pPlayer->max_player_health) + sprite[pPlayer->i].extra = pPlayer->max_player_health; + } + else if (!A_CheckSoundPlaying(nearSprite,RR ? DUKE_GRUNT : FLUSH_TOILET)) + { + if (RR && !RRRA) + g_canSeePlayer = -1; + + A_PlaySound(RR ? DUKE_GRUNT : FLUSH_TOILET,nearSprite); + } + return; + + case NUKEBUTTON__STATIC: + { + if (RR) break; + int wallNum; + + P_FindWall(pPlayer, &wallNum); + + if (wallNum >= 0 && wall[wallNum].overpicnum == 0) + { + if (actor[nearSprite].t_data[0] == 0) + { + if (ud.noexits && (g_netServer || ud.multimode > 1)) + { + // NUKEBUTTON frags the player + actor[pPlayer->i].picnum = NUKEBUTTON; + actor[pPlayer->i].extra = 250; + } + else + { + actor[nearSprite].t_data[0] = 1; + sprite[nearSprite].owner = pPlayer->i; + // assignment of buttonpalette here is not a bug + ud.secretlevel = + (pPlayer->buttonpalette = sprite[nearSprite].pal) ? sprite[nearSprite].lotag : 0; + } + } + } + return; + } + + case WATERFOUNTAIN__STATIC: + if (actor[nearSprite].t_data[0] != 1) + { + actor[nearSprite].t_data[0] = 1; + sprite[nearSprite].owner = pPlayer->i; + + if (sprite[pPlayer->i].extra < pPlayer->max_player_health) + { + sprite[pPlayer->i].extra++; + if (RR && !RRRA) + g_canSeePlayer = -1; + A_PlaySound(DUKE_DRINKING,pPlayer->i); + } + } + return; + + case PLUG__STATIC: + if (RR && !RRRA) + g_canSeePlayer = -1; + A_PlaySound(SHORT_CIRCUIT, pPlayer->i); + sprite[pPlayer->i].extra -= 2+(krand2()&3); + + P_PalFrom(pPlayer, 32, 48,48,64); + break; + + case VIEWSCREEN__STATIC: + case VIEWSCREEN2__STATIC: + if (RR) break; + // Try to find a camera sprite for the viewscreen. + for (bssize_t SPRITES_OF(STAT_ACTOR, spriteNum)) + { + if (PN(spriteNum) == CAMERA1 && SP(spriteNum) == 0 && sprite[nearSprite].hitag == SLT(spriteNum)) + { + sprite[spriteNum].yvel = 1; // Using this camera + A_PlaySound(MONITOR_ACTIVE, pPlayer->i); + sprite[nearSprite].owner = spriteNum; + sprite[nearSprite].yvel = 1; // VIEWSCREEN_YVEL + g_curViewscreen = nearSprite; + + int const playerSectnum = pPlayer->cursectnum; + pPlayer->cursectnum = SECT(spriteNum); + P_UpdateScreenPal(pPlayer); + pPlayer->cursectnum = playerSectnum; + pPlayer->newowner = spriteNum; + + //P_UpdatePosWhenViewingCam(pPlayer); + + return; + } + } + + G_ClearCameras(pPlayer); + return; + } // switch + } + + if (TEST_SYNC_KEY(g_player[playerNum].input->bits, SK_OPEN) == 0) + return; + + if (!RR && pPlayer->newowner >= 0) + { + G_ClearCameras(pPlayer); + return; + } + if (RR && !RRRA && nearWall == -1 && nearSector == -1 && nearSprite == -1) + g_canSeePlayer = playerNum; + + if (nearWall == -1 && nearSector == -1 && nearSprite == -1) + { + if (klabs(A_GetHitscanRange(pPlayer->i)) < 512) + { + if (RR && !RRRA) + g_canSeePlayer = -1; + A_PlaySound(((krand2()&255) < 16) ? DUKE_SEARCH2 : DUKE_SEARCH, pPlayer->i); + return; + } + } + + if (nearWall >= 0) + { + if (wall[nearWall].lotag > 0 && CheckDoorTile(wall[nearWall].picnum)) + { + if (foundWall == nearWall || foundWall == -1) + { + if (RR && !RRRA) + g_canSeePlayer = playerNum; + P_ActivateSwitch(playerNum,nearWall,0); + } + return; + } + else if (!RR && pPlayer->newowner >= 0) + { + G_ClearCameras(pPlayer); + return; + } + } + + if (nearSector >= 0 && (sector[nearSector].lotag&16384) == 0 && + isanearoperator(sector[nearSector].lotag)) + { + for (bssize_t SPRITES_OF_SECT(nearSector, spriteNum)) + { + if (PN(spriteNum) == ACTIVATOR || PN(spriteNum) == MASTERSWITCH) + return; + } + + if (!RR || P_HasKey(nearSector, playerNum)) + { + if (RR && !RRRA) + g_canSeePlayer = -1; + G_OperateSectors(nearSector,pPlayer->i); + } + else if (RR) + { + if (g_sectorExtra[nearSector] > 3) + A_PlaySound(99,pPlayer->i); + else + A_PlaySound(419,pPlayer->i); + if (RR && !RRRA) + g_canSeePlayer = -1; + P_DoQuote(41,pPlayer); + } + } + else if ((sector[sprite[pPlayer->i].sectnum].lotag&16384) == 0) + { + if (isanunderoperator(sector[sprite[pPlayer->i].sectnum].lotag)) + { + for (bssize_t SPRITES_OF_SECT(sprite[pPlayer->i].sectnum, spriteNum)) + { + if (PN(spriteNum) == ACTIVATOR || PN(spriteNum) == MASTERSWITCH) + return; + } + + if (!RR || P_HasKey(sprite[pPlayer->i].sectnum, playerNum)) + { + if (RR && !RRRA) + g_canSeePlayer = -1; + G_OperateSectors(sprite[pPlayer->i].sectnum,pPlayer->i); + } + else if (RR) + { + if (g_sectorExtra[sprite[pPlayer->i].sectnum] > 3) + A_PlaySound(99,pPlayer->i); + else + A_PlaySound(419,pPlayer->i); + if (RR && !RRRA) + g_canSeePlayer = -1; + P_DoQuote(41,pPlayer); + } + } + else P_ActivateSwitch(playerNum,nearWall,0); + } + } +} + +void G_DoFurniture(int wallNum, int sectNum, int playerNum) +{ + int startwall, endwall; + int insideCheck, i; + int32_t max_x, min_x, max_y, min_y, speed; + startwall = sector[wall[wallNum].nextsector].wallptr; + endwall = startwall+sector[wall[wallNum].nextsector].wallnum; + + insideCheck = 1; + max_x = max_y = -(2<<16); + min_x = min_y = 2<<16; + speed = sector[sectNum].hitag; + if (speed > 16) + speed = 16; + else if (speed == 0) + speed = 4; + for (i = startwall; i < endwall; i++) + { + if (max_x < wall[i].x) + max_x = wall[i].x; + if (max_y < wall[i].y) + max_y = wall[i].y; + if (min_x > wall[i].x) + min_x = wall[i].x; + if (min_y > wall[i].y) + min_y = wall[i].y; + } + max_x += speed+1; + max_y += speed+1; + min_x -= speed+1; + min_y -= speed+1; + if (!inside(max_x, max_y, sectNum)) + insideCheck = 0; + if (!inside(max_x, min_y, sectNum)) + insideCheck = 0; + if (!inside(min_x, min_y, sectNum)) + insideCheck = 0; + if (!inside(min_x, max_y, sectNum)) + insideCheck = 0; + if (insideCheck) + { + if (!S_CheckSoundPlaying(g_player[playerNum].ps->i, 389)) + A_PlaySound(389, g_player[playerNum].ps->i); + for (i = startwall; i < endwall; i++) + { + int32_t x, y; + x = wall[i].x; + y = wall[i].y; + switch (wall[wallNum].lotag) + { + case 42: + dragpoint(i,x,y+speed,0); + break; + case 41: + dragpoint(i,x-speed,y,0); + break; + case 40: + dragpoint(i,x,y-speed,0); + break; + case 43: + dragpoint(i,x+speed,y,0); + break; + } + } + } + else + { + speed -= 2; + for (i = startwall; i < endwall; i++) + { + int32_t x, y; + x = wall[i].x; + y = wall[i].y; + switch (wall[wallNum].lotag) + { + case 42: + dragpoint(i,x,y-speed,0); + break; + case 41: + dragpoint(i,x+speed,y,0); + break; + case 40: + dragpoint(i,x,y+speed,0); + break; + case 43: + dragpoint(i,x-speed,y,0); + break; + } + } + } +} + +void G_DoTorch(void) +{ + int j; + int startWall, endWall; + int randNum = rand()&8; + for (bsize_t i = 0; i < g_torchCnt; i++) + { + int shade = g_torchSectorShade[i] - randNum; + switch (g_torchType[i]) + { + case 0: + sector[g_torchSector[i]].floorshade = shade; + sector[g_torchSector[i]].ceilingshade = shade; + break; + case 1: + sector[g_torchSector[i]].ceilingshade = shade; + break; + case 2: + sector[g_torchSector[i]].floorshade = shade; + break; + case 4: + sector[g_torchSector[i]].ceilingshade = shade; + break; + case 5: + sector[g_torchSector[i]].floorshade = shade; + break; + } + startWall = sector[g_torchSector[i]].wallptr; + endWall = startWall + sector[g_torchSector[i]].wallnum - 1; + for (j = startWall; j <= endWall; j++) + { + if (wall[j].lotag != 1) + { + switch (g_torchType[i]) + { + case 0: + wall[j].shade = shade; + break; + case 1: + wall[j].shade = shade; + break; + case 2: + wall[j].shade = shade; + break; + case 3: + wall[j].shade = shade; + break; + } + } + } + } +} + +void G_DoJailDoor(void) +{ + int j; + int32_t speed; + int startWall, endWall; + for (bsize_t i = 0; i < g_jailDoorCnt; i++) + { + speed = g_jailDoorSpeed[i]; + if (speed < 2) + speed = 2; + + if (g_jailDoorOpen[i] == 1) + { + g_jailDoorDrag[i] -= speed; + if (g_jailDoorDrag[i] <= 0) + { + g_jailDoorDrag[i] = 0; + g_jailDoorOpen[i] = 2; + switch (g_jailDoorDir[i]) + { + case 10: + g_jailDoorDir[i] = 30; + break; + case 20: + g_jailDoorDir[i] = 40; + break; + case 30: + g_jailDoorDir[i] = 10; + break; + case 40: + g_jailDoorDir[i] = 20; + break; + } + } + else + { + startWall = sector[g_jailDoorSect[i]].wallptr; + endWall = startWall + sector[g_jailDoorSect[i]].wallnum - 1; + for (j = startWall; j <= endWall; j++) + { + int32_t x, y; + x = wall[j].x; + y = wall[j].y; + switch (g_jailDoorDir[i]) + { + case 10: + y += speed; + break; + case 20: + x -= speed; + break; + case 30: + y -= speed; + break; + case 40: + x += speed; + break; + } + dragpoint(j, x, y, 0); + } + } + } + if (g_jailDoorOpen[i] == 3) + { + g_jailDoorDrag[i] -= speed; + if (g_jailDoorDrag[i] <= 0) + { + g_jailDoorDrag[i] = 0; + g_jailDoorOpen[i] = 0; + switch (g_jailDoorDir[i]) + { + case 10: + g_jailDoorDir[i] = 30; + break; + case 20: + g_jailDoorDir[i] = 40; + break; + case 30: + g_jailDoorDir[i] = 10; + break; + case 40: + g_jailDoorDir[i] = 20; + break; + } + } + else + { + startWall = sector[g_jailDoorSect[i]].wallptr; + endWall = startWall + sector[g_jailDoorSect[i]].wallnum - 1; + for (j = startWall; j <= endWall; j++) + { + int32_t x, y; + x = wall[j].x; + y = wall[j].y; + switch (g_jailDoorDir[i]) + { + case 10: + y += speed; + break; + case 20: + x -= speed; + break; + case 30: + y -= speed; + break; + case 40: + x += speed; + break; + } + dragpoint(j, x, y, 0); + } + } + } + } +} + +void G_MoveMineCart(void) +{ + int j, nextj; + int startWall, endWall; + int32_t speed; + int32_t max_x, min_x, max_y, min_y, cx, cy; + for (bsize_t i = 0; i < g_mineCartCnt; i++) + { + speed = g_mineCartSpeed[i]; + if (speed < 2) + speed = 2; + + if (g_mineCartOpen[i] == 1) + { + g_mineCartDrag[i] -= speed; + if (g_mineCartDrag[i] <= 0) + { + g_mineCartDrag[i] = g_mineCartDist[i]; + g_mineCartOpen[i] = 2; + switch (g_mineCartDir[i]) + { + case 10: + g_mineCartDir[i] = 30; + break; + case 20: + g_mineCartDir[i] = 40; + break; + case 30: + g_mineCartDir[i] = 10; + break; + case 40: + g_mineCartDir[i] = 20; + break; + } + } + else + { + startWall = sector[g_mineCartSect[i]].wallptr; + endWall = startWall + sector[g_mineCartSect[i]].wallnum - 1; + for (j = startWall; j <= endWall; j++) + { + int32_t x, y; + x = wall[j].x; + y = wall[j].y; + switch (g_mineCartDir[i]) + { + case 10: + y += speed; + break; + case 20: + x -= speed; + break; + case 30: + y -= speed; + break; + case 40: + x += speed; + break; + } + dragpoint(j, x, y, 0); + } + } + } + if (g_mineCartOpen[i] == 2) + { + g_mineCartDrag[i] -= speed; + if (g_mineCartDrag[i] <= 0) + { + g_mineCartDrag[i] = g_mineCartDist[i]; + g_mineCartOpen[i] = 1; + switch (g_mineCartDir[i]) + { + case 10: + g_mineCartDir[i] = 30; + break; + case 20: + g_mineCartDir[i] = 40; + break; + case 30: + g_mineCartDir[i] = 10; + break; + case 40: + g_mineCartDir[i] = 20; + break; + } + } + else + { + startWall = sector[g_mineCartSect[i]].wallptr; + endWall = startWall + sector[g_mineCartSect[i]].wallnum - 1; + for (j = startWall; j <= endWall; j++) + { + int32_t x, y; + x = wall[j].x; + y = wall[j].y; + switch (g_mineCartDir[i]) + { + case 10: + y += speed; + break; + case 20: + x -= speed; + break; + case 30: + y -= speed; + break; + case 40: + x += speed; + break; + } + dragpoint(j, x, y, 0); + } + } + } + startWall = sector[g_mineCartChildSect[i]].wallptr; + endWall = startWall + sector[g_mineCartChildSect[i]].wallnum - 1; + max_x = max_y = -(2<<16); + min_x = min_y = 2<<16; + for (j = startWall; j <= endWall; j++) + { + if (max_x < wall[j].x) + max_x = wall[j].x; + if (max_y < wall[j].y) + max_y = wall[j].y; + if (min_x > wall[j].x) + min_x = wall[j].x; + if (min_y > wall[j].y) + min_y = wall[j].y; + } + cx = (max_x + min_x) >> 1; + cy = (max_y + min_y) >> 1; + j = headspritesect[g_mineCartChildSect[i]]; + vec3_t pos; + pos.x = cx; + pos.y = cy; + while (j != -1) + { + nextj = nextspritesect[j]; + pos.z = sprite[j].z; + if (A_CheckEnemySprite(&sprite[j])) + setsprite(j,&pos); + j = nextj; + } + } +} + + +void G_Thunder(void) +{ + static int32_t brightness; + int j; + int startWall, endWall; + uint8_t shade; + bsize_t i = 0; + if (!g_thunderFlash) + { + if ((gotpic[RRTILE2577>>3]&(1<<(RRTILE2577&7)))) + { + gotpic[RRTILE2577>>3] &= ~(1<<(RRTILE2577&7)); + if (tilePtr(RRTILE2577) != nullptr) // why does this on texture load state??? + { + g_visibility = 256; + if (krand2() > 65000) + { + g_thunderTime = 256; + g_thunderFlash = 1; + S_PlaySound(351+(rand()%3)); + } + } + } + else + { + brightness = 0; + g_visibility = g_player[screenpeek].ps->visibility; + } + } + else + { + g_thunderTime -= 4; + if (g_thunderTime < 0) + { + brightness = 0; + g_thunderFlash = 0; + videoSetBrightness(0); + g_visibility = g_player[screenpeek].ps->visibility; + } + } + if (!g_winderFlash) + { + if ((gotpic[RRTILE2562>>3]&(1<<(RRTILE2562&7)))) + { + gotpic[RRTILE2562>>3] &= ~(1<<(RRTILE2562&7)); + if (tilePtr(RRTILE2562) != nullptr) // why does this on texture load state??? + { + if (krand2() > 65000) + { + g_winderTime = 128; + g_winderFlash = 1; + S_PlaySound(351+(rand()%3)); + } + } + } + } + else + { + g_winderFlash -= 4; + if (g_winderTime < 0) + { + g_winderFlash = 0; + for (i = 0; i < g_lightninCnt; i++) + { + sector[g_lightninSector[i]].floorshade = g_lightninSectorShade[i]; + sector[g_lightninSector[i]].ceilingshade = g_lightninSectorShade[i]; + startWall = sector[g_lightninSector[i]].wallptr; + endWall = startWall + sector[g_lightninSector[i]].wallnum - 1; + for (j = startWall; j <= endWall; j++) + wall[j].shade = g_lightninSectorShade[i]; + } + } + } + if (g_thunderFlash == 1) + { + brightness += krand2()&4; + g_visibility = 2048; + if (brightness > 8) + brightness = 0; + videoSetBrightness(brightness); + } + if (g_winderFlash == 1) + { + if (i >= MAXTORCHSECTORS) + i = MAXTORCHSECTORS - 1; + shade = g_torchSectorShade[i]+(krand2()&8); + for (i = 0; i < g_lightninCnt; i++) + { + sector[g_lightninSector[i]].floorshade = g_lightninSectorShade[i] - shade; + sector[g_lightninSector[i]].ceilingshade = g_lightninSectorShade[i] - shade; + startWall = sector[g_lightninSector[i]].wallptr; + endWall = startWall + sector[g_lightninSector[i]].wallnum - 1; + for (j = startWall; j <= endWall; j++) + wall[j].shade = g_lightninSectorShade[i] - shade; + } + } +} + +END_DUKE_NS diff --git a/source/duke/src/sector.h b/source/duke/src/sector.h new file mode 100644 index 000000000..c6fff7d64 --- /dev/null +++ b/source/duke/src/sector.h @@ -0,0 +1,183 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef sector_h_ +#define sector_h_ + +#include "actors.h" // actor_t +#include "gamevars.h" +#include "macros.h" +#include "namesdyn.h" // for G_GetForcefieldPicnum() +#include "player.h" // playerspawn_t + +BEGIN_DUKE_NS + +#define MAXCYCLERS 1024 +#define MAXANIMATES 1024 +#define MAXANIMWALLS 512 +#define MAXANIMPOINTS 2048 + +#define VIEWSCREEN_ACTIVE_DISTANCE 8192 + +extern uint8_t g_shadedSector[MAXSECTORS]; + +typedef struct { + int16_t wallnum, tag; +} animwalltype; + +typedef struct { + // this needs to have a copy of everything related to the map/actor state + // see savegame.c + int32_t g_animateGoal[MAXANIMATES], g_animateVel[MAXANIMATES], g_animateCnt; + intptr_t g_animatePtr[MAXANIMATES]; + int32_t lockclock; + vec2_t origins[MAXANIMPOINTS]; + int32_t randomseed, g_globalRandom; + int32_t pskyidx; + + int16_t SpriteDeletionQueue[1024],g_spriteDeleteQueuePos; + int16_t g_animateSect[MAXANIMATES]; + int16_t g_cyclers[MAXCYCLERS][6]; + int16_t g_mirrorWall[64], g_mirrorSector[64], g_mirrorCount; + int16_t g_animWallCnt; + int16_t g_cloudCnt,g_cloudSect[256],g_cloudX,g_cloudY; + int16_t g_cyclerCnt; + + int32_t numsprites; + int16_t tailspritefree; + int16_t headspritesect[MAXSECTORS+1]; + int16_t headspritestat[MAXSTATUS+1]; + int16_t nextspritesect[MAXSPRITES]; + int16_t nextspritestat[MAXSPRITES]; + int16_t numsectors; + int16_t numwalls; + int16_t prevspritesect[MAXSPRITES]; + int16_t prevspritestat[MAXSPRITES]; + + uint16_t g_earthquakeTime; + int8_t g_playerSpawnCnt; + + FixedBitArray show2dsector; + + actor_t actor[MAXSPRITES]; + playerspawn_t g_playerSpawnPoints[MAXPLAYERS]; + animwalltype animwall[MAXANIMWALLS]; + usectortype sector[MAXSECTORS]; + spriteext_t spriteext[MAXSPRITES]; + uspritetype sprite[MAXSPRITES]; + uwalltype wall[MAXWALLS]; +#ifndef NEW_MAP_FORMAT + wallext_t wallext[MAXWALLS]; +#endif + intptr_t *vars[MAXGAMEVARS]; +#ifdef YAX_ENABLE + int32_t numyaxbunches; +# if !defined NEW_MAP_FORMAT + int16_t yax_bunchnum[MAXSECTORS][2]; + int16_t yax_nextwall[MAXWALLS][2]; +# endif +#endif +} mapstate_t; + +typedef struct { + mapstate_t *savedstate; +} map_t; + + +void G_ActivateBySector(int sect,int spriteNum); +int S_FindMusicSFX(int sectNum, int *sndptr); +void A_CallSound2(int soundNum, int playerNum); +int A_CallSound(int sectNum,int spriteNum); +int A_CheckHitSprite(int spriteNum,int16_t *hitSprite); +void A_DamageObject(int spriteNum,int dmgSrc); +void A_DamageWall(int spr,int dawallnum,const vec3_t *pos,int weaponNum); +int __fastcall A_FindPlayer(const spritetype *pSprite,int32_t *dist); +void G_AlignWarpElevators(void); +int CheckDoorTile(int tileNum); +int CheckBlockDoorTile(int tileNum); +void G_AnimateCamSprite(int smoothRatio); +void G_AnimateWalls(void); +int G_ActivateWarpElevators(int s,int warpDir); +int G_CheckActivatorMotion(int lotag); +void G_DoSectorAnimations(void); +void G_OperateActivators(int lotag, int playerNum); +void G_OperateForceFields(int spriteNum,int wallTag); +void G_OperateMasterSwitches(int lotag); +void G_OperateRespawns(int lotag); +void G_OperateSectors(int sectNum,int spriteNum); +void P_HandleSharedKeys(int playerNum); +int GetAnimationGoal(const int32_t *animPtr); +int isanearoperator(int lotag); +int isanunderoperator(int lotag); +int P_ActivateSwitch(int playerNum, int wallOrSprite, int nSwitchType); +void P_CheckSectors(int playerNum); +void Sect_DamageCeiling(int sectNum); +int SetAnimation(int sectNum,int32_t *animPtr,int goalVal,int animVel); +void G_DoFurniture(int wallNum, int sectNum, int playerNum); +void G_DoTorch(void); +void G_DoJailDoor(void); +void G_MoveMineCart(void); +void G_Thunder(void); + +#define FORCEFIELD_CSTAT (64+16+4+1) + +// Returns W_FORCEFIELD if wall has a forcefield overpicnum, its overpicnum else. +static inline int G_GetForcefieldPicnum(int wallNum) +{ + int tileNum = wall[wallNum].overpicnum; + if (tileNum == W_FORCEFIELD + 1 || tileNum == W_FORCEFIELD + 2) + tileNum = W_FORCEFIELD; + return tileNum; +} + +// Returns the interpolated position of the camera that the player is looking +// through (using a viewscreen). should be the player's ->newowner member. +static inline vec3_t G_GetCameraPosition(int32_t i, int32_t smoothratio) +{ + const spritetype *const cs = &sprite[i]; + const actor_t *const ca = &actor[i]; + + vec3_t cam = { ca->bpos.x + mulscale16(cs->x - ca->bpos.x, smoothratio), + ca->bpos.y + mulscale16(cs->y - ca->bpos.y, smoothratio), + ca->bpos.z + mulscale16(cs->z - ca->bpos.z, smoothratio) + }; + return cam; +} + +EXTERN_INLINE_HEADER int32_t G_CheckPlayerInSector(int32_t sect); + +#if defined sector_c_ || !defined DISABLE_INLINING + +EXTERN_INLINE int32_t G_CheckPlayerInSector(int32_t sect) +{ + int32_t i; + for (TRAVERSE_CONNECT(i)) + if ((unsigned)g_player[i].ps->i < MAXSPRITES && sprite[g_player[i].ps->i].sectnum == sect) + return i; + return -1; +} + +#endif + +END_DUKE_NS + +#endif diff --git a/source/duke/src/soundefs.h b/source/duke/src/soundefs.h new file mode 100644 index 000000000..f72481312 --- /dev/null +++ b/source/duke/src/soundefs.h @@ -0,0 +1,418 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#define KICK_HIT 0 +#define PISTOL_RICOCHET 1 +#define PISTOL_BODYHIT 2 +#define PISTOL_FIRE 3 +#define EJECT_CLIP 4 +#define INSERT_CLIP 5 +#define CHAINGUN_FIRE 6 +#define RPG_SHOOT 7 +#define POOLBALLHIT 8 +#define RPG_EXPLODE 9 +#define CAT_FIRE 10 +#define SHRINKER_FIRE 11 +#define ACTOR_SHRINKING 12 +#define PIPEBOMB_BOUNCE 13 +#define PIPEBOMB_EXPLODE 14 +#define LASERTRIP_ONWALL 15 +#define LASERTRIP_ARMING 16 +#define LASERTRIP_EXPLODE 17 +#define VENT_BUST 18 +#define GLASS_BREAKING 19 +#define GLASS_HEAVYBREAK 20 +#define SHORT_CIRCUIT 21 +#define ITEM_SPLASH 22 +#define DUKE_BREATHING 23 +#define DUKE_EXHALING 24 +#define DUKE_GASP 25 +#define SLIM_RECOG 26 +// #define ENDSEQVOL3SND1 27 +#define DUKE_URINATE 28 +#define ENDSEQVOL3SND2 29 +#define ENDSEQVOL3SND3 30 +#define DUKE_PASSWIND 32 +#define DUKE_CRACK 33 +#define SLIM_ATTACK 34 +#define SOMETHINGHITFORCE 35 +#define DUKE_DRINKING 36 +#define DUKE_KILLED1 37 +#define DUKE_GRUNT 38 +#define DUKE_HARTBEAT 39 +#define DUKE_ONWATER 40 +#define DUKE_DEAD 41 +#define DUKE_LAND 42 +#define DUKE_WALKINDUCTS 43 +#define DUKE_GLAD 44 +#define DUKE_YES 45 +#define DUKE_HEHE 46 +#define DUKE_SHUCKS 47 +#define DUKE_UNDERWATER 48 +#define DUKE_JETPACK_ON 49 +#define DUKE_JETPACK_IDLE 50 +#define DUKE_JETPACK_OFF 51 +#define LIZTROOP_GROWL 52 +#define LIZTROOP_TALK1 53 +#define LIZTROOP_TALK2 54 +#define LIZTROOP_TALK3 55 +#define DUKETALKTOBOSS 56 +#define LIZCAPT_GROWL 57 +#define LIZCAPT_TALK1 58 +#define LIZCAPT_TALK2 59 +#define LIZCAPT_TALK3 60 +#define LIZARD_BEG 61 +#define LIZARD_PAIN 62 +#define LIZARD_DEATH 63 +#define LIZARD_SPIT 64 +#define DRONE1_HISSRATTLE 65 +#define DRONE1_HISSSCREECH 66 +#define DUKE_TIP2 67 +#define FLESH_BURNING 68 +#define SQUISHED 69 +#define TELEPORTER 70 +#define ELEVATOR_ON 71 +#define DUKE_KILLED3 72 +#define ELEVATOR_OFF 73 +#define DOOR_OPERATE1 74 +#define SUBWAY 75 +#define SWITCH_ON 76 +#define FAN 77 +#define DUKE_GETWEAPON3 78 +#define FLUSH_TOILET 79 +#define HOVER_CRAFT 80 +#define EARTHQUAKE 81 +#define INTRUDER_ALERT 82 +#define END_OF_LEVEL_WARN 83 +#define ENGINE_OPERATING 84 +#define REACTOR_ON 85 +#define COMPUTER_AMBIENCE 86 +#define GEARS_GRINDING 87 +#define BUBBLE_AMBIENCE 88 +#define MACHINE_AMBIENCE 89 +#define SEWER_AMBIENCE 90 +#define WIND_AMBIENCE 91 +#define SOMETHING_DRIPPING 92 +#define STEAM_HISSING 93 +#define THEATER_BREATH 94 +#define BAR_MUSIC 95 +#define BOS1_ROAM 96 +#define BOS1_RECOG 97 +#define BOS1_ATTACK1 98 +#define BOS1_PAIN 99 +#define BOS1_DYING 100 +#define BOS2_ROAM 101 +#define BOS2_RECOG 102 +#define BOS2_ATTACK 103 +#define BOS2_PAIN 104 +#define BOS2_DYING 105 +#define GETATOMICHEALTH 106 +#define DUKE_GETWEAPON2 107 +#define BOS3_DYING 108 +#define SHOTGUN_FIRE 109 +#define PRED_ROAM 110 +#define PRED_RECOG 111 +#define PRED_ATTACK 112 +#define PRED_PAIN 113 +#define PRED_DYING 114 +#define CAPT_ROAM 115 +#define CAPT_ATTACK 116 +#define CAPT_RECOG 117 +#define CAPT_PAIN 118 +#define CAPT_DYING 119 +#define PIG_ROAM 120 +#define PIG_RECOG 121 +#define PIG_ATTACK 122 +#define PIG_PAIN 123 +#define PIG_DYING 124 +#define RECO_ROAM 125 +#define RECO_RECOG 126 +#define RECO_ATTACK 127 +#define RECO_PAIN 128 +#define RECO_DYING 129 +#define DRON_ROAM 130 +#define DRON_RECOG 131 +#define DRON_ATTACK1 132 +#define DRON_PAIN 133 +#define DRON_DYING 134 +#define COMM_ROAM 135 +#define COMM_RECOG 136 +#define COMM_ATTACK 137 +#define COMM_PAIN 138 +#define COMM_DYING 139 +#define OCTA_ROAM 140 +#define OCTA_RECOG 141 +#define OCTA_ATTACK1 142 +#define OCTA_PAIN 143 +#define OCTA_DYING 144 +#define TURR_ROAM 145 +#define TURR_RECOG 146 +#define TURR_ATTACK 147 +#define DUMPSTER_MOVE 148 +#define SLIM_DYING 149 +#define BOS3_ROAM 150 +#define BOS3_RECOG 151 +#define BOS3_ATTACK1 152 +#define BOS3_PAIN 153 +#define BOS1_ATTACK2 154 +#define COMM_SPIN 155 +#define BOS1_WALK 156 +#define DRON_ATTACK2 157 +#define THUD 158 +#define OCTA_ATTACK2 159 +#define WIERDSHOT_FLY 160 +#define TURR_PAIN 161 +#define TURR_DYING 162 +#define SLIM_ROAM 163 +#define LADY_SCREAM 164 +#define DOOR_OPERATE2 165 +#define DOOR_OPERATE3 166 +#define DOOR_OPERATE4 167 +#define BORNTOBEWILDSND 168 +#define SHOTGUN_COCK 169 +#define GENERIC_AMBIENCE1 170 +#define GENERIC_AMBIENCE2 171 +#define GENERIC_AMBIENCE3 172 +#define GENERIC_AMBIENCE4 173 +#define GENERIC_AMBIENCE5 174 +#define GENERIC_AMBIENCE6 175 +#define BOS3_ATTACK2 176 +#define GENERIC_AMBIENCE17 177 +#define GENERIC_AMBIENCE18 178 +#define GENERIC_AMBIENCE19 179 +#define GENERIC_AMBIENCE20 180 +#define GENERIC_AMBIENCE21 181 +#define GENERIC_AMBIENCE22 182 +#define SECRETLEVELSND 183 +#define GENERIC_AMBIENCE8 184 +#define GENERIC_AMBIENCE9 185 +#define GENERIC_AMBIENCE10 186 +#define GENERIC_AMBIENCE11 187 +#define GENERIC_AMBIENCE12 188 +#define GENERIC_AMBIENCE13 189 +#define GENERIC_AMBIENCE14 190 +#define GENERIC_AMBIENCE15 192 +#define GENERIC_AMBIENCE16 193 +#define FIRE_CRACKLE 194 +#define BONUS_SPEECH1 195 +#define BONUS_SPEECH2 196 +#define BONUS_SPEECH3 197 +#define PIG_CAPTURE_DUKE 198 +#define BONUS_SPEECH4 199 +#define DUKE_LAND_HURT 200 +#define DUKE_HIT_STRIPPER1 201 +#define DUKE_TIP1 202 +#define DUKE_KILLED2 203 +#define PRED_ROAM2 204 +#define PIG_ROAM2 205 +#define DUKE_GETWEAPON1 206 +#define DUKE_SEARCH2 207 +#define DUKE_CRACK2 208 +#define DUKE_SEARCH 209 +#define DUKE_GET 210 +#define DUKE_LONGTERM_PAIN 211 +#define MONITOR_ACTIVE 212 +#define NITEVISION_ONOFF 213 +#define DUKE_HIT_STRIPPER2 214 +#define DUKE_CRACK_FIRST 215 +#define DUKE_USEMEDKIT 216 +#define DUKE_TAKEPILLS 217 +#define DUKE_PISSRELIEF 218 +#define SELECT_WEAPON 219 +#define WATER_GURGLE 220 +#define DUKE_GETWEAPON4 221 +#define JIBBED_ACTOR1 222 +#define JIBBED_ACTOR2 223 +#define JIBBED_ACTOR3 224 +#define JIBBED_ACTOR4 225 +#define JIBBED_ACTOR5 226 +#define JIBBED_ACTOR6 227 +#define JIBBED_ACTOR7 228 +#define DUKE_GOTHEALTHATLOW 229 +#define BOSSTALKTODUKE 230 +#define WAR_AMBIENCE1 231 +#define WAR_AMBIENCE2 232 +#define WAR_AMBIENCE3 233 +#define WAR_AMBIENCE4 234 +#define WAR_AMBIENCE5 235 +#define WAR_AMBIENCE6 236 +#define WAR_AMBIENCE7 237 +#define WAR_AMBIENCE8 238 +#define WAR_AMBIENCE9 239 +#define WAR_AMBIENCE10 240 +#define ALIEN_TALK1 241 +#define ALIEN_TALK2 242 +#define EXITMENUSOUND 243 +#define FLY_BY 244 +#define DUKE_SCREAM 245 +#define SHRINKER_HIT 246 +#define RATTY 247 +#define INTO_MENU 248 +#define BONUSMUSIC 249 +#define DUKE_BOOBY 250 +#define DUKE_TALKTOBOSSFALL 251 +#define DUKE_LOOKINTOMIRROR 252 +#define PIG_ROAM3 253 +#define KILLME 254 +#define DRON_JETSND 255 +#define SPACE_DOOR1 256 +#define SPACE_DOOR2 257 +#define SPACE_DOOR3 258 +#define SPACE_DOOR4 259 +#define SPACE_DOOR5 260 +#define ALIEN_ELEVATOR1 261 +#define VAULT_DOOR 262 +#define JIBBED_ACTOR13 263 +#define DUKE_GETWEAPON6 264 +#define JIBBED_ACTOR8 265 +#define JIBBED_ACTOR9 266 +#define JIBBED_ACTOR10 267 +#define JIBBED_ACTOR11 268 +#define JIBBED_ACTOR12 269 +#define DUKE_KILLED4 270 +#define DUKE_KILLED5 271 +#define ALIEN_SWITCH1 272 +#define DUKE_STEPONFECES 273 +#define DUKE_LONGTERM_PAIN2 274 +#define DUKE_LONGTERM_PAIN3 275 +#define DUKE_LONGTERM_PAIN4 276 +#define COMPANB2 277 +#define KTIT 278 +#define HELICOP_IDLE 279 +#define STEPNIT 280 +#define SPACE_AMBIENCE1 281 +#define SPACE_AMBIENCE2 282 +#define SLIM_HATCH 283 +#define RIPHEADNECK 284 +#define FOUNDJONES 285 +#define ALIEN_DOOR1 286 +#define ALIEN_DOOR2 287 +#define ENDSEQVOL3SND4 288 +#define ENDSEQVOL3SND5 289 +#define ENDSEQVOL3SND6 290 +#define ENDSEQVOL3SND7 291 +#define ENDSEQVOL3SND8 292 +#define ENDSEQVOL3SND9 293 +#define WHIPYOURASS 294 +#define ENDSEQVOL2SND1 295 +#define ENDSEQVOL2SND2 296 +#define ENDSEQVOL2SND3 297 +#define ENDSEQVOL2SND4 298 +#define ENDSEQVOL2SND5 299 +#define ENDSEQVOL2SND6 300 +#define ENDSEQVOL2SND7 301 +#define GENERIC_AMBIENCE23 302 +#define SOMETHINGFROZE 303 +#define DUKE_LONGTERM_PAIN5 304 +#define DUKE_LONGTERM_PAIN6 305 +#define DUKE_LONGTERM_PAIN7 306 +#define DUKE_LONGTERM_PAIN8 307 +#define WIND_REPEAT 308 +#define MYENEMY_ROAM 309 +#define MYENEMY_HURT 310 +#define MYENEMY_DEAD 311 +#define MYENEMY_SHOOT 312 +#define STORE_MUSIC 313 +#define STORE_MUSIC_BROKE 314 +#define ACTOR_GROWING 315 +#define NEWBEAST_ROAM 316 +#define NEWBEAST_RECOG 317 +#define NEWBEAST_ATTACK 318 +#define NEWBEAST_PAIN 319 +#define NEWBEAST_DYING 320 +#define NEWBEAST_SPIT 321 +#define VOL4_1 322 +#define SUPERMARKET 323 +#define MOUSEANNOY 324 +#define BOOKEM 325 +#define SUPERMARKETCRY 326 +#define DESTRUCT 327 +#define EATFOOD 328 +#define MAKEMYDAY 329 +#define WITNESSSTAND 330 +#define VACATIONSPEECH 331 +#define YIPPEE1 332 +#define YOHOO1 333 +#define YOHOO2 334 +#define DOLPHINSND 335 +#define TOUGHGALSND1 336 +#define TOUGHGALSND2 337 +#define TOUGHGALSND3 338 +#define TOUGHGALSND4 339 +#define TANK_ROAM 340 +#define BOS4_ROAM 341 +#define BOS4_RECOG 342 +#define BOS4_ATTACK 343 +#define BOS4_PAIN 344 +#define BOS4_DYING 345 +#define NEWBEAST_ATTACKMISS 346 +#define VOL4_2 347 +#define COOKINGDEEPFRIER 348 +#define WHINING_DOG 349 +#define DEAD_DOG 350 +#define LIGHTNING_SLAP 351 +#define THUNDER 352 +#define HAPPYMOUSESND1 353 +#define HAPPYMOUSESND2 354 +#define HAPPYMOUSESND3 355 +#define HAPPYMOUSESND4 356 +#define ALARM 357 +#define RAIN 358 +#define DTAG_GREENRUN 359 +#define DTAG_BROWNRUN 360 +#define DTAG_GREENSCORE 361 +#define DTAG_BROWNSCORE 362 +#define INTRO4_1 363 +#define INTRO4_2 364 +#define INTRO4_3 365 +#define INTRO4_4 366 +#define INTRO4_5 367 +#define INTRO4_6 368 +#define SCREECH 369 +#define BOSS4_DEADSPEECH 370 +#define BOSS4_FIRSTSEE 371 +#define PARTY_SPEECH 372 +#define POSTAL_SPEECH 373 +#define TGSPEECH 374 +#define DOGROOMSPEECH 375 +#define SMACKED 376 +#define MDEVSPEECH 377 +#define AREA51SPEECH 378 +#define JEEPSOUND 379 +#define BIGDOORSLAM 380 +#define BOS4_LAY 381 +#define WAVESOUND 382 +#define ILLBEBACK 383 +#define VOL4ENDSND1 384 +#define VOL4ENDSND2 385 +#define EXPANDERHIT 386 +#define SNAKESPEECH 387 +#define EXPANDERSHOOT 388 +#define GETBACKTOWORK 389 +#define JIBBED_ACTOR14 390 +#define JIBBED_ACTOR15 391 +#define INTRO4_B 392 +#define BIGBANG 393 +#define HORNSND 394 +#define BELLSND 395 +#define GOAWAY 396 +#define JOKE 397 diff --git a/source/duke/src/sounds.cpp b/source/duke/src/sounds.cpp new file mode 100644 index 000000000..0742981ae --- /dev/null +++ b/source/duke/src/sounds.cpp @@ -0,0 +1,619 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors +Copyright (C) 2019 Christoph Oelckers + +This 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. +*/ +//------------------------------------------------------------------------- + +#include "ns.h" // Must come before everything else! + +#include "compat.h" + +#include "duke3d.h" +#include "raze_music.h" +#include "mapinfo.h" +#include "raze_sound.h" + +BEGIN_DUKE_NS + +class DukeSoundEngine : public SoundEngine +{ + // client specific parts of the sound engine go in this class. + void CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan* chan) override; + TArray ReadSound(int lumpnum) override; + +public: + DukeSoundEngine() + { + S_Rolloff.RolloffType = ROLLOFF_Doom; // Seems like Duke uses the same rolloff type as Doom. + S_Rolloff.MinDistance = 144; // was originally 576 which looks like a bug and sounds like crap. + S_Rolloff.MaxDistance = 1088; + } + + void StopChannel(FSoundChan* chan) override + { + if (chan && chan->SysChannel != NULL && !(chan->ChanFlags & CHANF_EVICTED) && chan->SourceType == SOURCE_Actor) + { + chan->Source = NULL; + chan->SourceType = SOURCE_Unattached; + } + SoundEngine::StopChannel(chan); + } + +}; + +void S_InitSound() +{ + soundEngine = new DukeSoundEngine; +} + +//========================================================================== +// +// +// +//========================================================================== + +TArray DukeSoundEngine::ReadSound(int lumpnum) +{ + auto wlump = fileSystem.OpenFileReader(lumpnum); + return wlump.Read(); +} + +//========================================================================== +// +// +// +//========================================================================== + +void cacheAllSounds(void) +{ + auto& sfx = soundEngine->GetSounds(); + int i = 0; + for(auto &snd : sfx) + { + soundEngine->CacheSound(&snd); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +static inline int S_GetPitch(int num) +{ + auto const* snd = soundEngine->GetUserData(num+1); + if (!snd) return 0; + int const range = abs(snd[kPitchEnd] - snd[kPitchStart]); + return (range == 0) ? snd[kPitchStart] : min(snd[kPitchStart], snd[kPitchEnd]) + rand() % range; +} + +float S_ConvertPitch(int lpitch) +{ + return pow(2, lpitch / 1200.); // I hope I got this right that ASS uses a linear scale where 1200 is a full octave. +} + +int S_GetUserFlags(int num) +{ + if (!soundEngine->isValidSoundId(num+1)) return 0; + auto const* snd = soundEngine->GetUserData(num + 1); + if (!snd) return 0; + return snd[kFlags]; +} + +//========================================================================== +// +// +// +//========================================================================== + +int S_DefineSound(unsigned index, const char *filename, int minpitch, int maxpitch, int priority, int type, int distance, float volume) +{ + if ((unsigned)index >= MAXSOUNDS) + return -1; + + auto& S_sfx = soundEngine->GetSounds(); + index++; + unsigned oldindex = S_sfx.Size(); + if (index >= S_sfx.Size()) + { + S_sfx.Resize(index + 1); + for (; oldindex <= index; oldindex++) + { + S_sfx[oldindex].Clear(); + } + } + auto sfx = &S_sfx[index]; + bool alreadydefined = !sfx->bTentative; + sfx->UserData.Resize(kMaxUserData); + auto sndinf = sfx->UserData.Data(); + sndinf[kFlags] = type & ~SF_ONEINST_INTERNAL; + if (sndinf[kFlags] & SF_LOOP) + sndinf[kFlags] |= SF_ONEINST_INTERNAL; + + sfx->lumpnum = S_LookupSound(filename); + sndinf[kPitchStart] = clamp(minpitch, INT16_MIN, INT16_MAX); + sndinf[kPitchEnd] = clamp(maxpitch, INT16_MIN, INT16_MAX); + sndinf[kPriority] = priority & 255; + sndinf[kVolAdjust] = clamp(distance, INT16_MIN, INT16_MAX); + sfx->Volume = volume; + sfx->NearLimit = 6; + sfx->bTentative = false; + sfx->name = filename; + return 0; +} + + +//========================================================================== +// +// +// +//========================================================================== + +static int S_CalcDistAndAng(int spriteNum, int soundNum, int sectNum, + const vec3_t *cam, const vec3_t *pos, int *distPtr, FVector3 *sndPos) +{ + // There's a lot of hackery going on here that could be mapped to rolloff and attenuation parameters. + // However, ultimately rolloff would also just reposition the sound source so this can remain as it is. + + int orgsndist = 0, sndang = 0, sndist = 0, explosion = 0; + auto const* snd = soundEngine->GetUserData(soundNum + 1); + int userflags = snd ? snd[kFlags] : 0; + int dist_adjust = snd ? snd[kVolAdjust] : 0; + + if (PN(spriteNum) != APLAYER || P_Get(spriteNum) != screenpeek) + { + orgsndist = sndist = FindDistance3D(cam->x - pos->x, cam->y - pos->y, (cam->z - pos->z)); + + if ((userflags & (SF_GLOBAL | SF_DTAG)) != SF_GLOBAL && S_IsAmbientSFX(spriteNum) && (sector[SECT(spriteNum)].lotag & 0xff) < 9) // ST_9_SLIDING_ST_DOOR + sndist = divscale14(sndist, SHT(spriteNum) + 1); + } + + sndist += dist_adjust; + if (sndist < 0) + sndist = 0; + + if (sectNum > -1 && sndist && PN(spriteNum) != MUSICANDSFX + && !cansee(cam->x, cam->y, cam->z - (24 << 8), sectNum, SX(spriteNum), SY(spriteNum), SZ(spriteNum) - (24 << 8), SECT(spriteNum))) + sndist += sndist>>(RR?2:5); + + // Here the sound distance was clamped to a minimum of 144*4. + // It's better to handle rolloff in the backend instead of whacking the sound origin here. + // That way the lower end can be made customizable instead of losing all precision right here at the source. + if (sndist < 0) sndist = 0; + + if (distPtr) + { + *distPtr = sndist; + } + + if (sndPos) + { + FVector3 sndorg = GetSoundPos(pos); + FVector3 campos = GetSoundPos(cam); + // Now calculate the virtual position in sound system coordinates. + FVector3 sndvec = sndorg - campos; + if (orgsndist > 0) + { + float scale = float(sndist) / orgsndist; // adjust by what was calculated above; + *sndPos = campos + sndvec * scale; + } + else *sndPos = campos; + } + + return false; +} + +//========================================================================== +// +// +// +//========================================================================== + +void S_GetCamera(vec3_t** c, int32_t* ca, int32_t* cs) +{ + if (ud.camerasprite == -1) + { + if (ud.overhead_on != 2) + { + if (c) *c = &CAMERA(pos); + if (cs) *cs = CAMERA(sect); + if (ca) *ca = fix16_to_int(CAMERA(q16ang)); + } + else + { + auto pPlayer = g_player[screenpeek].ps; + if (c) *c = &pPlayer->pos; + if (cs) *cs = pPlayer->cursectnum; + if (ca) *ca = fix16_to_int(pPlayer->q16ang); + } + } + else + { + if (c) *c = &sprite[ud.camerasprite].pos; + if (cs) *cs = sprite[ud.camerasprite].sectnum; + if (ca) *ca = sprite[ud.camerasprite].ang; + } +} + +//========================================================================= +// +// CalcPosVel +// +// The game specific part of the sound updater. +// +//========================================================================= + +void DukeSoundEngine::CalcPosVel(int type, const void* source, const float pt[3], int channum, int chanflags, FSoundID chanSound, FVector3* pos, FVector3* vel, FSoundChan* chan) +{ + if (pos != nullptr) + { + vec3_t* campos; + int32_t camsect; + + S_GetCamera(&campos, nullptr, &camsect); + if (vel) vel->Zero(); + + if (type == SOURCE_Unattached) + { + pos->X = pt[0]; + pos->Y = pt[1]; + pos->Z = pt[2]; + } + else if (type == SOURCE_Actor) + { + auto actor = (spritetype*)source; + assert(actor != nullptr); + if (actor != nullptr) + { + S_CalcDistAndAng(int(actor - sprite), chanSound - 1, camsect, campos, &actor->pos, nullptr, pos); + /* + if (vel) // DN3D does not properly maintain this. + { + vel->X = float(actor->Vel.X * TICRATE); + vel->Y = float(actor->Vel.Z * TICRATE); + vel->Z = float(actor->Vel.Y * TICRATE); + } + */ + } + } + if ((chanflags & CHANF_LISTENERZ) && campos != nullptr && type != SOURCE_None) + { + pos->Y = campos->z / 256.f; + } + } +} + + +//========================================================================== +// +// +// +//========================================================================== + +void S_Update(void) +{ + SoundListener listener; + vec3_t* c; + int32_t ca, cs; + + auto& gm = g_player[myconnectindex].ps->gm; + if (RR && !Mus_IsPlaying() && (gm && gm & MODE_GAME)) + S_PlayRRMusic(); + + S_GetCamera(&c, &ca, &cs); + + if (c != nullptr) + { + listener.angle = -(float)ca * pi::pi() / 1024; // Build uses a period of 2048. + listener.velocity.Zero(); + listener.position = GetSoundPos(c); + listener.underwater = false; + // This should probably use a real environment instead of the pitch hacking in S_PlaySound3D. + // listenactor->waterlevel == 3; + //assert(primaryLevel->Zones.Size() > listenactor->Sector->ZoneNumber); + listener.Environment = 0;// primaryLevel->Zones[listenactor->Sector->ZoneNumber].Environment; + listener.valid = true; + } + else + { + listener.angle = 0; + listener.position.Zero(); + listener.velocity.Zero(); + listener.underwater = false; + listener.Environment = nullptr; + listener.valid = false; + } + listener.ListenerObject = ud.camerasprite == -1 ? nullptr : &sprite[ud.camerasprite]; + soundEngine->SetListener(listener); + soundEngine->UpdateSounds((int)totalclock); +} + + +//========================================================================== +// +// +// +//========================================================================== + +int S_PlaySound3D(int sndnum, int spriteNum, const vec3_t* pos, int channel, EChanFlags flags) +{ + auto const pPlayer = g_player[myconnectindex].ps; + if (!soundEngine->isValidSoundId(sndnum+1) || !SoundEnabled() || (unsigned)spriteNum >= MAXSPRITES || (pPlayer->gm & MODE_MENU) || + (pPlayer->timebeforeexit > 0 && pPlayer->timebeforeexit <= GAMETICSPERSEC * 3)) return -1; + + int userflags = S_GetUserFlags(sndnum); + if ((!(snd_speech & 1) && (userflags & SF_TALK)) || ((userflags & SF_ADULT) && adult_lockout)) + return -1; + + // Duke talk + if (userflags & SF_TALK) + { + if ((g_netServer || ud.multimode > 1) && PN(spriteNum) == APLAYER && P_Get(spriteNum) != screenpeek) // other player sound + { + if ((snd_speech & 4) != 4) + return -1; + } + else if ((snd_speech & 1) != 1) + return -1; + + + bool foundone = soundEngine->EnumerateChannels([&](FSoundChan* chan) + { + auto sid = chan->OrgID; + auto flags = S_GetUserFlags(sid - 1); + return !!(flags & SF_TALK); + }); + // don't play if any Duke talk sounds are already playing + if (foundone) return -1; + } + else if ((userflags & (SF_DTAG | SF_GLOBAL)) == SF_DTAG) // Duke-Tag sound + { + return S_PlaySound(sndnum); + + } + + int32_t sndist; + FVector3 sndpos; // this is in sound engine space. + + vec3_t* campos; + int32_t camsect; + + S_GetCamera(&campos, nullptr, &camsect); + S_CalcDistAndAng(spriteNum, sndnum, camsect, campos, pos, &sndist, &sndpos); + int pitch = S_GetPitch(sndnum); + auto const pOther = g_player[screenpeek].ps; + + + if (pOther->sound_pitch) + pitch += pOther->sound_pitch; + + bool explosionp = ((userflags & (SF_GLOBAL | SF_DTAG)) == (SF_GLOBAL | SF_DTAG)) || ((sndnum == PIPEBOMB_EXPLODE || sndnum == LASERTRIP_EXPLODE || sndnum == RPG_EXPLODE)); + + if (explosionp) + { + if (pOther->cursectnum > -1 && sector[pOther->cursectnum].lotag == ST_2_UNDERWATER) + pitch -= 1024; + } + else + { + if (sndist > 32767 && PN(spriteNum) != MUSICANDSFX && (userflags & (SF_LOOP | SF_MSFX)) == 0) + return -1; + + if (pOther->cursectnum > -1 && sector[pOther->cursectnum].lotag == ST_2_UNDERWATER + && (userflags & SF_TALK) == 0) + pitch = -768; + } + + bool is_playing = soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, sndnum+1); + if (is_playing && PN(spriteNum) != MUSICANDSFX) + S_StopEnvSound(sndnum, spriteNum); + + int const repeatp = (userflags & SF_LOOP); + + if (repeatp && (userflags & SF_ONEINST_INTERNAL) && is_playing) + { + return -1; + } + + // These explosion sounds originally used some distance hackery to make them louder but due to how the rolloff was set up they always played at full volume as a result. + // I think it is better to lower their attenuation so that they are louder than the rest but still fade in the distance. + // For the original effect, attenuation needs to be set to ATTN_NONE here. + float attenuation; + if (explosionp) attenuation = 0.5f; + else attenuation = (userflags & (SF_GLOBAL | SF_DTAG)) == SF_GLOBAL ? ATTN_NONE : ATTN_NORM; + + if (userflags & SF_LOOP) flags |= CHANF_LOOP; + auto chan = soundEngine->StartSound(SOURCE_Actor, &sprite[spriteNum], &sndpos, CHAN_AUTO, flags, sndnum+1, attenuation == ATTN_NONE? 0.8f : 1.f, attenuation, nullptr, S_ConvertPitch(pitch)); + return chan ? 0 : -1; +} + +//========================================================================== +// +// +// +//========================================================================== + +int S_PlaySound(int sndnum, int channel, EChanFlags flags) +{ + if (!soundEngine->isValidSoundId(sndnum+1) || !SoundEnabled()) return -1; + + int userflags = S_GetUserFlags(sndnum); + if ((!(snd_speech & 1) && (userflags & SF_TALK)) || ((userflags & SF_ADULT) && adult_lockout)) + return -1; + + int const pitch = S_GetPitch(sndnum); + + if (userflags & SF_LOOP) flags |= CHANF_LOOP; + auto chan = soundEngine->StartSound(SOURCE_None, nullptr, nullptr, channel, flags, sndnum + 1, 0.8f, ATTN_NONE, nullptr, S_ConvertPitch(pitch)); + return chan ? 0 : -1; +} + +//========================================================================== +// +// +// +//========================================================================== + +int A_PlaySound(int soundNum, int spriteNum, int channel, EChanFlags flags) +{ + return (unsigned)spriteNum >= MAXSPRITES ? S_PlaySound(soundNum, channel, flags) : + S_PlaySound3D(soundNum, spriteNum, &sprite[spriteNum].pos, channel, flags); +} + +void S_StopEnvSound(int sndNum, int sprNum, int channel) +{ + if (sprNum < -1 || sprNum >= MAXSPRITES) return; + + if (sprNum == -1) soundEngine->StopSoundID(sndNum+1); + else + { + if (channel == -1) soundEngine->StopSound(SOURCE_Actor, &sprite[sprNum], -1, sndNum + 1); + else soundEngine->StopSound(SOURCE_Actor, &sprite[sprNum], channel, -1); + + // StopSound kills the actor reference so this cannot be delayed until ChannelEnded gets called. At that point the actor may also not be valid anymore. + if (S_IsAmbientSFX(sprNum) && sector[SECT(sprNum)].lotag < 3) // ST_2_UNDERWATER + actor[sprNum].t_data[0] = 0; + } +} + +void S_ChangeSoundPitch(int soundNum, int spriteNum, int pitchoffset) +{ + if (spriteNum < -1 || spriteNum >= MAXSPRITES) return; + double expitch = pow(2, pitchoffset / 1200.); // I hope I got this right that ASS uses a linear scale where 1200 is a full octave. + if (spriteNum == -1) + { + soundEngine->ChangeSoundPitch(SOURCE_Unattached, nullptr, CHAN_AUTO, expitch, soundNum+1); + } + else + { + soundEngine->ChangeSoundPitch(SOURCE_Actor, &sprite[spriteNum], CHAN_AUTO, expitch, soundNum+1); + } +} + +//========================================================================== +// +// +// +//========================================================================== + +int A_CheckSoundPlaying(int spriteNum, int soundNum, int channel) +{ + if (spriteNum == -1) return soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, soundNum+1); + if ((unsigned)spriteNum >= MAXSPRITES) return false; + return soundEngine->IsSourcePlayingSomething(SOURCE_Actor, &sprite[spriteNum], channel, soundNum+1); +} + +// Check if actor is playing any sound. +int A_CheckAnySoundPlaying(int spriteNum) +{ + if ((unsigned)spriteNum >= MAXSPRITES) return false; + return soundEngine->IsSourcePlayingSomething(SOURCE_Actor, &sprite[spriteNum], CHAN_AUTO, 0); +} + +int S_CheckSoundPlaying(int soundNum) +{ + return soundEngine->GetSoundPlayingInfo(SOURCE_Any, nullptr, soundNum+1); +} + +//========================================================================== +// +// +// +//========================================================================== + +void S_MenuSound(void) +{ + static int SoundNum; + int const menusnds[] = { + LASERTRIP_EXPLODE, DUKE_GRUNT, DUKE_LAND_HURT, CHAINGUN_FIRE, SQUISHED, KICK_HIT, + PISTOL_RICOCHET, PISTOL_BODYHIT, PISTOL_FIRE, SHOTGUN_FIRE, BOS1_WALK, RPG_EXPLODE, + PIPEBOMB_BOUNCE, PIPEBOMB_EXPLODE, NITEVISION_ONOFF, RPG_SHOOT, SELECT_WEAPON, + }; + int s = RR ? 390 : menusnds[SoundNum++ % ARRAY_SIZE(menusnds)]; + if (s != -1) + S_PlaySound(s, CHAN_AUTO, CHANF_UI); +} + +//========================================================================== +// +// Music +// +//========================================================================== + +static bool cd_disabled = false; // This is in case mus_redbook is enabled but no tracks found so that the regular music system can be switched on. + +static void S_SetMusicIndex(unsigned int m) +{ + ud.music_episode = m / MAXLEVELS; + ud.music_level = m % MAXLEVELS; +} + +void S_PlayLevelMusicOrNothing(unsigned int m) +{ + auto& mr = m == USERMAPMUSICFAKESLOT ? userMapRecord : mapList[m]; + if (RR && mr.music.IsEmpty() && mus_redbook && !cd_disabled) return; + Mus_Play(mr.labelName, mr.music, true); + S_SetMusicIndex(m); +} + +int S_TryPlaySpecialMusic(unsigned int m) +{ + if (RR) return 0; // Can only be MUS_LOADING, RR does not use it. + auto& musicfn = mapList[m].music; + if (musicfn.IsNotEmpty()) + { + if (!Mus_Play(nullptr, musicfn, true)) + { + S_SetMusicIndex(m); + return 0; + } + } + + return 1; +} + +void S_PlaySpecialMusicOrNothing(unsigned int m) +{ + if (S_TryPlaySpecialMusic(m)) + { + S_SetMusicIndex(m); + } +} + +void S_PlayRRMusic(int newTrack) +{ + if (!RR || !mus_redbook || cd_disabled || currentLevel->music.IsNotEmpty()) + return; + Mus_Stop(); + + for (int i = 0; i < 10; i++) + { + g_cdTrack = newTrack != -1 ? newTrack : g_cdTrack + 1; + if (newTrack != 10 && (g_cdTrack > 9 || g_cdTrack < 2)) + g_cdTrack = 2; + + FStringf filename("track%02d.ogg", g_cdTrack); + if (Mus_Play(nullptr, filename, false)) return; + } + // If none of the tracks managed to start, disable the CD music for this session so that regular music can play if defined. + cd_disabled = true; +} + + +END_DUKE_NS diff --git a/source/duke/src/sounds.h b/source/duke/src/sounds.h new file mode 100644 index 000000000..e5a8d2e2a --- /dev/null +++ b/source/duke/src/sounds.h @@ -0,0 +1,80 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2010 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +//**************************************************************************** +// +// sounds.h +// +//**************************************************************************** + +#ifndef sounds_public_h_ +#define sounds_public_h_ + +#include "sounds_common.h" +#include "raze_sound.h" +#include "raze_music.h" + +BEGIN_DUKE_NS + +#define MAXSOUNDS 4096 +#define LOUDESTVOLUME 111 + +enum esound_t +{ + kPitchStart, + kPitchEnd, + kVolAdjust, + kPriority, + kFlags, + kMaxUserData +}; + +int A_CheckSoundPlaying(int spriteNum, int soundNum, int channel = 0); +int A_PlaySound(int soundNum, int spriteNum, int channel = CHAN_AUTO, EChanFlags flags = 0); +int A_CheckAnySoundPlaying(int spriteNum); +int S_CheckSoundPlaying(int soundNum); +inline int S_CheckSoundPlaying(int sprnum, int soundNum) { return S_CheckSoundPlaying(soundNum); } +inline void S_ClearSoundLocks(void) {} +void cacheAllSounds(void); +void S_MenuSound(void); +void S_PlayLevelMusicOrNothing(unsigned int); +int S_TryPlaySpecialMusic(unsigned int); +void S_PlaySpecialMusicOrNothing(unsigned int); +void S_ContinueLevelMusic(void); +int S_PlaySound(int num, int channel = CHAN_AUTO, EChanFlags flags = 0); +int S_PlaySound3D(int num, int spriteNum, const vec3_t *pos, int channel = CHAN_AUTO, EChanFlags flags = 0); +void S_StopEnvSound(int sndNum,int sprNum, int flags = -1); +void S_Update(void); +void S_ChangeSoundPitch(int soundNum, int spriteNum, int pitchoffset); +int S_GetUserFlags(int sndnum); +int S_DefineSound(unsigned index, const char* filename, int ps, int pe, int pr, int m, int vo, float vol); +void S_InitSound(); +void S_PlayRRMusic(int newTrack = -1); + +static inline bool S_IsAmbientSFX(int spriteNum) +{ + return (sprite[spriteNum].picnum == MUSICANDSFX && sprite[spriteNum].lotag < 999); +} + +END_DUKE_NS + +#endif diff --git a/source/duke/src/sounds_common.h b/source/duke/src/sounds_common.h new file mode 100644 index 000000000..5c0dae7ff --- /dev/null +++ b/source/duke/src/sounds_common.h @@ -0,0 +1,38 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2013 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#ifndef EDUKE32_SOUNDS_COMMON_H +#define EDUKE32_SOUNDS_COMMON_H + +// Sound flags +enum { + SF_LOOP = 1, + SF_MSFX = 2, + SF_TALK = 4, + SF_ADULT = 8, + SF_GLOBAL = 16, + SF_ONEINST_INTERNAL = 32, + + SF_DTAG = 128, +}; + +#endif diff --git a/source/duke/src/soundsdyn.cpp b/source/duke/src/soundsdyn.cpp new file mode 100644 index 000000000..10c29d2a0 --- /dev/null +++ b/source/duke/src/soundsdyn.cpp @@ -0,0 +1,386 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2013 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- +#include "ns.h" // Must come before everything else! + +#include "compat.h" +#include "build.h" + +#include "namesdyn.h" +#include "sounds.h" +#include "soundsdyn.h" +#include "global.h" + +BEGIN_DUKE_NS + +#ifdef DYNSOUNDREMAP_ENABLE +# define DVPTR(x) &x +#else +# define DVPTR(x) NULL +#endif + +int16_t DynamicSoundMap[MAXSOUNDS]; + +struct sdynitem +{ + const char *str; + int32_t *dynvalptr; + const int16_t staticval; +}; + +static struct sdynitem g_dynSoundList[] = +{ + { "KICK_HIT", DVPTR(KICK_HIT), KICK_HIT__STATIC }, + { "PISTOL_RICOCHET", DVPTR(PISTOL_RICOCHET), PISTOL_RICOCHET__STATIC }, + { "PISTOL_BODYHIT", DVPTR(PISTOL_BODYHIT), PISTOL_BODYHIT__STATIC }, + { "PISTOL_FIRE", DVPTR(PISTOL_FIRE), PISTOL_FIRE__STATIC }, + { "EJECT_CLIP", DVPTR(EJECT_CLIP), EJECT_CLIP__STATIC }, + { "INSERT_CLIP", DVPTR(INSERT_CLIP), INSERT_CLIP__STATIC }, + { "CHAINGUN_FIRE", DVPTR(CHAINGUN_FIRE), CHAINGUN_FIRE__STATIC }, + { "RPG_SHOOT", DVPTR(RPG_SHOOT), RPG_SHOOT__STATIC }, + { "POOLBALLHIT", DVPTR(POOLBALLHIT), POOLBALLHIT__STATIC }, + { "RPG_EXPLODE", DVPTR(RPG_EXPLODE), RPG_EXPLODE__STATIC }, + { "CAT_FIRE", DVPTR(CAT_FIRE), CAT_FIRE__STATIC }, + { "SHRINKER_FIRE", DVPTR(SHRINKER_FIRE), SHRINKER_FIRE__STATIC }, + { "PIPEBOMB_BOUNCE", DVPTR(PIPEBOMB_BOUNCE), PIPEBOMB_BOUNCE__STATIC }, + { "PIPEBOMB_EXPLODE", DVPTR(PIPEBOMB_EXPLODE), PIPEBOMB_EXPLODE__STATIC }, + { "LASERTRIP_ONWALL", DVPTR(LASERTRIP_ONWALL), LASERTRIP_ONWALL__STATIC }, + { "LASERTRIP_ARMING", DVPTR(LASERTRIP_ARMING), LASERTRIP_ARMING__STATIC }, + { "LASERTRIP_EXPLODE", DVPTR(LASERTRIP_EXPLODE), LASERTRIP_EXPLODE__STATIC }, + { "VENT_BUST", DVPTR(VENT_BUST), VENT_BUST__STATIC }, + { "GLASS_BREAKING", DVPTR(GLASS_BREAKING), GLASS_BREAKING__STATIC }, + { "GLASS_HEAVYBREAK", DVPTR(GLASS_HEAVYBREAK), GLASS_HEAVYBREAK__STATIC }, + { "SHORT_CIRCUIT", DVPTR(SHORT_CIRCUIT), SHORT_CIRCUIT__STATIC }, + { "ITEM_SPLASH", DVPTR(ITEM_SPLASH), ITEM_SPLASH__STATIC }, + { "DUKE_GASP", DVPTR(DUKE_GASP), DUKE_GASP__STATIC }, + { "SLIM_RECOG", DVPTR(SLIM_RECOG), SLIM_RECOG__STATIC }, + { "DUKE_URINATE", DVPTR(DUKE_URINATE), DUKE_URINATE__STATIC }, + { "ENDSEQVOL3SND2", DVPTR(ENDSEQVOL3SND2), ENDSEQVOL3SND2__STATIC }, + { "ENDSEQVOL3SND3", DVPTR(ENDSEQVOL3SND3), ENDSEQVOL3SND3__STATIC }, + { "DUKE_CRACK", DVPTR(DUKE_CRACK), DUKE_CRACK__STATIC }, + { "SLIM_ATTACK", DVPTR(SLIM_ATTACK), SLIM_ATTACK__STATIC }, + { "SOMETHINGHITFORCE", DVPTR(SOMETHINGHITFORCE), SOMETHINGHITFORCE__STATIC }, + { "DUKE_DRINKING", DVPTR(DUKE_DRINKING), DUKE_DRINKING__STATIC }, + { "DUKE_GRUNT", DVPTR(DUKE_GRUNT), DUKE_GRUNT__STATIC }, + { "DUKE_HARTBEAT", DVPTR(DUKE_HARTBEAT), DUKE_HARTBEAT__STATIC }, + { "DUKE_ONWATER", DVPTR(DUKE_ONWATER), DUKE_ONWATER__STATIC }, + { "DUKE_LAND", DVPTR(DUKE_LAND), DUKE_LAND__STATIC }, + { "DUKE_WALKINDUCTS", DVPTR(DUKE_WALKINDUCTS), DUKE_WALKINDUCTS__STATIC }, + { "DUKE_UNDERWATER", DVPTR(DUKE_UNDERWATER), DUKE_UNDERWATER__STATIC }, + { "DUKE_JETPACK_ON", DVPTR(DUKE_JETPACK_ON), DUKE_JETPACK_ON__STATIC }, + { "DUKE_JETPACK_IDLE", DVPTR(DUKE_JETPACK_IDLE), DUKE_JETPACK_IDLE__STATIC }, + { "DUKE_JETPACK_OFF", DVPTR(DUKE_JETPACK_OFF), DUKE_JETPACK_OFF__STATIC }, + { "DUKETALKTOBOSS", DVPTR(DUKETALKTOBOSS), DUKETALKTOBOSS__STATIC }, + { "SQUISHED", DVPTR(SQUISHED), SQUISHED__STATIC }, + { "TELEPORTER", DVPTR(TELEPORTER), TELEPORTER__STATIC }, + { "ELEVATOR_ON", DVPTR(ELEVATOR_ON), ELEVATOR_ON__STATIC }, + { "ELEVATOR_OFF", DVPTR(ELEVATOR_OFF), ELEVATOR_OFF__STATIC }, + { "SUBWAY", DVPTR(SUBWAY), SUBWAY__STATIC }, + { "SWITCH_ON", DVPTR(SWITCH_ON), SWITCH_ON__STATIC }, + { "FLUSH_TOILET", DVPTR(FLUSH_TOILET), FLUSH_TOILET__STATIC }, + { "EARTHQUAKE", DVPTR(EARTHQUAKE), EARTHQUAKE__STATIC }, + { "END_OF_LEVEL_WARN", DVPTR(END_OF_LEVEL_WARN), END_OF_LEVEL_WARN__STATIC }, + { "WIND_AMBIENCE", DVPTR(WIND_AMBIENCE), WIND_AMBIENCE__STATIC }, + { "SOMETHING_DRIPPING", DVPTR(SOMETHING_DRIPPING), SOMETHING_DRIPPING__STATIC }, + { "BOS1_RECOG", DVPTR(BOS1_RECOG), BOS1_RECOG__STATIC }, + { "BOS2_RECOG", DVPTR(BOS2_RECOG), BOS2_RECOG__STATIC }, + { "DUKE_GETWEAPON2", DVPTR(DUKE_GETWEAPON2), DUKE_GETWEAPON2__STATIC }, + { "SHOTGUN_FIRE", DVPTR(SHOTGUN_FIRE), SHOTGUN_FIRE__STATIC }, + { "PRED_RECOG", DVPTR(PRED_RECOG), PRED_RECOG__STATIC }, + { "CAPT_RECOG", DVPTR(CAPT_RECOG), CAPT_RECOG__STATIC }, + { "PIG_RECOG", DVPTR(PIG_RECOG), PIG_RECOG__STATIC }, + { "RECO_ROAM", DVPTR(RECO_ROAM), RECO_ROAM__STATIC }, + { "RECO_RECOG", DVPTR(RECO_RECOG), RECO_RECOG__STATIC }, + { "RECO_ATTACK", DVPTR(RECO_ATTACK), RECO_ATTACK__STATIC }, + { "RECO_PAIN", DVPTR(RECO_PAIN), RECO_PAIN__STATIC }, + { "DRON_RECOG", DVPTR(DRON_RECOG), DRON_RECOG__STATIC }, + { "COMM_RECOG", DVPTR(COMM_RECOG), COMM_RECOG__STATIC }, + { "OCTA_RECOG", DVPTR(OCTA_RECOG), OCTA_RECOG__STATIC }, + { "TURR_RECOG", DVPTR(TURR_RECOG), TURR_RECOG__STATIC }, + { "SLIM_DYING", DVPTR(SLIM_DYING), SLIM_DYING__STATIC }, + { "BOS3_RECOG", DVPTR(BOS3_RECOG), BOS3_RECOG__STATIC }, + { "BOS1_WALK", DVPTR(BOS1_WALK), BOS1_WALK__STATIC }, + { "THUD", DVPTR(THUD), THUD__STATIC }, + { "WIERDSHOT_FLY", DVPTR(WIERDSHOT_FLY), WIERDSHOT_FLY__STATIC }, + { "SLIM_ROAM", DVPTR(SLIM_ROAM), SLIM_ROAM__STATIC }, + { "SHOTGUN_COCK", DVPTR(SHOTGUN_COCK), SHOTGUN_COCK__STATIC }, + { "GENERIC_AMBIENCE17", DVPTR(GENERIC_AMBIENCE17), GENERIC_AMBIENCE17__STATIC }, + { "BONUS_SPEECH1", DVPTR(BONUS_SPEECH1), BONUS_SPEECH1__STATIC }, + { "BONUS_SPEECH2", DVPTR(BONUS_SPEECH2), BONUS_SPEECH2__STATIC }, + { "BONUS_SPEECH3", DVPTR(BONUS_SPEECH3), BONUS_SPEECH3__STATIC }, + { "BONUS_SPEECH4", DVPTR(BONUS_SPEECH4), BONUS_SPEECH4__STATIC }, + { "DUKE_LAND_HURT", DVPTR(DUKE_LAND_HURT), DUKE_LAND_HURT__STATIC }, + { "DUKE_SEARCH2", DVPTR(DUKE_SEARCH2), DUKE_SEARCH2__STATIC }, + { "DUKE_CRACK2", DVPTR(DUKE_CRACK2), DUKE_CRACK2__STATIC }, + { "DUKE_SEARCH", DVPTR(DUKE_SEARCH), DUKE_SEARCH__STATIC }, + { "DUKE_GET", DVPTR(DUKE_GET), DUKE_GET__STATIC }, + { "DUKE_LONGTERM_PAIN", DVPTR(DUKE_LONGTERM_PAIN), DUKE_LONGTERM_PAIN__STATIC }, + { "MONITOR_ACTIVE", DVPTR(MONITOR_ACTIVE), MONITOR_ACTIVE__STATIC }, + { "NITEVISION_ONOFF", DVPTR(NITEVISION_ONOFF), NITEVISION_ONOFF__STATIC }, + { "DUKE_CRACK_FIRST", DVPTR(DUKE_CRACK_FIRST), DUKE_CRACK_FIRST__STATIC }, + { "DUKE_USEMEDKIT", DVPTR(DUKE_USEMEDKIT), DUKE_USEMEDKIT__STATIC }, + { "DUKE_TAKEPILLS", DVPTR(DUKE_TAKEPILLS), DUKE_TAKEPILLS__STATIC }, + { "DUKE_PISSRELIEF", DVPTR(DUKE_PISSRELIEF), DUKE_PISSRELIEF__STATIC }, + { "SELECT_WEAPON", DVPTR(SELECT_WEAPON), SELECT_WEAPON__STATIC }, + { "JIBBED_ACTOR5", DVPTR(JIBBED_ACTOR5), JIBBED_ACTOR5__STATIC }, + { "JIBBED_ACTOR6", DVPTR(JIBBED_ACTOR6), JIBBED_ACTOR6__STATIC }, + { "DUKE_GOTHEALTHATLOW", DVPTR(DUKE_GOTHEALTHATLOW), DUKE_GOTHEALTHATLOW__STATIC }, + { "BOSSTALKTODUKE", DVPTR(BOSSTALKTODUKE), BOSSTALKTODUKE__STATIC }, + { "WAR_AMBIENCE2", DVPTR(WAR_AMBIENCE2), WAR_AMBIENCE2__STATIC }, + { "EXITMENUSOUND", DVPTR(EXITMENUSOUND), EXITMENUSOUND__STATIC }, + { "FLY_BY", DVPTR(FLY_BY), FLY_BY__STATIC }, + { "DUKE_SCREAM", DVPTR(DUKE_SCREAM), DUKE_SCREAM__STATIC }, + { "SHRINKER_HIT", DVPTR(SHRINKER_HIT), SHRINKER_HIT__STATIC }, + { "RATTY", DVPTR(RATTY), RATTY__STATIC }, + { "BONUSMUSIC", DVPTR(BONUSMUSIC), BONUSMUSIC__STATIC }, + { "DUKE_GETWEAPON6", DVPTR(DUKE_GETWEAPON6), DUKE_GETWEAPON6__STATIC }, + { "ALIEN_SWITCH1", DVPTR(ALIEN_SWITCH1), ALIEN_SWITCH1__STATIC }, + { "RIPHEADNECK", DVPTR(RIPHEADNECK), RIPHEADNECK__STATIC }, + { "ENDSEQVOL3SND4", DVPTR(ENDSEQVOL3SND4), ENDSEQVOL3SND4__STATIC }, + { "ENDSEQVOL3SND5", DVPTR(ENDSEQVOL3SND5), ENDSEQVOL3SND5__STATIC }, + { "ENDSEQVOL3SND6", DVPTR(ENDSEQVOL3SND6), ENDSEQVOL3SND6__STATIC }, + { "ENDSEQVOL3SND7", DVPTR(ENDSEQVOL3SND7), ENDSEQVOL3SND7__STATIC }, + { "ENDSEQVOL3SND8", DVPTR(ENDSEQVOL3SND8), ENDSEQVOL3SND8__STATIC }, + { "ENDSEQVOL3SND9", DVPTR(ENDSEQVOL3SND9), ENDSEQVOL3SND9__STATIC }, + { "WHIPYOURASS", DVPTR(WHIPYOURASS), WHIPYOURASS__STATIC }, + { "ENDSEQVOL2SND1", DVPTR(ENDSEQVOL2SND1), ENDSEQVOL2SND1__STATIC }, + { "ENDSEQVOL2SND2", DVPTR(ENDSEQVOL2SND2), ENDSEQVOL2SND2__STATIC }, + { "ENDSEQVOL2SND3", DVPTR(ENDSEQVOL2SND3), ENDSEQVOL2SND3__STATIC }, + { "ENDSEQVOL2SND4", DVPTR(ENDSEQVOL2SND4), ENDSEQVOL2SND4__STATIC }, + { "ENDSEQVOL2SND5", DVPTR(ENDSEQVOL2SND5), ENDSEQVOL2SND5__STATIC }, + { "ENDSEQVOL2SND6", DVPTR(ENDSEQVOL2SND6), ENDSEQVOL2SND6__STATIC }, + { "ENDSEQVOL2SND7", DVPTR(ENDSEQVOL2SND7), ENDSEQVOL2SND7__STATIC }, + { "SOMETHINGFROZE", DVPTR(SOMETHINGFROZE), SOMETHINGFROZE__STATIC }, + { "WIND_REPEAT", DVPTR(WIND_REPEAT), WIND_REPEAT__STATIC }, + { "BOS4_RECOG", DVPTR(BOS4_RECOG), BOS4_RECOG__STATIC }, + { "LIGHTNING_SLAP", DVPTR(LIGHTNING_SLAP), LIGHTNING_SLAP__STATIC }, + { "THUNDER", DVPTR(THUNDER), THUNDER__STATIC }, + { "INTRO4_1", DVPTR(INTRO4_1), INTRO4_1__STATIC }, + { "INTRO4_2", DVPTR(INTRO4_2), INTRO4_2__STATIC }, + { "INTRO4_3", DVPTR(INTRO4_3), INTRO4_3__STATIC }, + { "INTRO4_4", DVPTR(INTRO4_4), INTRO4_4__STATIC }, + { "INTRO4_5", DVPTR(INTRO4_5), INTRO4_5__STATIC }, + { "INTRO4_6", DVPTR(INTRO4_6), INTRO4_6__STATIC }, + { "BOSS4_DEADSPEECH", DVPTR(BOSS4_DEADSPEECH), BOSS4_DEADSPEECH__STATIC }, + { "BOSS4_FIRSTSEE", DVPTR(BOSS4_FIRSTSEE), BOSS4_FIRSTSEE__STATIC }, + { "VOL4ENDSND1", DVPTR(VOL4ENDSND1), VOL4ENDSND1__STATIC }, + { "VOL4ENDSND2", DVPTR(VOL4ENDSND2), VOL4ENDSND2__STATIC }, + { "EXPANDERSHOOT", DVPTR(EXPANDERSHOOT), EXPANDERSHOOT__STATIC }, + { "INTRO4_B", DVPTR(INTRO4_B), INTRO4_B__STATIC }, + { "BIGBANG", DVPTR(BIGBANG), BIGBANG__STATIC }, + { NULL, NULL, -1 }, + }; + +#ifdef DYNSOUNDREMAP_ENABLE + +int32_t KICK_HIT = KICK_HIT__STATIC; +int32_t PISTOL_RICOCHET = PISTOL_RICOCHET__STATIC; +int32_t PISTOL_BODYHIT = PISTOL_BODYHIT__STATIC; +int32_t PISTOL_FIRE = PISTOL_FIRE__STATIC; +int32_t EJECT_CLIP = EJECT_CLIP__STATIC; +int32_t INSERT_CLIP = INSERT_CLIP__STATIC; +int32_t CHAINGUN_FIRE = CHAINGUN_FIRE__STATIC; +int32_t RPG_SHOOT = RPG_SHOOT__STATIC; +int32_t POOLBALLHIT = POOLBALLHIT__STATIC; +int32_t RPG_EXPLODE = RPG_EXPLODE__STATIC; +int32_t CAT_FIRE = CAT_FIRE__STATIC; +int32_t SHRINKER_FIRE = SHRINKER_FIRE__STATIC; +int32_t PIPEBOMB_BOUNCE = PIPEBOMB_BOUNCE__STATIC; +int32_t PIPEBOMB_EXPLODE = PIPEBOMB_EXPLODE__STATIC; +int32_t LASERTRIP_ONWALL = LASERTRIP_ONWALL__STATIC; +int32_t LASERTRIP_ARMING = LASERTRIP_ARMING__STATIC; +int32_t LASERTRIP_EXPLODE = LASERTRIP_EXPLODE__STATIC; +int32_t VENT_BUST = VENT_BUST__STATIC; +int32_t GLASS_BREAKING = GLASS_BREAKING__STATIC; +int32_t GLASS_HEAVYBREAK = GLASS_HEAVYBREAK__STATIC; +int32_t SHORT_CIRCUIT = SHORT_CIRCUIT__STATIC; +int32_t ITEM_SPLASH = ITEM_SPLASH__STATIC; +int32_t DUKE_GASP = DUKE_GASP__STATIC; +int32_t SLIM_RECOG = SLIM_RECOG__STATIC; +int32_t DUKE_URINATE = DUKE_URINATE__STATIC; +int32_t ENDSEQVOL3SND2 = ENDSEQVOL3SND2__STATIC; +int32_t ENDSEQVOL3SND3 = ENDSEQVOL3SND3__STATIC; +int32_t DUKE_CRACK = DUKE_CRACK__STATIC; +int32_t SLIM_ATTACK = SLIM_ATTACK__STATIC; +int32_t SOMETHINGHITFORCE = SOMETHINGHITFORCE__STATIC; +int32_t DUKE_DRINKING = DUKE_DRINKING__STATIC; +int32_t DUKE_GRUNT = DUKE_GRUNT__STATIC; +int32_t DUKE_HARTBEAT = DUKE_HARTBEAT__STATIC; +int32_t DUKE_ONWATER = DUKE_ONWATER__STATIC; +int32_t DUKE_LAND = DUKE_LAND__STATIC; +int32_t DUKE_WALKINDUCTS = DUKE_WALKINDUCTS__STATIC; +int32_t DUKE_UNDERWATER = DUKE_UNDERWATER__STATIC; +int32_t DUKE_JETPACK_ON = DUKE_JETPACK_ON__STATIC; +int32_t DUKE_JETPACK_IDLE = DUKE_JETPACK_IDLE__STATIC; +int32_t DUKE_JETPACK_OFF = DUKE_JETPACK_OFF__STATIC; +int32_t DUKETALKTOBOSS = DUKETALKTOBOSS__STATIC; +int32_t SQUISHED = SQUISHED__STATIC; +int32_t TELEPORTER = TELEPORTER__STATIC; +int32_t ELEVATOR_ON = ELEVATOR_ON__STATIC; +int32_t ELEVATOR_OFF = ELEVATOR_OFF__STATIC; +int32_t SUBWAY = SUBWAY__STATIC; +int32_t SWITCH_ON = SWITCH_ON__STATIC; +int32_t FLUSH_TOILET = FLUSH_TOILET__STATIC; +int32_t EARTHQUAKE = EARTHQUAKE__STATIC; +int32_t END_OF_LEVEL_WARN = END_OF_LEVEL_WARN__STATIC; +int32_t WIND_AMBIENCE = WIND_AMBIENCE__STATIC; +int32_t SOMETHING_DRIPPING = SOMETHING_DRIPPING__STATIC; +int32_t BOS1_RECOG = BOS1_RECOG__STATIC; +int32_t BOS2_RECOG = BOS2_RECOG__STATIC; +int32_t DUKE_GETWEAPON2 = DUKE_GETWEAPON2__STATIC; +int32_t SHOTGUN_FIRE = SHOTGUN_FIRE__STATIC; +int32_t PRED_RECOG = PRED_RECOG__STATIC; +int32_t CAPT_RECOG = CAPT_RECOG__STATIC; +int32_t PIG_RECOG = PIG_RECOG__STATIC; +int32_t RECO_ROAM = RECO_ROAM__STATIC; +int32_t RECO_RECOG = RECO_RECOG__STATIC; +int32_t RECO_ATTACK = RECO_ATTACK__STATIC; +int32_t RECO_PAIN = RECO_PAIN__STATIC; +int32_t DRON_RECOG = DRON_RECOG__STATIC; +int32_t COMM_RECOG = COMM_RECOG__STATIC; +int32_t OCTA_RECOG = OCTA_RECOG__STATIC; +int32_t TURR_RECOG = TURR_RECOG__STATIC; +int32_t SLIM_DYING = SLIM_DYING__STATIC; +int32_t BOS3_RECOG = BOS3_RECOG__STATIC; +int32_t BOS1_WALK = BOS1_WALK__STATIC; +int32_t THUD = THUD__STATIC; +int32_t WIERDSHOT_FLY = WIERDSHOT_FLY__STATIC; +int32_t SLIM_ROAM = SLIM_ROAM__STATIC; +int32_t SHOTGUN_COCK = SHOTGUN_COCK__STATIC; +int32_t GENERIC_AMBIENCE17 = GENERIC_AMBIENCE17__STATIC; +int32_t BONUS_SPEECH1 = BONUS_SPEECH1__STATIC; +int32_t BONUS_SPEECH2 = BONUS_SPEECH2__STATIC; +int32_t BONUS_SPEECH3 = BONUS_SPEECH3__STATIC; +int32_t BONUS_SPEECH4 = BONUS_SPEECH4__STATIC; +int32_t DUKE_LAND_HURT = DUKE_LAND_HURT__STATIC; +int32_t DUKE_SEARCH2 = DUKE_SEARCH2__STATIC; +int32_t DUKE_CRACK2 = DUKE_CRACK2__STATIC; +int32_t DUKE_SEARCH = DUKE_SEARCH__STATIC; +int32_t DUKE_GET = DUKE_GET__STATIC; +int32_t DUKE_LONGTERM_PAIN = DUKE_LONGTERM_PAIN__STATIC; +int32_t MONITOR_ACTIVE = MONITOR_ACTIVE__STATIC; +int32_t NITEVISION_ONOFF = NITEVISION_ONOFF__STATIC; +int32_t DUKE_CRACK_FIRST = DUKE_CRACK_FIRST__STATIC; +int32_t DUKE_USEMEDKIT = DUKE_USEMEDKIT__STATIC; +int32_t DUKE_TAKEPILLS = DUKE_TAKEPILLS__STATIC; +int32_t DUKE_PISSRELIEF = DUKE_PISSRELIEF__STATIC; +int32_t SELECT_WEAPON = SELECT_WEAPON__STATIC; +int32_t JIBBED_ACTOR5 = JIBBED_ACTOR5__STATIC; +int32_t JIBBED_ACTOR6 = JIBBED_ACTOR6__STATIC; +int32_t DUKE_GOTHEALTHATLOW = DUKE_GOTHEALTHATLOW__STATIC; +int32_t BOSSTALKTODUKE = BOSSTALKTODUKE__STATIC; +int32_t WAR_AMBIENCE2 = WAR_AMBIENCE2__STATIC; +int32_t EXITMENUSOUND = EXITMENUSOUND__STATIC; +int32_t FLY_BY = FLY_BY__STATIC; +int32_t DUKE_SCREAM = DUKE_SCREAM__STATIC; +int32_t SHRINKER_HIT = SHRINKER_HIT__STATIC; +int32_t RATTY = RATTY__STATIC; +int32_t BONUSMUSIC = BONUSMUSIC__STATIC; +int32_t DUKE_GETWEAPON6 = DUKE_GETWEAPON6__STATIC; +int32_t ALIEN_SWITCH1 = ALIEN_SWITCH1__STATIC; +int32_t RIPHEADNECK = RIPHEADNECK__STATIC; +int32_t ENDSEQVOL3SND4 = ENDSEQVOL3SND4__STATIC; +int32_t ENDSEQVOL3SND5 = ENDSEQVOL3SND5__STATIC; +int32_t ENDSEQVOL3SND6 = ENDSEQVOL3SND6__STATIC; +int32_t ENDSEQVOL3SND7 = ENDSEQVOL3SND7__STATIC; +int32_t ENDSEQVOL3SND8 = ENDSEQVOL3SND8__STATIC; +int32_t ENDSEQVOL3SND9 = ENDSEQVOL3SND9__STATIC; +int32_t WHIPYOURASS = WHIPYOURASS__STATIC; +int32_t ENDSEQVOL2SND1 = ENDSEQVOL2SND1__STATIC; +int32_t ENDSEQVOL2SND2 = ENDSEQVOL2SND2__STATIC; +int32_t ENDSEQVOL2SND3 = ENDSEQVOL2SND3__STATIC; +int32_t ENDSEQVOL2SND4 = ENDSEQVOL2SND4__STATIC; +int32_t ENDSEQVOL2SND5 = ENDSEQVOL2SND5__STATIC; +int32_t ENDSEQVOL2SND6 = ENDSEQVOL2SND6__STATIC; +int32_t ENDSEQVOL2SND7 = ENDSEQVOL2SND7__STATIC; +int32_t SOMETHINGFROZE = SOMETHINGFROZE__STATIC; +int32_t WIND_REPEAT = WIND_REPEAT__STATIC; +int32_t BOS4_RECOG = BOS4_RECOG__STATIC; +int32_t LIGHTNING_SLAP = LIGHTNING_SLAP__STATIC; +int32_t THUNDER = THUNDER__STATIC; +int32_t INTRO4_1 = INTRO4_1__STATIC; +int32_t INTRO4_2 = INTRO4_2__STATIC; +int32_t INTRO4_3 = INTRO4_3__STATIC; +int32_t INTRO4_4 = INTRO4_4__STATIC; +int32_t INTRO4_5 = INTRO4_5__STATIC; +int32_t INTRO4_6 = INTRO4_6__STATIC; +int32_t BOSS4_DEADSPEECH = BOSS4_DEADSPEECH__STATIC; +int32_t BOSS4_FIRSTSEE = BOSS4_FIRSTSEE__STATIC; +int32_t VOL4ENDSND1 = VOL4ENDSND1__STATIC; +int32_t VOL4ENDSND2 = VOL4ENDSND2__STATIC; +int32_t EXPANDERSHOOT = EXPANDERSHOOT__STATIC; +int32_t INTRO4_B = INTRO4_B__STATIC; +int32_t BIGBANG = BIGBANG__STATIC; + +static hashtable_t h_names = {512, NULL}; + +void G_ProcessDynamicSoundMapping(const char *szLabel, int32_t lValue) +{ + int32_t i; + + if ((unsigned)lValue >= MAXSOUNDS || !szLabel) + return; + + i = hash_find(&h_names,szLabel); + if (i>=0) + { + struct sdynitem *di = &g_dynSoundList[i]; +#ifdef DEBUGGINGAIDS + if (g_scriptDebug && di->staticval != lValue) + Printf("REMAP %s (%d) --> %d\n", di->str, di->staticval, lValue); +#endif + *di->dynvalptr = lValue; + } +} + +void initsoundhashnames(void) +{ + int32_t i; + + hash_init(&h_names); + + for (i=0; g_dynSoundList[i].staticval >= 0; i++) + hash_add(&h_names, g_dynSoundList[i].str, i, 0); +} + +void freesoundhashnames(void) +{ + hash_free(&h_names); +} +#endif + +// This is run after all CON define's have been processed to set up the +// dynamic->static sound mapping. +void G_InitDynamicSounds(void) +{ + int32_t i; + + Bmemset(DynamicSoundMap, 0, sizeof(DynamicSoundMap)); + + for (i=0; g_dynSoundList[i].staticval >= 0; i++) +#ifdef DYNSOUNDREMAP_ENABLE + DynamicSoundMap[*(g_dynSoundList[i].dynvalptr)] = g_dynSoundList[i].staticval; +#else + DynamicSoundMap[g_dynSoundList[i].staticval] = g_dynSoundList[i].staticval; +#endif + +} +END_DUKE_NS diff --git a/source/duke/src/soundsdyn.h b/source/duke/src/soundsdyn.h new file mode 100644 index 000000000..77c4fd97f --- /dev/null +++ b/source/duke/src/soundsdyn.h @@ -0,0 +1,332 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2013 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +BEGIN_DUKE_NS + +#define DYNSOUNDREMAP_ENABLE + + +#define KICK_HIT__STATIC 0 +#define PISTOL_RICOCHET__STATIC 1 +#define PISTOL_BODYHIT__STATIC 2 +#define PISTOL_FIRE__STATIC 3 +#define EJECT_CLIP__STATIC 4 +#define INSERT_CLIP__STATIC 5 +#define CHAINGUN_FIRE__STATIC 6 +#define RPG_SHOOT__STATIC 7 +#define POOLBALLHIT__STATIC 8 +#define RPG_EXPLODE__STATIC 9 +#define CAT_FIRE__STATIC 10 +#define SHRINKER_FIRE__STATIC 11 +#define PIPEBOMB_BOUNCE__STATIC 13 +#define PIPEBOMB_EXPLODE__STATIC 14 +#define LASERTRIP_ONWALL__STATIC 15 +#define LASERTRIP_ARMING__STATIC 16 +#define LASERTRIP_EXPLODE__STATIC 17 +#define VENT_BUST__STATIC 18 +#define GLASS_BREAKING__STATIC 19 +#define GLASS_HEAVYBREAK__STATIC 20 +#define SHORT_CIRCUIT__STATIC 21 +#define ITEM_SPLASH__STATIC 22 +#define DUKE_GASP__STATIC 25 +#define SLIM_RECOG__STATIC 26 +#define DUKE_URINATE__STATIC 28 +#define ENDSEQVOL3SND2__STATIC 29 +#define ENDSEQVOL3SND3__STATIC 30 +#define DUKE_CRACK__STATIC 33 +#define SLIM_ATTACK__STATIC 34 +#define SOMETHINGHITFORCE__STATIC 35 +#define DUKE_DRINKING__STATIC 36 +#define DUKE_GRUNT__STATIC 38 +#define DUKE_HARTBEAT__STATIC 39 +#define DUKE_ONWATER__STATIC 40 +#define DUKE_LAND__STATIC 42 +#define DUKE_WALKINDUCTS__STATIC 43 +#define DUKE_UNDERWATER__STATIC 48 +#define DUKE_JETPACK_ON__STATIC 49 +#define DUKE_JETPACK_IDLE__STATIC 50 +#define DUKE_JETPACK_OFF__STATIC 51 +#define DUKETALKTOBOSS__STATIC 56 +#define SQUISHED__STATIC 69 +#define TELEPORTER__STATIC 70 +#define ELEVATOR_ON__STATIC 71 +#define ELEVATOR_OFF__STATIC 73 +#define SUBWAY__STATIC 75 +#define SWITCH_ON__STATIC 76 +#define FLUSH_TOILET__STATIC 79 +#define EARTHQUAKE__STATIC 81 +#define END_OF_LEVEL_WARN__STATIC 83 +#define WIND_AMBIENCE__STATIC 91 +#define SOMETHING_DRIPPING__STATIC 92 +#define BOS1_RECOG__STATIC 97 +#define BOS2_RECOG__STATIC 102 +#define DUKE_GETWEAPON2__STATIC 107 +#define SHOTGUN_FIRE__STATIC 109 +#define PRED_RECOG__STATIC 111 +#define CAPT_RECOG__STATIC 117 +#define PIG_RECOG__STATIC 121 +#define RECO_ROAM__STATIC 125 +#define RECO_RECOG__STATIC 126 +#define RECO_ATTACK__STATIC 127 +#define RECO_PAIN__STATIC 128 +#define DRON_RECOG__STATIC 131 +#define COMM_RECOG__STATIC 136 +#define OCTA_RECOG__STATIC 141 +#define TURR_RECOG__STATIC 146 +#define SLIM_DYING__STATIC 149 +#define BOS3_RECOG__STATIC 151 +#define BOS1_WALK__STATIC 156 +#define THUD__STATIC 158 +#define WIERDSHOT_FLY__STATIC 160 +#define SLIM_ROAM__STATIC 163 +#define SHOTGUN_COCK__STATIC 169 +#define GENERIC_AMBIENCE17__STATIC 177 +#define BONUS_SPEECH1__STATIC 195 +#define BONUS_SPEECH2__STATIC 196 +#define BONUS_SPEECH3__STATIC 197 +#define BONUS_SPEECH4__STATIC 199 +#define DUKE_LAND_HURT__STATIC 200 +#define DUKE_SEARCH2__STATIC 207 +#define DUKE_CRACK2__STATIC 208 +#define DUKE_SEARCH__STATIC 209 +#define DUKE_GET__STATIC 210 +#define DUKE_LONGTERM_PAIN__STATIC 211 +#define MONITOR_ACTIVE__STATIC 212 +#define NITEVISION_ONOFF__STATIC 213 +#define DUKE_CRACK_FIRST__STATIC 215 +#define DUKE_USEMEDKIT__STATIC 216 +#define DUKE_TAKEPILLS__STATIC 217 +#define DUKE_PISSRELIEF__STATIC 218 +#define SELECT_WEAPON__STATIC 219 +#define JIBBED_ACTOR5__STATIC 226 +#define JIBBED_ACTOR6__STATIC 227 +#define DUKE_GOTHEALTHATLOW__STATIC 229 +#define BOSSTALKTODUKE__STATIC 230 +#define WAR_AMBIENCE2__STATIC 232 +#define EXITMENUSOUND__STATIC 243 +#define FLY_BY__STATIC 244 +#define DUKE_SCREAM__STATIC 245 +#define SHRINKER_HIT__STATIC 246 +#define RATTY__STATIC 247 +#define BONUSMUSIC__STATIC 249 +#define DUKE_GETWEAPON6__STATIC 264 +#define ALIEN_SWITCH1__STATIC 272 +#define RIPHEADNECK__STATIC 284 +#define ENDSEQVOL3SND4__STATIC 288 +#define ENDSEQVOL3SND5__STATIC 289 +#define ENDSEQVOL3SND6__STATIC 290 +#define ENDSEQVOL3SND7__STATIC 291 +#define ENDSEQVOL3SND8__STATIC 292 +#define ENDSEQVOL3SND9__STATIC 293 +#define WHIPYOURASS__STATIC 294 +#define ENDSEQVOL2SND1__STATIC 295 +#define ENDSEQVOL2SND2__STATIC 296 +#define ENDSEQVOL2SND3__STATIC 297 +#define ENDSEQVOL2SND4__STATIC 298 +#define ENDSEQVOL2SND5__STATIC 299 +#define ENDSEQVOL2SND6__STATIC 300 +#define ENDSEQVOL2SND7__STATIC 301 +#define SOMETHINGFROZE__STATIC 303 +#define WIND_REPEAT__STATIC 308 +#define BOS4_RECOG__STATIC 342 +#define LIGHTNING_SLAP__STATIC 351 +#define THUNDER__STATIC 352 +#define INTRO4_1__STATIC 363 +#define INTRO4_2__STATIC 364 +#define INTRO4_3__STATIC 365 +#define INTRO4_4__STATIC 366 +#define INTRO4_5__STATIC 367 +#define INTRO4_6__STATIC 368 +#define BOSS4_DEADSPEECH__STATIC 370 +#define BOSS4_FIRSTSEE__STATIC 371 +#define VOL4ENDSND1__STATIC 384 +#define VOL4ENDSND2__STATIC 385 +#define EXPANDERSHOOT__STATIC 388 +#define INTRO4_B__STATIC 392 +#define BIGBANG__STATIC 393 + +extern int16_t DynamicSoundMap[MAXSOUNDS]; + +void G_InitDynamicSounds(void); + +#ifdef DYNSOUNDREMAP_ENABLE + +void G_ProcessDynamicSoundMapping(const char *szLabel, int32_t lValue); + +void initsoundhashnames(void); +void freesoundhashnames(void); + +extern int32_t KICK_HIT; +extern int32_t PISTOL_RICOCHET; +extern int32_t PISTOL_BODYHIT; +extern int32_t PISTOL_FIRE; +extern int32_t EJECT_CLIP; +extern int32_t INSERT_CLIP; +extern int32_t CHAINGUN_FIRE; +extern int32_t RPG_SHOOT; +extern int32_t POOLBALLHIT; +extern int32_t RPG_EXPLODE; +extern int32_t CAT_FIRE; +extern int32_t SHRINKER_FIRE; +extern int32_t PIPEBOMB_BOUNCE; +extern int32_t PIPEBOMB_EXPLODE; +extern int32_t LASERTRIP_ONWALL; +extern int32_t LASERTRIP_ARMING; +extern int32_t LASERTRIP_EXPLODE; +extern int32_t VENT_BUST; +extern int32_t GLASS_BREAKING; +extern int32_t GLASS_HEAVYBREAK; +extern int32_t SHORT_CIRCUIT; +extern int32_t ITEM_SPLASH; +extern int32_t DUKE_GASP; +extern int32_t SLIM_RECOG; +extern int32_t DUKE_URINATE; +extern int32_t ENDSEQVOL3SND2; +extern int32_t ENDSEQVOL3SND3; +extern int32_t DUKE_CRACK; +extern int32_t SLIM_ATTACK; +extern int32_t SOMETHINGHITFORCE; +extern int32_t DUKE_DRINKING; +extern int32_t DUKE_GRUNT; +extern int32_t DUKE_HARTBEAT; +extern int32_t DUKE_ONWATER; +extern int32_t DUKE_LAND; +extern int32_t DUKE_WALKINDUCTS; +extern int32_t DUKE_UNDERWATER; +extern int32_t DUKE_JETPACK_ON; +extern int32_t DUKE_JETPACK_IDLE; +extern int32_t DUKE_JETPACK_OFF; +extern int32_t DUKETALKTOBOSS; +extern int32_t SQUISHED; +extern int32_t TELEPORTER; +extern int32_t ELEVATOR_ON; +extern int32_t ELEVATOR_OFF; +extern int32_t SUBWAY; +extern int32_t SWITCH_ON; +extern int32_t FLUSH_TOILET; +extern int32_t EARTHQUAKE; +extern int32_t END_OF_LEVEL_WARN; +extern int32_t WIND_AMBIENCE; +extern int32_t SOMETHING_DRIPPING; +extern int32_t BOS1_RECOG; +extern int32_t BOS2_RECOG; +extern int32_t DUKE_GETWEAPON2; +extern int32_t SHOTGUN_FIRE; +extern int32_t PRED_RECOG; +extern int32_t CAPT_RECOG; +extern int32_t PIG_RECOG; +extern int32_t RECO_ROAM; +extern int32_t RECO_RECOG; +extern int32_t RECO_ATTACK; +extern int32_t RECO_PAIN; +extern int32_t DRON_RECOG; +extern int32_t COMM_RECOG; +extern int32_t OCTA_RECOG; +extern int32_t TURR_RECOG; +extern int32_t SLIM_DYING; +extern int32_t BOS3_RECOG; +extern int32_t BOS1_WALK; +extern int32_t THUD; +extern int32_t WIERDSHOT_FLY; +extern int32_t SLIM_ROAM; +extern int32_t SHOTGUN_COCK; +extern int32_t GENERIC_AMBIENCE17; +extern int32_t BONUS_SPEECH1; +extern int32_t BONUS_SPEECH2; +extern int32_t BONUS_SPEECH3; +extern int32_t BONUS_SPEECH4; +extern int32_t DUKE_LAND_HURT; +extern int32_t DUKE_SEARCH2; +extern int32_t DUKE_CRACK2; +extern int32_t DUKE_SEARCH; +extern int32_t DUKE_GET; +extern int32_t DUKE_LONGTERM_PAIN; +extern int32_t MONITOR_ACTIVE; +extern int32_t NITEVISION_ONOFF; +extern int32_t DUKE_CRACK_FIRST; +extern int32_t DUKE_USEMEDKIT; +extern int32_t DUKE_TAKEPILLS; +extern int32_t DUKE_PISSRELIEF; +extern int32_t SELECT_WEAPON; +extern int32_t JIBBED_ACTOR5; +extern int32_t JIBBED_ACTOR6; +extern int32_t DUKE_GOTHEALTHATLOW; +extern int32_t BOSSTALKTODUKE; +extern int32_t WAR_AMBIENCE2; +extern int32_t EXITMENUSOUND; +extern int32_t FLY_BY; +extern int32_t DUKE_SCREAM; +extern int32_t SHRINKER_HIT; +extern int32_t RATTY; +extern int32_t BONUSMUSIC; +extern int32_t DUKE_GETWEAPON6; +extern int32_t ALIEN_SWITCH1; +extern int32_t RIPHEADNECK; +extern int32_t ENDSEQVOL3SND4; +extern int32_t ENDSEQVOL3SND5; +extern int32_t ENDSEQVOL3SND6; +extern int32_t ENDSEQVOL3SND7; +extern int32_t ENDSEQVOL3SND8; +extern int32_t ENDSEQVOL3SND9; +extern int32_t WHIPYOURASS; +extern int32_t ENDSEQVOL2SND1; +extern int32_t ENDSEQVOL2SND2; +extern int32_t ENDSEQVOL2SND3; +extern int32_t ENDSEQVOL2SND4; +extern int32_t ENDSEQVOL2SND5; +extern int32_t ENDSEQVOL2SND6; +extern int32_t ENDSEQVOL2SND7; +extern int32_t SOMETHINGFROZE; +extern int32_t WIND_REPEAT; +extern int32_t BOS4_RECOG; +extern int32_t LIGHTNING_SLAP; +extern int32_t THUNDER; +extern int32_t INTRO4_1; +extern int32_t INTRO4_2; +extern int32_t INTRO4_3; +extern int32_t INTRO4_4; +extern int32_t INTRO4_5; +extern int32_t INTRO4_6; +extern int32_t BOSS4_DEADSPEECH; +extern int32_t BOSS4_FIRSTSEE; +extern int32_t VOL4ENDSND1; +extern int32_t VOL4ENDSND2; +extern int32_t EXPANDERSHOOT; +extern int32_t INTRO4_B; +extern int32_t BIGBANG; + +#define DYNAMICSOUNDMAP(Soundnum) (DynamicSoundMap[Soundnum]) + +#else /* if !defined DYNSOUNDREMAP_ENABLE */ + +#define G_ProcessDynamicSoundMapping(x, y) ((void)(0)) + +#define initsoundhashnames() ((void)0) +#define freesoundhashnames() ((void)0) + +#include "soundefs.h" + +#define DYNAMICSOUNDMAP(Soundnum) (Soundnum) + +#endif + +END_DUKE_NS diff --git a/source/duke/src/text.cpp b/source/duke/src/text.cpp new file mode 100644 index 000000000..8db23279f --- /dev/null +++ b/source/duke/src/text.cpp @@ -0,0 +1,374 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- +#include "ns.h" // Must come before everything else! + +#include "duke3d.h" +#include "compat.h" +#include "sbar.h" +#include "menus.h" +#include "gstrings.h" + +BEGIN_DUKE_NS + +// assign the character's tilenum +int GameInterface::GetStringTile(int font, const char* t, int f) +{ + if (f & TEXT_DIGITALNUMBER) + return *t - '0' + font; // copied from digitalnumber + else if (f & (TEXT_BIGALPHANUM|TEXT_GRAYFONT)) + { + int32_t offset = (f & TEXT_GRAYFONT) ? 26 : 0; + + if (*t >= '0' && *t <= '9') + return *t - '0' + font + ((f & TEXT_GRAYFONT) ? 26 : -10); + else if (*t >= 'a' && *t <= 'z') + return *t - 'a' + font + ((f & TEXT_GRAYFONT) ? -26 : 26); + else if (*t >= 'A' && *t <= 'Z') + return *t - 'A' + font; + else switch (*t) + { + case '_': + case '-': + return font - (11 + offset); + break; + case '.': + return font + (BIGPERIOD - (BIGALPHANUM + offset)); + break; + case ',': + return font + (BIGCOMMA - (BIGALPHANUM + offset)); + break; + case '!': + return font + (BIGX_ - (BIGALPHANUM + offset)); + break; + case '?': + return font + (BIGQ - (BIGALPHANUM + offset)); + break; + case ';': + return font + (BIGSEMI - (BIGALPHANUM + offset)); + break; + case ':': + return font + (BIGCOLIN - (BIGALPHANUM + offset)); + break; + case '\\': + case '/': + return font + (68 - offset); // 3008-2940 + break; + case '%': + return font + (69 - offset); // 3009-2940 + break; + case '`': + case '\"': // could be better hacked in + case '\'': + return font + (BIGAPPOS - (BIGALPHANUM + offset)); + break; + default: // unknown character + fallthrough__; + case '\t': + case ' ': + case '\n': + case '\x7F': + return font; + break; + } + } + else + return *t - '!' + font; // uses ASCII order +} + + +vec2_t gametext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t o, int32_t a, int32_t f) +{ + return G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, s, p, o|2|8|16|ROTATESPRITE_FULL16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); +} +void gametext_simple(int32_t x, int32_t y, const char *t) +{ + G_ScreenText(MF_Bluefont.tilenum, x, y, MF_Bluefont.zoom, 0, 0, t, 0, MF_Bluefont.pal, 2|8|16|ROTATESPRITE_FULL16, 0, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags, 0, 0, xdim-1, ydim-1); +} +vec2_t mpgametext(int32_t x, int32_t y, const char *t, int32_t s, int32_t o, int32_t a, int32_t f) +{ + return G_ScreenText(MF_Bluefont.tilenum, x, y, textsc(MF_Bluefont.zoom), 0, 0, t, s, MF_Bluefont.pal, o|2|8|16|ROTATESPRITE_FULL16, a, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); +} +vec2_t mpgametextsize(const char *t, int32_t f) +{ + return G_ScreenTextSize(MF_Bluefont.tilenum, 0, 0, textsc(MF_Bluefont.zoom), 0, t, 2|8|16|ROTATESPRITE_FULL16, MF_Bluefont.emptychar.x, MF_Bluefont.emptychar.y, MF_Bluefont.between.x, MF_Bluefont.between.y, MF_Bluefont.textflags|f, 0, 0, xdim-1, ydim-1); +} + +// minitext_yofs: in hud_scale-independent, (<<16)-scaled, 0-200-normalized y coords, +// (sb&ROTATESPRITE_MAX) only. +int32_t minitext_yofs = 0; +int32_t minitext_lowercase = 0; +int32_t minitext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t sb) +{ + vec2_t dim; + int32_t z = MF_Minifont.zoom; + + if (t == NULL) + { + Printf("minitext: NULL text!\n"); + return 0; + } + + if (!(sb & ROTATESPRITE_FULL16)) + { + x<<=16; + y<<=16; + } + + if (sb & ROTATESPRITE_MAX) + { + if (sb & RS_ALIGN_R) + x = sbarxr16(x); + else + x = sbarx16(x); + y = minitext_yofs+sbary16(y); + z = sbarsc(z); + } + + sb &= (ROTATESPRITE_MAX-1)|RS_CENTERORIGIN; + + dim = G_ScreenText(MF_Minifont.tilenum, x, y, z, 0, 0, t, s, p, sb|ROTATESPRITE_FULL16, 0, MF_Minifont.emptychar.x, MF_Minifont.emptychar.y, MF_Minifont.between.x, MF_Minifont.between.y, MF_Minifont.textflags, 0, 0, xdim-1, ydim-1); + + x += dim.x; + + if (!(sb & ROTATESPRITE_FULL16)) + x >>= 16; + + return x; +} + +void menutext_(int32_t x, int32_t y, int32_t s, char const *t, int32_t o, int32_t f) +{ + if (RR) f |= TEXT_RRMENUTEXTHACK; + G_ScreenText(MF_Redfont.tilenum, x, y - (12<<16), MF_Redfont.zoom, 0, 0, t, s, MF_Redfont.pal, o|ROTATESPRITE_FULL16, 0, MF_Redfont.emptychar.x, MF_Redfont.emptychar.y, MF_Redfont.between.x, MF_Redfont.between.y, f|MF_Redfont.textflags|TEXT_LITERALESCAPE, 0, 0, xdim-1, ydim-1); +} + +void captionmenutext(int32_t x, int32_t y, char const *t) +{ + G_ScreenText(MF_Redfont.tilenum, x, y - (12<<16), MF_Redfont.zoom, 0, 0, t, 0, ud.menutitle_pal, 2|8|16|ROTATESPRITE_FULL16, 0, MF_Redfont.emptychar.x, MF_Redfont.emptychar.y, MF_Redfont.between.x, MF_Redfont.between.y, MF_Redfont.textflags|TEXT_LITERALESCAPE|TEXT_XCENTER|TEXT_YCENTER, 0, 0, xdim-1, ydim-1); +} + + +int32_t user_quote_time[MAXUSERQUOTES]; +static char user_quote[MAXUSERQUOTES][178]; + +void G_AddUserQuote(const char* daquote) +{ + int32_t i; + + if (hud_messages == 0) return; + Printf(PRINT_MEDIUM | PRINT_NOTIFY, "%s\n", daquote); + if (hud_messages == 1) + { + for (i = MAXUSERQUOTES - 1; i > 0; i--) + { + Bstrcpy(user_quote[i], user_quote[i - 1]); + user_quote_time[i] = user_quote_time[i - 1]; + } + Bstrcpy(user_quote[0], daquote); + + user_quote_time[0] = hud_messagetime; + pub = NUMPAGES; + } +} + +int32_t textsc(int32_t sc) +{ + return scale(sc, hud_textscale, 400); +} + +#define FTAOPAQUETIME 30 + +// alpha increments of 8 --> 256 / 8 = 32 --> round up to power of 2 --> 32 --> divide by 2 --> 16 alphatabs required +static inline int32_t textsh(uint32_t t) +{ + return (hud_glowingquotes && ((videoGetRenderMode() == REND_CLASSIC && numalphatabs < 15) || t >= FTAOPAQUETIME)) + ? sintable[(t << 7) & 2047] >> 11 + : (sintable[(FTAOPAQUETIME << 7) & 2047] >> 11); +} + +// orientation flags depending on time that a quote has still to be displayed +static inline int32_t texto(int32_t t) +{ + if (videoGetRenderMode() != REND_CLASSIC || numalphatabs >= 15 || t > 4) + return 0; + + if (t > 2) + return 1; + + return 1|32; +} + +static inline int32_t texta(int32_t t) +{ + return 255 - clamp(t<<3, 0, 255); +} + +static FORCE_INLINE int32_t text_ypos(void) +{ + if (hud_position == 1 && ud.screen_size == 4 && ud.althud == 1) + return 32<<16; + +#ifdef GEKKO + return 16<<16; +#elif defined EDUKE32_TOUCH_DEVICES + return 24<<16; +#else + return 1<<16; +#endif +} + +static FString text_quote; // To put text into the quote display that does not come from the quote array. (Is it really necessary to implement everything as a hack??? :( ) + +// this handles both multiplayer and item pickup message type text +// both are passed on to gametext +void G_PrintGameQuotes(int32_t snum) +{ + const DukePlayer_t *const ps = g_player[snum].ps; + const int32_t reserved_quote = (ps->ftq >= QUOTE_RESERVED && ps->ftq <= QUOTE_RESERVED3); + // NOTE: QUOTE_RESERVED4 is not included. + + int32_t const ybase = (fragbarheight()<<16) + text_ypos(); + int32_t height = 0; + int32_t k = ps->fta; + + + // primary quote + + do + { + if (k <= 1) + break; + + int32_t y = ybase; + if (reserved_quote) + { +#ifdef SPLITSCREEN_MOD_HACKS + if (!g_fakeMultiMode) + y = 140<<16; + else + y = 70<<16; +#else + y = 140<<16; +#endif + } + + int32_t pal = 0; + int32_t x = 160<<16; + +#ifdef SPLITSCREEN_MOD_HACKS + if (g_fakeMultiMode) + { + pal = g_player[snum].pcolor; + const int32_t sidebyside = ud.screen_size != 0; + + if (sidebyside) + x = snum == 1 ? 240<<16 : 80<<16; + else if (snum == 1) + y += 100<<16; + } +#endif + + if (text_quote.IsNotEmpty() && ps->ftq == -32768) height = gametext_(x, y, text_quote, textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1 << 16); + else height = gametext_(x, y, quoteMgr.GetQuote(ps->ftq), textsh(k), pal, texto(k), texta(k), TEXT_XCENTER).y + (1 << 16); + } + while (0); + + + // userquotes + + int32_t y = ybase; + + if (k > 1 && !reserved_quote) + y += k <= 8 ? (height * (k-1))>>3 : height; + + for (size_t i = MAXUSERQUOTES-1; i < MAXUSERQUOTES; --i) + { + k = user_quote_time[i]; + + if (k <= 0) + continue; + + // int32_t const sh = hud_glowingquotes ? sintable[((totalclock+(i<<2))<<5)&2047]>>11 : 0; + + height = mpgametext(mpgametext_x, y, user_quote[i], textsh(k), texto(k), texta(k), TEXT_LINEWRAP).y + textsc(1<<16); + y += k <= 4 ? (height * (k-1))>>2 : height; + } +} + +void P_DoQuote(int32_t q, DukePlayer_t *p) +{ + int32_t cq = 0; + + if (hud_messages == 0 || q < 0 || !(p->gm & MODE_GAME)) + return; + + if (q & MAXQUOTES) + { + cq = 1; + q &= ~MAXQUOTES; + } + + if (p->fta > 0 && q != QUOTE_RESERVED && q != QUOTE_RESERVED2) + if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; + + if (p->ftq != q) + { + auto qu = quoteMgr.GetQuote(q); + if (p == g_player[screenpeek].ps && qu[0] != '\0') + Printf((cq ? PRINT_LOW : PRINT_MEDIUM) | PRINT_NOTIFY, "%s\n", qu); + + } + + if (hud_messages == 1) + { + p->ftq = q; + p->fta = 100; + pub = NUMPAGES; + pus = NUMPAGES; + } +} + +void GameInterface::DoPrintMessage(int prio, const char* t) +{ + auto p = g_player[myconnectindex].ps; // text quotes always belong to the local player. + int32_t cq = 0; + + if (hud_messages == 0 || !(p->gm & MODE_GAME)) + return; + + if (p->fta > 0) + if (p->ftq == QUOTE_RESERVED || p->ftq == QUOTE_RESERVED2) return; + + if (p == g_player[screenpeek].ps) + Printf(prio|PRINT_NOTIFY, cq ? TEXTCOLOR_TAN "%s\n" : "%s\n", t); + + if (hud_messages == 1) + { + p->fta = 100; + p->ftq = -32768; + text_quote = t; + pub = NUMPAGES; + pus = NUMPAGES; + } +} + +END_DUKE_NS diff --git a/source/duke/src/text.h b/source/duke/src/text.h new file mode 100644 index 000000000..f133a335f --- /dev/null +++ b/source/duke/src/text.h @@ -0,0 +1,62 @@ +//------------------------------------------------------------------------- +/* +Copyright (C) 2016 EDuke32 developers and contributors + +This file is part of EDuke32. + +EDuke32 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. +*/ +//------------------------------------------------------------------------- + +#pragma once + +#include "menus.h" +#include "screentext.h" + +BEGIN_DUKE_NS + +#define MAXUSERQUOTES 6 + +extern int32_t user_quote_time[MAXUSERQUOTES]; +extern int32_t minitext_lowercase; +extern int32_t minitext_yofs; + + +extern int32_t minitext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t sb); +extern void menutext_(int32_t x, int32_t y, int32_t s, char const *t, int32_t o, int32_t f); +extern void captionmenutext(int32_t x, int32_t y, char const *t); +extern vec2_t gametext_(int32_t x, int32_t y, const char *t, int32_t s, int32_t p, int32_t o, int32_t a, int32_t f); +extern void gametext_simple(int32_t x, int32_t y, const char *t); +#define mpgametext_x (5<<16) +extern vec2_t mpgametext(int32_t x, int32_t y, char const * t, int32_t s, int32_t o, int32_t a, int32_t f); +extern vec2_t mpgametextsize(char const * t, int32_t f); +extern int32_t textsc(int32_t sc); + +#define minitextshade(x, y, t, s, p, sb) minitext_(x,y,t,s,p,sb) +#define minitext(x, y, t, p, sb) minitext_(x,y,t,0,p,sb) +#define menutext(x, y, t) menutext_((x)<<16, (y)<<16, 0, (t), 10|16, 0) +#define menutext_centeralign(x, y, t) menutext_((x), (y), 0, (t), 10|16, TEXT_XCENTER|TEXT_YCENTER) +#define menutext_center(y, t) menutext_(160<<16, (y)<<16, 0, (t), 10|16, TEXT_XCENTER) +#define gametext(x, y, t) gametext_simple((x)<<16, (y)<<16, (t)) +#define gametext_widenumber(x, y, t) gametext_((x)<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 1024, 0, TEXT_GAMETEXTNUMHACK) +#define gametext_number(x, y, t) gametext_((x)<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 0, 0, TEXT_GAMETEXTNUMHACK) +#define gametext_pal(x, y, t, p) gametext_((x)<<16, (y)<<16, (t), 0, (p), 0, 0, 0) +#define gametext_center(y, t) gametext_(160<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 0, 0, TEXT_XCENTER) +#define gametext_center_number(y, t) gametext_(160<<16, (y)<<16, (t), 0, MF_Bluefont.pal, 0, 0, TEXT_XCENTER|TEXT_GAMETEXTNUMHACK) +#define gametext_center_shade(y, t, s) gametext_(160<<16, (y)<<16, (t), (s), MF_Bluefont.pal, 0, 0, TEXT_XCENTER) +#define gametext_center_shade_pal(y, t, s, p) gametext_(160<<16, (y)<<16, (t), (s), (p), 0, 0, TEXT_XCENTER) + + +END_DUKE_NS diff --git a/source/duke3d/src/actors.cpp b/source/duke3d/src/actors.cpp index dfb65384d..4c6f4265b 100644 --- a/source/duke3d/src/actors.cpp +++ b/source/duke3d/src/actors.cpp @@ -33,7 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "v_text.h" #include "printf.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #if KRANDDEBUG @@ -8944,4 +8944,4 @@ void G_MoveWorld(void) g_moveWorldTime = (1-0.033)*g_moveWorldTime + 0.033*(timerGetHiTicks()-worldTime); } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/actors.h b/source/duke3d/src/actors.h index 3fb1c6fa7..450d279e0 100644 --- a/source/duke3d/src/actors.h +++ b/source/duke3d/src/actors.h @@ -26,7 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "player.h" # include "namesdyn.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define MAXSLEEPDIST 16384 #define SLEEPTIME 1536 @@ -466,7 +466,7 @@ EXTERN_INLINE int A_CheckEnemySprite(void const * const pSprite) return A_CheckEnemyTile(((uspriteptr_t) pSprite)->picnum); } -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/anim.cpp b/source/duke3d/src/anim.cpp index 1276042b7..76b69c6a9 100644 --- a/source/duke3d/src/anim.cpp +++ b/source/duke3d/src/anim.cpp @@ -39,7 +39,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # include "animvpx.h" #endif -BEGIN_DUKE_NS +BEGIN_EDUKE_NS dukeanim_t* g_animPtr; @@ -533,4 +533,4 @@ end_anim: return !running; } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/anim.h b/source/duke3d/src/anim.h index 9fb31fca8..124af03a7 100644 --- a/source/duke3d/src/anim.h +++ b/source/duke3d/src/anim.h @@ -28,7 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "tarray.h" #include "zstring.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS struct animsound_t { uint16_t frame = 0; @@ -53,6 +53,6 @@ extern dukeanim_t * Anim_Create(const char *fn); int32_t Anim_Play(const char *fn); void Anim_Init(void); -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/cheats.cpp b/source/duke3d/src/cheats.cpp index 4c5feebfd..6153de36c 100644 --- a/source/duke3d/src/cheats.cpp +++ b/source/duke3d/src/cheats.cpp @@ -29,7 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mapinfo.h" #include "c_dispatch.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS char CheatStrings [NUMCHEATS][MAXCHEATLEN] = { @@ -745,4 +745,4 @@ void G_DoCheats(void) } } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/cheats.h b/source/duke3d/src/cheats.h index aec829785..5309de04c 100644 --- a/source/duke3d/src/cheats.h +++ b/source/duke3d/src/cheats.h @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #pragma once -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define MAXCHEATLEN 20 #define MAXCHEATDESC 64 @@ -95,4 +95,4 @@ enum CheatCodeFunctions NUMCHEATFUNCS, }; -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/cmdline.cpp b/source/duke3d/src/cmdline.cpp index d0713863c..d87439b93 100644 --- a/source/duke3d/src/cmdline.cpp +++ b/source/duke3d/src/cmdline.cpp @@ -31,7 +31,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "printf.h" #include "c_dispatch.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS int32_t g_fakeMultiMode = 0; @@ -97,4 +97,4 @@ void G_CheckCommandLine() } } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/cmdline.h b/source/duke3d/src/cmdline.h index 2b47a2f39..c653aa08d 100644 --- a/source/duke3d/src/cmdline.h +++ b/source/duke3d/src/cmdline.h @@ -25,7 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "compat.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS extern void G_CheckCommandLine(); @@ -34,6 +34,6 @@ extern void G_ShowDebugHelp(void); extern int32_t g_fakeMultiMode; -END_DUKE_NS +END_EDUKE_NS #endif // cmdline_h__ diff --git a/source/duke3d/src/common.cpp b/source/duke3d/src/common.cpp index 2ecbfe879..c6a880823 100644 --- a/source/duke3d/src/common.cpp +++ b/source/duke3d/src/common.cpp @@ -17,7 +17,7 @@ #include "common.h" #include "common_game.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS // Set up new-style multi-psky handling. @@ -138,4 +138,4 @@ void G_LoadLookups(void) } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/common_game.h b/source/duke3d/src/common_game.h index 335e1a315..22828e2fc 100644 --- a/source/duke3d/src/common_game.h +++ b/source/duke3d/src/common_game.h @@ -9,7 +9,7 @@ #include "gamecontrol.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define DUKE (g_gameType & GAMEFLAG_DUKE) @@ -67,5 +67,5 @@ static inline void Duke_ApplySpritePropertiesToTSprite(tspriteptr_t tspr, usprit void Duke_CommonCleanup(void); -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/config.cpp b/source/duke3d/src/config.cpp index 12aba63f8..c7cb8f88a 100644 --- a/source/duke3d/src/config.cpp +++ b/source/duke3d/src/config.cpp @@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "baselayer.h" #include "cmdline.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS @@ -68,4 +68,4 @@ int CONFIG_ReadSetup(void) return 0; } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/config.h b/source/duke3d/src/config.h index 53840e739..07dca201e 100644 --- a/source/duke3d/src/config.h +++ b/source/duke3d/src/config.h @@ -25,10 +25,10 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "gamecontrol.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS int CONFIG_ReadSetup(void); -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/d_menu.cpp b/source/duke3d/src/d_menu.cpp index 0dd8cfd93..f5fa3fa3c 100644 --- a/source/duke3d/src/d_menu.cpp +++ b/source/duke3d/src/d_menu.cpp @@ -41,7 +41,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "menus.h" #include "../../glbackend/glbackend.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define MENU_MARGIN_REGULAR 40 #define MENU_MARGIN_WIDE 32 @@ -754,7 +754,7 @@ void GameInterface::QuitToTitle() G_CloseDemoWrite(); artClearMapArt(); } -END_DUKE_NS +END_EDUKE_NS //---------------------------------------------------------------------------- // diff --git a/source/duke3d/src/demo.cpp b/source/duke3d/src/demo.cpp index 44110a9ce..4ae7009a1 100644 --- a/source/duke3d/src/demo.cpp +++ b/source/duke3d/src/demo.cpp @@ -32,7 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "menu.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS char g_firstDemoFile[BMAX_PATH]; @@ -933,4 +933,4 @@ nextdemo_nomenu: return 1; } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/demo.h b/source/duke3d/src/demo.h index 3d0475f39..177c5cdfd 100644 --- a/source/duke3d/src/demo.h +++ b/source/duke3d/src/demo.h @@ -26,7 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "compat.h" #include "filesystem.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define DEMOFN_FMT "edemo%03d.edm" #define MAXDEMOS 1000 @@ -58,6 +58,6 @@ int32_t krd_print(const char *filename); void krd_enable(int32_t which); #endif -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/duke3d.h b/source/duke3d/src/duke3d.h index 6a2e70ace..150464970 100644 --- a/source/duke3d/src/duke3d.h +++ b/source/duke3d/src/duke3d.h @@ -131,7 +131,7 @@ EDUKE32_STATIC_ASSERT(7 <= MAXTILES-MAXUSERTILES); #include "soundsdyn.h" #include "text.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS // Order is that of EDuke32 by necessity because it exposes the key binds to scripting by index instead of by name. enum GameFunction_t @@ -247,6 +247,6 @@ struct GameInterface : ::GameInterface }; -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/events_defs.h b/source/duke3d/src/events_defs.h index 0af073b17..4e5e076a0 100644 --- a/source/duke3d/src/events_defs.h +++ b/source/duke3d/src/events_defs.h @@ -2,7 +2,7 @@ #ifndef EDUKE32_EVENTS_DEFS_H_ #define EDUKE32_EVENTS_DEFS_H_ -BEGIN_DUKE_NS +BEGIN_EDUKE_NS // the order of these can't be changed or else compatibility with EDuke 2.0 mods will break // KEEPINSYNC with EventNames[] @@ -167,6 +167,6 @@ enum GameEvent_t { MAXEVENTS }; -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/game.cpp b/source/duke3d/src/game.cpp index 610f20ff0..2aa0e98c9 100644 --- a/source/duke3d/src/game.cpp +++ b/source/duke3d/src/game.cpp @@ -65,7 +65,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # define GAME_STATIC static #endif -BEGIN_DUKE_NS +BEGIN_EDUKE_NS int32_t g_quitDeadline = 0; @@ -6253,4 +6253,4 @@ void GameInterface::UpdateScreenSize() return new GameInterface; } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/game.h b/source/duke3d/src/game.h index 03496a54d..63375de9f 100644 --- a/source/duke3d/src/game.h +++ b/source/duke3d/src/game.h @@ -37,7 +37,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "palette.h" #include "cmdlib.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #ifndef ONLY_USERDEFS @@ -432,6 +432,6 @@ static inline int G_GetMusicIdx(const char *str) #endif -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/gamedef.cpp b/source/duke3d/src/gamedef.cpp index d885f5a6c..23e1363cf 100644 --- a/source/duke3d/src/gamedef.cpp +++ b/source/duke3d/src/gamedef.cpp @@ -44,7 +44,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. void C_CON_SetButtonAlias(int num, const char* text); void C_CON_ClearButtonAlias(int num); -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define LINE_NUMBER (g_lineNumber << 12) @@ -6113,4 +6113,4 @@ void C_ReportError(int error) } } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/gamedef.h b/source/duke3d/src/gamedef.h index 9d2db6829..871776f8d 100644 --- a/source/duke3d/src/gamedef.h +++ b/source/duke3d/src/gamedef.h @@ -33,7 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "events_defs.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS enum { @@ -1352,6 +1352,6 @@ enum ScriptKeywords_t #undef ENUM_TRANSFORM #undef COMMA -END_DUKE_NS +END_EDUKE_NS #endif // gamedef_h_ diff --git a/source/duke3d/src/gameexec.cpp b/source/duke3d/src/gameexec.cpp index b36c90776..c199fb84a 100644 --- a/source/duke3d/src/gameexec.cpp +++ b/source/duke3d/src/gameexec.cpp @@ -53,7 +53,7 @@ FString C_CON_GetBoundKeyForLastInput(int gameFunc); const char* C_CON_GetButtonFunc(int num); const char* KB_ScanCodeToString(int scancode); // convert scancode into a string -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #if KRANDDEBUG # define GAMEEXEC_INLINE @@ -6657,4 +6657,4 @@ void VM_DrawTileSmall(int32_t x, int32_t y, int32_t tilenum, int32_t shade, int3 VM_DrawTileGeneric(x, y, 32768, tilenum, shade, orientation, tilePal); } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/gameexec.h b/source/duke3d/src/gameexec.h index 11a5a08a3..e1dc74e1f 100644 --- a/source/duke3d/src/gameexec.h +++ b/source/duke3d/src/gameexec.h @@ -29,7 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "sector.h" // mapstate_t #include "zstring.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum, int const nDist, int32_t const nReturn); int32_t VM_ExecuteEvent(int const nEventID, int const spriteNum, int const playerNum, int const nDist); @@ -121,6 +121,6 @@ int G_StartTrack(int levelNum); void VM_UpdateAnim(int const spriteNum, int32_t * const pData); void VM_GetZRange(int const spriteNum, int32_t * const ceilhit, int32_t * const florhit, int const wallDist); -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/gamestructures.cpp b/source/duke3d/src/gamestructures.cpp index 462ec5761..ace4cbc08 100644 --- a/source/duke3d/src/gamestructures.cpp +++ b/source/duke3d/src/gamestructures.cpp @@ -28,7 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "gameexec.h" #include "global.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define LABEL_SETUP_UNMATCHED(struct, memb, name, idx) \ { \ @@ -1969,4 +1969,4 @@ void VM_InitHashTables(void) } //#undef STRUCT_HASH_SETUP -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/gamestructures.h b/source/duke3d/src/gamestructures.h index b5bce04b7..adfb4e895 100644 --- a/source/duke3d/src/gamestructures.h +++ b/source/duke3d/src/gamestructures.h @@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "compat.h" #include "hash.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS int32_t __fastcall VM_GetUserdef(int32_t labelNum, int const lParm2); void __fastcall VM_SetUserdef(int const labelNum, int const lParm2, int32_t const newValue); @@ -85,7 +85,7 @@ static hashtable_t *const vmStructHashTablePtrs[] = { &h_actor, &h_input, &h_paldata, &h_player, &h_projectile, &h_sector, &h_tiledata, &h_tsprite, &h_userdef, &h_wall, }; -END_DUKE_NS +END_EDUKE_NS #endif // gamestructures_h__ \ No newline at end of file diff --git a/source/duke3d/src/gamevars.cpp b/source/duke3d/src/gamevars.cpp index 667ce6977..f652f8a0f 100644 --- a/source/duke3d/src/gamevars.cpp +++ b/source/duke3d/src/gamevars.cpp @@ -29,7 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "menu.h" #include "gamestructures.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS gamevar_t aGameVars[MAXGAMEVARS]; gamearray_t aGameArrays[MAXGAMEARRAYS]; int32_t g_gameVarCount = 0; @@ -1417,4 +1417,4 @@ void Gv_RefreshPointers(void) aGameArrays[Gv_GetArrayIndex("tilesizx")].pValues = (intptr_t *)tileWidth; aGameArrays[Gv_GetArrayIndex("tilesizy")].pValues = (intptr_t *)tileHeight; } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/gamevars.h b/source/duke3d/src/gamevars.h index 8fd40cc09..2461bc0ee 100644 --- a/source/duke3d/src/gamevars.h +++ b/source/duke3d/src/gamevars.h @@ -27,7 +27,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "gamedef.h" #include "filesystem.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define MAXGAMEVARS 2048 // must be a power of two @@ -283,6 +283,6 @@ VM_GAMEVAR_OPERATOR(Gv_ShiftVarR, >>=) #undef VM_GAMEVAR_OPERATOR -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/global.cpp b/source/duke3d/src/global.cpp index efddc8e1d..25676b1c9 100644 --- a/source/duke3d/src/global.cpp +++ b/source/duke3d/src/global.cpp @@ -26,7 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "global.h" #include "duke3d.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS user_defs ud; @@ -124,4 +124,4 @@ int16_t g_blimpSpawnItems[15] = char CheatKeys[2] = { sc_D, sc_N }; -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/global.h b/source/duke3d/src/global.h index 2e4c5424b..2331bdc93 100644 --- a/source/duke3d/src/global.h +++ b/source/duke3d/src/global.h @@ -32,7 +32,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "sounds.h" #include "menu.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #ifdef global_c_ #define G_EXTERN @@ -205,7 +205,7 @@ EXTERN_INLINE void G_RestoreInterpolations(void) //Stick at end of drawscreen #endif -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/inv.h b/source/duke3d/src/inv.h index c67af156d..a8dd1c513 100644 --- a/source/duke3d/src/inv.h +++ b/source/duke3d/src/inv.h @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #pragma once -BEGIN_DUKE_NS +BEGIN_EDUKE_NS enum dukeinv_t { @@ -76,4 +76,4 @@ enum dukeweapon_t MAX_WEAPONS }; -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/keys.h b/source/duke3d/src/keys.h index 90fede7cd..1ddb0746d 100644 --- a/source/duke3d/src/keys.h +++ b/source/duke3d/src/keys.h @@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define KEYS_H -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define NUM_CODES 128 @@ -147,6 +147,6 @@ BEGIN_DUKE_NS #define asc_Enter 13 #define asc_Space 32 -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/macros.h b/source/duke3d/src/macros.h index 7c5b23eb1..25ae0b6ab 100644 --- a/source/duke3d/src/macros.h +++ b/source/duke3d/src/macros.h @@ -25,7 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mmulti.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS // Macros, some from SW source @@ -190,6 +190,6 @@ BEGIN_DUKE_NS #define T5(i) actor[i].t_data[4] #define T6(i) actor[i].t_data[5] -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/menus.h b/source/duke3d/src/menus.h index 4d33c01c4..c13e80c85 100644 --- a/source/duke3d/src/menus.h +++ b/source/duke3d/src/menus.h @@ -25,7 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "compat.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS // a subset of screentext parameters, restricted because menus require accessibility struct MenuFont_t @@ -57,6 +57,6 @@ inline int G_CheckPlayerColor(int color) } -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/namesdyn.cpp b/source/duke3d/src/namesdyn.cpp index 7bfe19896..7631fec3b 100644 --- a/source/duke3d/src/namesdyn.cpp +++ b/source/duke3d/src/namesdyn.cpp @@ -29,7 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "global.h" #include "gamecontrol.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS # define DVPTR(x) &x @@ -1375,4 +1375,4 @@ void G_InitDynamicTiles(void) WeaponPickupSprites[11] = SHRINKERSPRITE; WeaponPickupSprites[12] = FLAMETHROWERSPRITE; } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/namesdyn.h b/source/duke3d/src/namesdyn.h index 225f5c6d1..d11d153f1 100644 --- a/source/duke3d/src/namesdyn.h +++ b/source/duke3d/src/namesdyn.h @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef namesdyn_h__ #define namesdyn_h__ -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define SECTOREFFECTOR__STATIC 1 @@ -1295,6 +1295,6 @@ extern int32_t E32_TILE5846; #define DYNAMICTILEMAP(Tilenum) (DynamicTileMap[Tilenum]) -END_DUKE_NS +END_EDUKE_NS #endif // namesdyn_h__ diff --git a/source/duke3d/src/network.cpp b/source/duke3d/src/network.cpp index 6a1342237..09fde13bb 100644 --- a/source/duke3d/src/network.cpp +++ b/source/duke3d/src/network.cpp @@ -45,7 +45,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "m_crc32.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS // Data needed even if netcode is disabled ENetHost *g_netServer = NULL; @@ -5317,4 +5317,4 @@ static int osdcmd_kickban(CCmdFuncPtr parm) #endif //------------------------------------------------------------------------------------------------- -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/network.h b/source/duke3d/src/network.h index a5af3dbaa..d60d046d9 100644 --- a/source/duke3d/src/network.h +++ b/source/duke3d/src/network.h @@ -35,7 +35,7 @@ struct ENetHost; struct ENetPeer; struct ENetAddress; -BEGIN_DUKE_NS +BEGIN_EDUKE_NS // net packet specification/compatibility version #define NETVERSION 1 @@ -360,6 +360,6 @@ void Net_PrintLag(FString& output); #endif -END_DUKE_NS +END_EDUKE_NS #endif // netplay_h_ diff --git a/source/duke3d/src/osdcmds.cpp b/source/duke3d/src/osdcmds.cpp index 038b15af2..f28ead067 100644 --- a/source/duke3d/src/osdcmds.cpp +++ b/source/duke3d/src/osdcmds.cpp @@ -33,7 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "sbar.h" #include "mapinfo.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS struct osdcmd_cheatsinfo osdcmd_cheatsinfo_stat = { -1, 0, 0 }; @@ -658,4 +658,4 @@ int32_t registerosdcommands(void) return 0; } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/osdcmds.h b/source/duke3d/src/osdcmds.h index b9ebd615e..ca86d709c 100644 --- a/source/duke3d/src/osdcmds.h +++ b/source/duke3d/src/osdcmds.h @@ -24,7 +24,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #define osdcmds_h_ #include -BEGIN_DUKE_NS +BEGIN_EDUKE_NS struct osdcmd_cheatsinfo { int32_t cheatnum; // -1 = none, else = see DoCheats() @@ -39,7 +39,7 @@ int32_t registerosdcommands(void); extern const char *const ConsoleButtons[]; -END_DUKE_NS +END_EDUKE_NS #endif // osdcmds_h_ diff --git a/source/duke3d/src/player.cpp b/source/duke3d/src/player.cpp index a174c03d2..d9eaebdfd 100644 --- a/source/duke3d/src/player.cpp +++ b/source/duke3d/src/player.cpp @@ -34,7 +34,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "i_specialpaths.h" #include "savegamehelp.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS int32_t lastvisinc; @@ -5924,4 +5924,4 @@ int portableBackupSave(const char * path, const char * name, int volume, int lev return 0; } #endif -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/player.h b/source/duke3d/src/player.h index 22547507d..f824d5f09 100644 --- a/source/duke3d/src/player.h +++ b/source/duke3d/src/player.h @@ -26,7 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "build.h" #include "inv.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS extern int32_t g_mostConcurrentPlayers; @@ -384,6 +384,6 @@ static inline int P_Get(int32_t spriteNum) { return P_GetP((uspriteptr_t)&sprite extern int portableBackupSave(const char *, const char *, int, int); -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/premap.cpp b/source/duke3d/src/premap.cpp index 21f6893b8..be961cbf7 100644 --- a/source/duke3d/src/premap.cpp +++ b/source/duke3d/src/premap.cpp @@ -36,7 +36,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "v_2ddrawer.h" #include "secrets.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS static uint8_t precachehightile[2][(MAXTILES+7)>>3]; static int32_t g_precacheCount; @@ -1930,4 +1930,4 @@ void G_FreeMapState(int levelNum) ALIGNED_FREE_AND_NULL(board.savedstate); } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/premap.h b/source/duke3d/src/premap.h index b3a80597c..30be3ba9c 100644 --- a/source/duke3d/src/premap.h +++ b/source/duke3d/src/premap.h @@ -23,7 +23,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef premap_h_ #define premap_h_ -BEGIN_DUKE_NS +BEGIN_EDUKE_NS extern int32_t g_levelTextTime; extern int32_t voting,vote_map,vote_episode; @@ -43,6 +43,6 @@ void G_ClearFIFO(void); void G_ResetInterpolations(void); int fragbarheight(void); -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/savegame.cpp b/source/duke3d/src/savegame.cpp index c79b896fa..a996994af 100644 --- a/source/duke3d/src/savegame.cpp +++ b/source/duke3d/src/savegame.cpp @@ -35,7 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mapinfo.h" #include "raze_music.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS // For storing pointers in files. // back_p==0: ptr -> "small int" @@ -1886,4 +1886,4 @@ static void postloadplayer(int32_t savegamep) } ////////// END GENERIC SAVING/LOADING SYSTEM ////////// -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/savegame.h b/source/duke3d/src/savegame.h index 46503dfb6..0f4e9952c 100644 --- a/source/duke3d/src/savegame.h +++ b/source/duke3d/src/savegame.h @@ -25,7 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "game.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define SV_MAJOR_VER 1 @@ -86,6 +86,6 @@ void G_Util_PtrToIdx(void *ptr, int32_t count, const void *base, int32_t mode); void G_Util_PtrToIdx2(void *ptr, int32_t count, size_t stride, const void *base, int32_t mode); -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/sbar.cpp b/source/duke3d/src/sbar.cpp index 94651edff..65008c06d 100644 --- a/source/duke3d/src/sbar.cpp +++ b/source/duke3d/src/sbar.cpp @@ -26,7 +26,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "compat.h" #include "sbar.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS static int32_t sbarx(int32_t x) { @@ -1128,4 +1128,4 @@ void G_DrawBackground(void) pus = pub = NUMPAGES; } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/sbar.h b/source/duke3d/src/sbar.h index 6a6ce5bdd..3d9842577 100644 --- a/source/duke3d/src/sbar.h +++ b/source/duke3d/src/sbar.h @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #pragma once -BEGIN_DUKE_NS +BEGIN_EDUKE_NS static FORCE_INLINE int32_t sbarsc(int32_t sc) { @@ -39,4 +39,4 @@ static FORCE_INLINE int32_t sbartile(void) return WORLDTOUR ? WIDESCREENSTATUSBAR : BOTTOMSTATUSBAR; } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/screens.cpp b/source/duke3d/src/screens.cpp index 4a9014b6f..105871b37 100644 --- a/source/duke3d/src/screens.cpp +++ b/source/duke3d/src/screens.cpp @@ -35,7 +35,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mapinfo.h" #include "v_2ddrawer.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define quotepulseshade (sintable[((uint32_t)totalclock<<5)&2047]>>11) @@ -2188,4 +2188,4 @@ void G_BonusScreen(int32_t bonusonly) } while (1); } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/screens.h b/source/duke3d/src/screens.h index 8c4ad1fc1..8a1fd5f76 100644 --- a/source/duke3d/src/screens.h +++ b/source/duke3d/src/screens.h @@ -20,7 +20,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ //------------------------------------------------------------------------- -BEGIN_DUKE_NS +BEGIN_EDUKE_NS extern void G_DisplayExtraScreens(void); extern void G_DisplayLogo(void); @@ -41,4 +41,4 @@ extern int32_t g_noLogoAnim, g_noLogo; extern void G_FadePalette(int32_t r, int32_t g, int32_t b, int32_t e); -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/sector.cpp b/source/duke3d/src/sector.cpp index c90a40bd6..d7434226b 100644 --- a/source/duke3d/src/sector.cpp +++ b/source/duke3d/src/sector.cpp @@ -31,7 +31,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "v_video.h" #include "glbackend/glbackend.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS // PRIMITIVE @@ -3532,4 +3532,4 @@ void P_CheckSectors(int playerNum) } } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/sector.h b/source/duke3d/src/sector.h index e35c5a8d2..0ccbc6632 100644 --- a/source/duke3d/src/sector.h +++ b/source/duke3d/src/sector.h @@ -29,7 +29,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "namesdyn.h" // for G_GetForcefieldPicnum() #include "player.h" // playerspawn_t -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define MAXCYCLERS 1024 #define MAXANIMATES 1024 @@ -176,6 +176,6 @@ EXTERN_INLINE int32_t G_GetPlayerInSector(int32_t const sect) #endif -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/sounds.cpp b/source/duke3d/src/sounds.cpp index 3a0086d77..b6476cded 100644 --- a/source/duke3d/src/sounds.cpp +++ b/source/duke3d/src/sounds.cpp @@ -28,7 +28,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "mapinfo.h" #include "raze_sound.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS class DukeSoundEngine : public SoundEngine @@ -607,4 +607,4 @@ void S_ContinueLevelMusic(void) } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/sounds.h b/source/duke3d/src/sounds.h index a48dd5bea..a4a760f9d 100644 --- a/source/duke3d/src/sounds.h +++ b/source/duke3d/src/sounds.h @@ -33,7 +33,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "raze_sound.h" #include "raze_music.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define MAXSOUNDS 4096 #define LOUDESTVOLUME 111 @@ -75,6 +75,6 @@ static inline bool S_IsAmbientSFX(int spriteNum) return (sprite[spriteNum].picnum == MUSICANDSFX && sprite[spriteNum].lotag < 999); } -END_DUKE_NS +END_EDUKE_NS #endif diff --git a/source/duke3d/src/soundsdyn.cpp b/source/duke3d/src/soundsdyn.cpp index 3022ec352..3a678d76b 100644 --- a/source/duke3d/src/soundsdyn.cpp +++ b/source/duke3d/src/soundsdyn.cpp @@ -30,7 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "soundsdyn.h" #include "global.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #ifdef DYNSOUNDREMAP_ENABLE # define DVPTR(x) &x @@ -386,4 +386,4 @@ void G_InitDynamicSounds(void) #endif } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/soundsdyn.h b/source/duke3d/src/soundsdyn.h index 84a836a6b..b5da53dc6 100644 --- a/source/duke3d/src/soundsdyn.h +++ b/source/duke3d/src/soundsdyn.h @@ -22,7 +22,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #ifndef soundsdyn_h__ #define soundsdyn_h__ -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define DYNSOUNDREMAP_ENABLE @@ -339,6 +339,6 @@ extern int32_t E5L7_DUKE_QUIT_YOU; #endif -END_DUKE_NS +END_EDUKE_NS #endif // soundsdyn_h__ diff --git a/source/duke3d/src/text.cpp b/source/duke3d/src/text.cpp index cd51778aa..7ee8719a6 100644 --- a/source/duke3d/src/text.cpp +++ b/source/duke3d/src/text.cpp @@ -30,7 +30,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "quotemgr.h" #include "c_dispatch.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS // assign the character's tilenum int GameInterface::GetStringTile(int font, const char* t, int f) @@ -369,4 +369,4 @@ void GameInterface::DoPrintMessage(int prio, const char* t) } -END_DUKE_NS +END_EDUKE_NS diff --git a/source/duke3d/src/text.h b/source/duke3d/src/text.h index f367fed3a..7086191de 100644 --- a/source/duke3d/src/text.h +++ b/source/duke3d/src/text.h @@ -25,7 +25,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "screentext.h" #include "menus.h" -BEGIN_DUKE_NS +BEGIN_EDUKE_NS #define MAXUSERQUOTES 6 @@ -63,4 +63,4 @@ extern void G_PrintGameText(int32_t tile, int32_t x, int32_t y, const char *t, int32_t x1, int32_t y1, int32_t x2, int32_t y2, int32_t z, int32_t a); -END_DUKE_NS +END_EDUKE_NS