Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • STJr/SRB2
  • Sryder/SRB2
  • wolfy852/SRB2
  • Alpha2244/SRB2
  • Inuyasha/SRB2
  • yoshibot/SRB2
  • TehRealSalt/SRB2
  • PrisimaTF/SRB2
  • Hatninja/SRB2
  • SteelT/SRB2
  • james/SRB2
  • ShaderWraith/SRB2
  • SinnamonLat/SRB2
  • mazmazz_/SRB2
  • filpAM/SRB2
  • chaoloveicemdboy/SRB2
  • Whooa21/SRB2
  • Machturne/SRB2
  • Golden/SRB2
  • Tatsuru/SRB2
  • Snu/SRB2
  • Zwip-Zwap_Zapony/SRB2
  • fickleheart/SRB2
  • alphaRexJames/SRB2
  • JJK/SRB2
  • diskpoppy/SRB2
  • Hannu_Hanhi/SRB2
  • ZipperQR/SRB2
  • kays/SRB2
  • spherallic/SRB2
  • Zippy_Zolton/SRB2
  • namiishere/SRB2
  • Ors/SRB2
  • SMS_Alfredo/SRB2
  • sonic_edge/SRB2
  • lavla/SRB2
  • ashi/SRB2
  • X.organic/SRB2
  • Fafabis/SRB2
  • Meziu/SRB2
  • v-rob/SRB2
  • tertu/SRB2
  • bitten2up/SRB2
  • flarn2006/SRB2
  • Krabs/SRB2
  • clairebun/SRB2
  • Lactozilla/SRB2
  • thehackstack/SRB2
  • Spice/SRB2
  • win8linux/SRB2
  • JohnFrostFox/SRB2
  • talktoneon726/SRB2
  • Wane/SRB2
  • Lamibe/SRB2
  • spectrumuk2/srb-2
  • nerdyminer18/srb-2
  • 256nil/SRB2
  • ARJr/SRB2
  • Alam/SRB2
  • Zenya/srb-2-marathon-demos
  • Acelite/srb-2-archivedmodifications
  • MIDIMan/SRB2
  • Lach/SRB2
  • Frostiikin/bounce-tweaks
  • Jaden/SRB2
  • Tyron/SRB2
  • Astronight/SRB2
  • Mari0shi06/SRB2
  • aiire/SRB2
  • Galactice/SRB2
  • srb2-ports/srb2-dreamcast
  • sdasdas/SRB2
  • chreas/srb-2-vr
  • StarManiaKG/the-story-of-sinically-rocketing-and-botching-the-2nd
  • LoganAir/SRB2
  • NepDisk/srb-2
  • alufolie91/SRB2
  • Felicia.iso/SRB2
  • twi/SRB2
  • BarrelsOFun/SRB2
  • Speed2411/SRB2
  • Leather_Realms/SRB2
  • Ayemar/SRB2
  • Acelite/SRB2
  • VladDoc/SRB2
  • kaldrum/model-features
  • strawberryfox417/SRB2
  • Lugent/SRB2
  • Rem/SRB2
  • Refrag/SRB2
  • Henry_3230/srb-3230
  • TehPuertoRicanSpartan2/tprs-srb2
  • Leminn/srb-2-marathon-stuff
  • chromaticpipe2/SRB2
  • MiguelGustavo15/SRB2
  • Maru/srb-2-tests
  • SilicDev/SRB2
  • UnmatchedBracket/SRB2
  • HybridDog/SRB2
  • xordspar0/SRB2
  • jsjhbewfhh/SRB2
  • Fancy2209/SRB2
  • Lorsoen/SRB2
  • shindoukin/SRB2
  • GamerOfDays/SRB2
  • Craftyawesome/SRB2
  • tenshi-tensai-tennoji/SRB2
  • Scarfdudebalder/SRB2
  • luigi-budd/srb-2-fix-interplag-lockon
  • mskluesner/SRB2
  • johnpetersa19/SRB2
  • Pheazant/SRB2
  • chromaticpipe2/srb2classic
  • romoney5/SRB2
  • PAS/SRB2Classic
  • BlueStaggo/SRB2
  • Jisk/srb-2-beef-jerky
117 results
Select Git revision
Show changes
Commits on Source (70)
......@@ -10479,12 +10479,84 @@ static inline int lib_getenum(lua_State *L)
} else if (fastcmp(word,"paused")) {
lua_pushboolean(L, paused);
return 1;
// begin map vars
} else if (fastcmp(word,"spstage_start")) {
lua_pushinteger(L, spstage_start);
return 1;
} else if (fastcmp(word,"sstage_start")) {
lua_pushinteger(L, sstage_start);
return 1;
} else if (fastcmp(word,"sstage_end")) {
lua_pushinteger(L, sstage_end);
return 1;
} else if (fastcmp(word,"smpstage_start")) {
lua_pushinteger(L, smpstage_start);
return 1;
} else if (fastcmp(word,"smpstage_end")) {
lua_pushinteger(L, smpstage_end);
return 1;
} else if (fastcmp(word,"titlemap")) {
lua_pushinteger(L, titlemap);
return 1;
} else if (fastcmp(word,"titlemapinaction")) {
lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF));
return 1;
} else if (fastcmp(word,"bootmap")) {
lua_pushinteger(L, bootmap);
return 1;
} else if (fastcmp(word,"tutorialmap")) {
lua_pushinteger(L, tutorialmap);
return 1;
} else if (fastcmp(word,"tutorialmode")) {
lua_pushboolean(L, tutorialmode);
return 1;
// end map vars
// begin CTF colors
} else if (fastcmp(word,"skincolor_redteam")) {
lua_pushinteger(L, skincolor_redteam);
return 1;
} else if (fastcmp(word,"skincolor_blueteam")) {
lua_pushinteger(L, skincolor_blueteam);
return 1;
} else if (fastcmp(word,"skincolor_redring")) {
lua_pushinteger(L, skincolor_redring);
return 1;
} else if (fastcmp(word,"skincolor_bluering")) {
lua_pushinteger(L, skincolor_bluering);
return 1;
// end CTF colors
// begin timers
} else if (fastcmp(word,"invulntics")) {
lua_pushinteger(L, invulntics);
return 1;
} else if (fastcmp(word,"sneakertics")) {
lua_pushinteger(L, sneakertics);
return 1;
} else if (fastcmp(word,"flashingtics")) {
lua_pushinteger(L, flashingtics);
return 1;
} else if (fastcmp(word,"tailsflytics")) {
lua_pushinteger(L, tailsflytics);
return 1;
} else if (fastcmp(word,"underwatertics")) {
lua_pushinteger(L, underwatertics);
return 1;
} else if (fastcmp(word,"spacetimetics")) {
lua_pushinteger(L, spacetimetics);
return 1;
} else if (fastcmp(word,"extralifetics")) {
lua_pushinteger(L, extralifetics);
return 1;
} else if (fastcmp(word,"nightslinktics")) {
lua_pushinteger(L, nightslinktics);
return 1;
} else if (fastcmp(word,"gameovertics")) {
lua_pushinteger(L, gameovertics);
return 1;
} else if (fastcmp(word,"ammoremovaltics")) {
lua_pushinteger(L, ammoremovaltics);
return 1;
// end timers
} else if (fastcmp(word,"gametype")) {
lua_pushinteger(L, gametype);
return 1;
......
......@@ -2664,23 +2664,17 @@ static int lib_gSetCustomExitVars(lua_State *L)
// Supported:
// G_SetCustomExitVars(); [reset to defaults]
// G_SetCustomExitVars(int) [nextmap override only]
// G_SetCustomExitVars(bool) [skipstats only]
// G_SetCustomExitVars(int, bool) [both of the above]
// G_SetCustomExitVars(nil, int) [skipstats only]
// G_SetCustomExitVars(int, int) [both of the above]
nextmapoverride = 0;
skipstats = 0;
if (n >= 1)
{
if (lua_isnumber(L, 1) || n >= 2)
{
nextmapoverride = (INT16)luaL_checknumber(L, 1);
lua_remove(L, 1); // remove nextmapoverride; skipstats now 1 if available
}
skipstats = luaL_optinteger(L, 2, 0);
}
else
{
nextmapoverride = 0;
skipstats = 0;
nextmapoverride = (INT16)luaL_optinteger(L, 1, 0);
skipstats = (INT16)luaL_optinteger(L, 2, 0);
}
// ---
return 0;
}
......
......@@ -21,6 +21,7 @@ enum hud {
// Match / CTF / Tag / Ringslinger
hud_weaponrings,
hud_powerstones,
hud_teamscores,
// NiGHTS mode
hud_nightslink,
hud_nightsdrill,
......
......@@ -48,6 +48,7 @@ static const char *const hud_disable_options[] = {
"weaponrings",
"powerstones",
"teamscores",
"nightslink",
"nightsdrill",
......
......@@ -445,7 +445,7 @@ static int sectorlines_get(lua_State *L)
// get the "linecount" by shifting our retrieved memory address of "lines" to where "linecount" is in the sector_t, then dereferencing the result
// we need this to determine the array's actual size, and therefore also the maximum value allowed as an index
// this only works if seclines is actually a pointer to a sector's lines member in memory, oh boy
numoflines = (size_t)(*(seclines - (offsetof(sector_t, lines) - offsetof(sector_t, linecount))));
numoflines = (size_t)(*(size_t *)(((size_t)seclines) - (offsetof(sector_t, lines) - offsetof(sector_t, linecount))));
/* OLD HACK
// check first linedef to figure which of its sectors owns this sector->lines pointer
......@@ -479,7 +479,7 @@ static int sectorlines_num(lua_State *L)
return luaL_error(L, "accessed sector_t.lines doesn't exist anymore.");
// see comments in the _get function above
numoflines = (size_t)(*(seclines - (offsetof(sector_t, lines) - offsetof(sector_t, linecount))));
numoflines = (size_t)(*(size_t *)(((size_t)seclines) - (offsetof(sector_t, lines) - offsetof(sector_t, linecount))));
lua_pushinteger(L, numoflines);
return 1;
}
......
......@@ -1106,7 +1106,7 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
#else
fixed_t cheight = sec->ceilingheight;
#endif
mt->options = (UINT16)((cheight - player->mo->z - player->mo->height)>>FRACBITS);
mt->z = (UINT16)((cheight - player->mo->z - player->mo->height)>>FRACBITS);
}
else
{
......@@ -1115,12 +1115,11 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
#else
fixed_t fheight = sec->floorheight;
#endif
mt->options = (UINT16)((player->mo->z - fheight)>>FRACBITS);
mt->z = (UINT16)((player->mo->z - fheight)>>FRACBITS);
}
mt->options <<= ZSHIFT;
mt->angle = (INT16)(FixedInt(AngleFixed(player->mo->angle)));
mt->options |= (UINT16)cv_opflags.value;
mt->options = (mt->z << ZSHIFT) | (UINT16)cv_opflags.value;
return mt;
}
......
......@@ -13614,12 +13614,12 @@ static boolean PIT_DustDevilLaunch(mobj_t *thing)
}
else
{ //Player on the top of the tornado.
P_ResetPlayer(player);
thing->z = dustdevil->z + dustdevil->height;
thrust = 20 * FRACUNIT;
player->powers[pw_nocontrol] = 0;
S_StartSound(thing, sfx_wdjump);
P_SetPlayerMobjState(thing, S_PLAY_FALL);
player->pflags &= ~PF_JUMPED;
}
thing->momz = thrust;
......@@ -14712,20 +14712,35 @@ void A_DragonWing(mobj_t *actor)
void A_DragonSegment(mobj_t *actor)
{
mobj_t *target = actor->target;
fixed_t dist = P_AproxDistance(P_AproxDistance(actor->x - target->x, actor->y - target->y), actor->z - target->z);
fixed_t radius = actor->radius + target->radius;
angle_t hangle = R_PointToAngle2(target->x, target->y, actor->x, actor->y);
angle_t zangle = R_PointToAngle2(0, target->z, dist, actor->z);
fixed_t hdist = P_ReturnThrustX(target, zangle, radius);
fixed_t xdist = P_ReturnThrustX(target, hangle, hdist);
fixed_t ydist = P_ReturnThrustY(target, hangle, hdist);
fixed_t zdist = P_ReturnThrustY(target, zangle, radius);
fixed_t dist;
fixed_t radius;
angle_t hangle;
angle_t zangle;
fixed_t hdist;
fixed_t xdist;
fixed_t ydist;
fixed_t zdist;
#ifdef HAVE_BLUA
if (LUA_CallAction("A_DragonSegment", actor))
return;
#endif
if (target == NULL || !target->health)
{
P_RemoveMobj(actor);
return;
}
dist = P_AproxDistance(P_AproxDistance(actor->x - target->x, actor->y - target->y), actor->z - target->z);
radius = actor->radius + target->radius;
hangle = R_PointToAngle2(target->x, target->y, actor->x, actor->y);
zangle = R_PointToAngle2(0, target->z, dist, actor->z);
hdist = P_ReturnThrustX(target, zangle, radius);
xdist = P_ReturnThrustX(target, hangle, hdist);
ydist = P_ReturnThrustY(target, hangle, hdist);
zdist = P_ReturnThrustY(target, zangle, radius);
actor->angle = hangle;
P_TeleportMove(actor, target->x + xdist, target->y + ydist, target->z + zdist);
}
......@@ -7833,7 +7833,8 @@ void P_MobjThinker(mobj_t *mobj)
boolean dojump = false, targonground, love, makeheart = false;
if (mobj->target != player->mo)
P_SetTarget(&mobj->target, player->mo);
targonground = (P_IsObjectOnGround(mobj->target) && (player->panim == PA_IDLE || player->panim == PA_WALK || player->panim == PA_RUN));
// Tatsuru: Don't try to hug them if they're above or below you!
targonground = (P_IsObjectOnGround(mobj->target) && (player->panim == PA_IDLE || player->panim == PA_WALK || player->panim == PA_RUN) && player->mo->z == mobj->z);
love = (player->skin == 0 || player->skin == 5);
switch (stat)
......@@ -11120,6 +11121,19 @@ void P_PrecipitationEffects(void)
}
}
/** Returns corresponding mobj type from mapthing number.
* \param mthingtype Mapthing number in question.
* \return Mobj type; MT_UNKNOWN if nothing found.
*/
static mobjtype_t P_GetMobjtype(UINT16 mthingtype)
{
mobjtype_t i;
for (i = 0; i < NUMMOBJTYPES; i++)
if (mthingtype == mobjinfo[i].doomednum)
return i;
return MT_UNKNOWN;
}
//
// P_RespawnSpecials
//
......@@ -11158,17 +11172,12 @@ void P_RespawnSpecials(void)
if (mthing)
{
mobjtype_t i;
mobjtype_t i = P_GetMobjtype(mthing->type);
x = mthing->x << FRACBITS;
y = mthing->y << FRACBITS;
ss = R_PointInSubsector(x, y);
// find which type to spawn
for (i = 0; i < NUMMOBJTYPES; i++)
if (mthing->type == mobjinfo[i].doomednum)
break;
if (i == NUMMOBJTYPES) // prevent creation of objects with this type -- Monster Iestyn 17/12/17
if (i == MT_UNKNOWN) // prevent creation of objects with this type -- Monster Iestyn 17/12/17
{
// 3D Mode start Thing is unlikely to be added to the que,
// so don't bother checking for that specific type
......@@ -11550,43 +11559,109 @@ void P_MovePlayerToStarpost(INT32 playernum)
mapthing_t *huntemeralds[MAXHUNTEMERALDS];
INT32 numhuntemeralds;
//
// P_SpawnMapThing
// The fields of the mapthing should
// already be in host byte order.
//
void P_SpawnMapThing(mapthing_t *mthing)
{
mobjtype_t i;
mobj_t *mobj;
fixed_t x, y, z;
subsector_t *ss;
boolean doangle = true;
if (!mthing->type)
return; // Ignore type-0 things as NOPs
static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y)
{
const subsector_t *ss = R_PointInSubsector(x, y);
fixed_t offset = mthing->z << FRACBITS;
boolean flip = (!!(mobjinfo[mobjtype].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP));
// Always spawn in objectplace.
// Skip all returning code.
if (objectplacing)
switch (mobjtype)
{
// find which type to spawn
for (i = 0; i < NUMMOBJTYPES; i++)
if (mthing->type == mobjinfo[i].doomednum)
break;
// Bumpers never spawn flipped.
case MT_NIGHTSBUMPER:
flip = false;
break;
if (i == NUMMOBJTYPES)
{
if (mthing->type == 3328) // 3D Mode start Thing
return;
CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y);
i = MT_UNKNOWN;
}
goto noreturns;
// Axis objects snap to the floor.
case MT_AXIS:
case MT_AXISTRANSFER:
case MT_AXISTRANSFERLINE:
return ONFLOORZ;
// Objects with a non-zero default height.
case MT_CRAWLACOMMANDER:
case MT_DETON:
case MT_JETTBOMBER:
case MT_JETTGUNNER:
case MT_EGGMOBILE2:
if (!offset)
offset = 33*FRACUNIT;
break;
case MT_EGGMOBILE:
if (!offset)
offset = 128*FRACUNIT;
break;
case MT_GOLDBUZZ:
case MT_REDBUZZ:
if (!offset)
offset = 288*FRACUNIT;
break;
// Horizontal springs, may float additional units with MTF_AMBUSH.
case MT_YELLOWHORIZ:
case MT_REDHORIZ:
case MT_BLUEHORIZ:
offset += mthing->options & MTF_AMBUSH ? 16*FRACUNIT : 0;
// Ring-like items, may float additional units with MTF_AMBUSH.
case MT_SPIKEBALL:
case MT_EMERALDSPAWN:
case MT_TOKEN:
case MT_EMBLEM:
case MT_RING:
case MT_REDTEAMRING:
case MT_BLUETEAMRING:
case MT_COIN:
case MT_BLUESPHERE:
case MT_BOMBSPHERE:
case MT_NIGHTSCHIP:
case MT_NIGHTSSTAR:
offset += mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0;
break;
// Remaining objects.
default:
if (P_WeaponOrPanel(mobjtype))
offset += mthing->options & MTF_AMBUSH ? 24*FRACUNIT : 0;
}
// count deathmatch start positions
if (mthing->type == 33)
if (!offset) // Snap to the surfaces when there's no offset set.
{
if (flip)
return ONCEILINGZ;
else
return ONFLOORZ;
}
// Establish height.
if (flip)
return (
#ifdef ESLOPE
ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) :
#endif
ss->sector->ceilingheight) - offset - mobjinfo[mobjtype].height;
else
return (
#ifdef ESLOPE
ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) :
#endif
ss->sector->floorheight) + offset;
}
static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing)
{
#if MAXPLAYERS > 32
You should think about modifying the deathmatch starts to take full advantage of this!
#endif
if (mthing->type <= MAXPLAYERS) // Player starts
{
// save spots for respawning in network games
if (!metalrecording)
playerstarts[mthing->type - 1] = mthing;
return true;
}
else if (mthing->type == 33) // Match starts
{
if (numdmstarts < MAX_DM_STARTS)
{
......@@ -11594,10 +11669,9 @@ void P_SpawnMapThing(mapthing_t *mthing)
mthing->type = 0;
numdmstarts++;
}
return;
return true;
}
else if (mthing->type == 34) // Red CTF Starts
else if (mthing->type == 34) // Red CTF starts
{
if (numredctfstarts < MAXPLAYERS)
{
......@@ -11605,10 +11679,9 @@ void P_SpawnMapThing(mapthing_t *mthing)
mthing->type = 0;
numredctfstarts++;
}
return;
return true;
}
else if (mthing->type == 35) // Blue CTF Starts
else if (mthing->type == 35) // Blue CTF starts
{
if (numbluectfstarts < MAXPLAYERS)
{
......@@ -11616,106 +11689,154 @@ void P_SpawnMapThing(mapthing_t *mthing)
mthing->type = 0;
numbluectfstarts++;
}
return;
}
else if (mthing->type == 750) // Slope vertex point (formerly chaos spawn)
return;
else if (mthing->type == mobjinfo[MT_RING].doomednum || mthing->type == mobjinfo[MT_COIN].doomednum
|| mthing->type == mobjinfo[MT_REDTEAMRING].doomednum || mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum
|| mthing->type == mobjinfo[MT_BLUESPHERE].doomednum || mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum
|| (mthing->type >= 600 && mthing->type <= 609) // circles and diagonals
|| mthing->type == 1705 || mthing->type == 1713) // hoops
{
// Don't spawn hoops, wings, or rings yet!
return;
}
// check for players specially
#if MAXPLAYERS > 32
You should think about modifying the deathmatch starts to take full advantage of this!
#endif
if (mthing->type > 0 && mthing->type <= MAXPLAYERS)
{
// save spots for respawning in network games
if (!metalrecording)
playerstarts[mthing->type-1] = mthing;
return;
return true;
}
if (metalrecording && mthing->type == mobjinfo[MT_METALSONIC_RACE].doomednum)
else if (metalrecording && mthing->type == mobjinfo[MT_METALSONIC_RACE].doomednum)
{ // If recording, you ARE Metal Sonic. Do not spawn it, do not save normal spawnpoints.
playerstarts[0] = mthing;
return;
}
// find which type to spawn
for (i = 0; i < NUMMOBJTYPES; i++)
if (mthing->type == mobjinfo[i].doomednum)
break;
if (i == NUMMOBJTYPES)
{
if (mthing->type == 3328) // 3D Mode start Thing
return;
CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y);
i = MT_UNKNOWN;
return true;
}
else if (mthing->type == 750 // Slope vertex point (formerly chaos spawn)
|| (mthing->type >= 600 && mthing->type <= 609) // Special placement patterns
|| mthing->type == 1705 || mthing->type == 1713) // Hoops
return true; // These are handled elsewhere.
if (metalrecording) // Metal Sonic can't use these things.
if (mobjinfo[i].flags & (MF_ENEMY|MF_BOSS) || i == MT_TOKEN || i == MT_STARPOST)
return;
return false;
}
if (i >= MT_EMERALD1 && i <= MT_EMERALD7) // Pickupable Emeralds
{
static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
{
switch (i)
{
case MT_RING:
case MT_COIN:
case MT_REDTEAMRING:
case MT_BLUETEAMRING:
case MT_BLUESPHERE:
case MT_BOMBSPHERE:
case MT_NIGHTSSTAR:
case MT_NIGHTSCHIP:
return false; // These are handled in P_SpawnHoopsAndRings().
case MT_EMERALD1:
case MT_EMERALD2:
case MT_EMERALD3:
case MT_EMERALD4:
case MT_EMERALD5:
case MT_EMERALD6:
case MT_EMERALD7:
if (gametype != GT_COOP) // Don't place emeralds in non-coop modes
return;
return false;
if (metalrecording)
return; // Metal Sonic isn't for collecting emeralds.
return false; // Metal Sonic isn't for collecting emeralds.
if (emeralds & mobjinfo[i].speed) // You already have this emerald!
return;
}
return false;
if (i == MT_EMERHUNT)
{
break;
case MT_EMERHUNT:
// Emerald Hunt is Coop only.
if (gametype != GT_COOP)
return;
ss = R_PointInSubsector(mthing->x << FRACBITS, mthing->y << FRACBITS);
mthing->z = (INT16)(((
#ifdef ESLOPE
ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, mthing->x << FRACBITS, mthing->y << FRACBITS) :
#endif
ss->sector->floorheight)>>FRACBITS) + (mthing->options >> ZSHIFT));
return false;
if (numhuntemeralds < MAXHUNTEMERALDS)
huntemeralds[numhuntemeralds++] = mthing;
return;
}
if (i == MT_EMERALDSPAWN)
{
return false;
case MT_EMERALDSPAWN:
if (!cv_powerstones.value)
return;
return false;
if (!(gametype == GT_MATCH || gametype == GT_CTF))
return;
return false;
runemeraldmanager = true;
break;
case MT_ROSY:
if (!(gametype == GT_COOP || (mthing->options & MTF_EXTRA)))
return false; // she doesn't hang out here
if (!mariomode && !(netgame || multiplayer) && players[consoleplayer].skin == 3)
return false; // no doubles
break;
case MT_TOKEN:
if (gametype != GT_COOP && gametype != GT_COMPETITION)
return false; // Gametype's not right
if (tokenbits == 30)
return false; // Too many tokens
if (tokenlist & (1 << tokenbits++))
return false; // You already got this token
break;
case MT_EMBLEM:
if (netgame || multiplayer)
return false; // Single player
if (modifiedgame && !savemoddata)
return false; // No cheating!!
break;
default:
break;
}
if (!G_PlatformGametype()) // No enemies in match or CTF modes
if (metalrecording) // Metal Sonic can't use these things.
if (mobjinfo[i].flags & (MF_ENEMY|MF_BOSS) || i == MT_TOKEN || i == MT_STARPOST)
return false;
if (!G_PlatformGametype())
{
if ((mobjinfo[i].flags & MF_ENEMY) || (mobjinfo[i].flags & MF_BOSS))
return;
return false; // No enemies in ringslinger modes
if (i == MT_SIGN || i == MT_STARPOST)
return false; // Don't spawn exit signs or starposts in wrong game modes
}
if (!G_RingSlingerGametype() || !cv_specialrings.value)
if (P_WeaponOrPanel(i))
return; // Don't place weapons/panels in non-ringslinger modes
return false; // Don't place weapons/panels in non-ringslinger modes
if (gametype != GT_CTF) // CTF specific things
{
if (i == MT_BLUEFLAG || i == MT_REDFLAG)
return false; // No flags in non-CTF modes!
}
else
{
if ((i == MT_BLUEFLAG && blueflag) || (i == MT_REDFLAG && redflag))
{
CONS_Alert(CONS_ERROR, M_GetText("Only one flag per team allowed in CTF!\n"));
return false;
}
}
if (modeattacking) // Record Attack special stuff
{
// Don't spawn starposts that wouldn't be usable
if (i == MT_STARPOST)
return false;
}
if (ultimatemode)
{
if (i == MT_PITY_BOX || i == MT_ELEMENTAL_BOX || i == MT_ATTRACT_BOX
|| i == MT_FORCE_BOX || i == MT_ARMAGEDDON_BOX || i == MT_WHIRLWIND_BOX
|| i == MT_FLAMEAURA_BOX || i == MT_BUBBLEWRAP_BOX || i == MT_THUNDERCOIN_BOX
|| i == MT_RING_BOX || i == MT_STARPOST)
return false; // No rings or shields in Ultimate mode
// Don't include the gold repeating boxes here please.
// They're likely facets of the level's design and therefore required to progress.
}
return true;
}
static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i)
{
// Altering monitor spawns via cvars
// If MF_GRENADEBOUNCE is set in the monitor's info,
// skip this step. (Used for gold monitors)
......@@ -11725,267 +11846,676 @@ You should think about modifying the deathmatch starts to take full advantage of
if (gametype == GT_COMPETITION || gametype == GT_RACE)
{
// Set powerup boxes to user settings for competition.
if (cv_competitionboxes.value == 1) // Mystery
i = MT_MYSTERY_BOX;
else if (cv_competitionboxes.value == 2) // Teleport
i = MT_MIXUP_BOX;
else if (cv_competitionboxes.value == 3) // None
return; // Don't spawn!
// default case: normal
switch (cv_competitionboxes.value)
{
case 1: // Mystery
return MT_MYSTERY_BOX;
case 2: // Teleport
return MT_MIXUP_BOX;
case 3: // None
return MT_NULL; // Don't spawn!
default:
return i;
}
}
// Set powerup boxes to user settings for other netplay modes
else if (gametype != GT_COOP)
{
if (cv_matchboxes.value == 1) // Mystery
i = MT_MYSTERY_BOX;
else if (cv_matchboxes.value == 2) // Unchanging
switch (cv_matchboxes.value)
{
case 1: // Mystery
return MT_MYSTERY_BOX;
case 2: // Unchanging
if (i == MT_MYSTERY_BOX)
return; // don't spawn
return MT_NULL; // don't spawn
mthing->options &= ~(MTF_AMBUSH|MTF_OBJECTSPECIAL); // no random respawning!
return i;
case 3: // Don't spawn
return MT_NULL;
default:
return i;
}
else if (cv_matchboxes.value == 3) // Don't spawn
return;
// default case: normal
}
}
if (gametype != GT_CTF) // CTF specific things
{
if (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX)
i = MT_RING_BOX;
else if (i == MT_BLUEFLAG || i == MT_REDFLAG)
return; // No flags in non-CTF modes!
}
else
if (gametype != GT_CTF && (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX))
return MT_RING_BOX;
if (modeattacking && i == MT_1UP_BOX) // 1UPs -->> Score TVs
{
if ((i == MT_BLUEFLAG && blueflag) || (i == MT_REDFLAG && redflag))
{
CONS_Alert(CONS_ERROR, M_GetText("Only one flag per team allowed in CTF!\n"));
return;
}
// Either or, doesn't matter which.
if (mthing->options & (MTF_AMBUSH | MTF_OBJECTSPECIAL))
return MT_SCORE10K_BOX; // 10,000
else
return MT_SCORE1K_BOX; // 1,000
}
if (!G_PlatformGametype() && (i == MT_SIGN || i == MT_STARPOST))
return; // Don't spawn exit signs or starposts in wrong game modes
if (mariomode && i == MT_ROSY)
return MT_TOAD; // don't remove on penalty of death
if (modeattacking) // Record Attack special stuff
{
// Don't spawn starposts that wouldn't be usable
if (i == MT_STARPOST)
return;
return i;
}
// 1UPs -->> Score TVs
else if (i == MT_1UP_BOX) // 1UP
{
// Either or, doesn't matter which.
if (mthing->options & (MTF_AMBUSH|MTF_OBJECTSPECIAL))
i = MT_SCORE10K_BOX; // 10,000
else
i = MT_SCORE1K_BOX; // 1,000
}
}
static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj)
{
INT32 j;
emblem_t* emblem = M_GetLevelEmblems(gamemap);
skincolors_t emcolor;
if (ultimatemode)
while (emblem)
{
if (i == MT_PITY_BOX || i == MT_ELEMENTAL_BOX || i == MT_ATTRACT_BOX
|| i == MT_FORCE_BOX || i == MT_ARMAGEDDON_BOX || i == MT_WHIRLWIND_BOX
|| i == MT_FLAMEAURA_BOX || i == MT_BUBBLEWRAP_BOX || i == MT_THUNDERCOIN_BOX
|| i == MT_RING_BOX || i == MT_STARPOST)
return; // No rings or shields in Ultimate mode
if ((emblem->type == ET_GLOBAL || emblem->type == ET_SKIN) && emblem->tag == mthing->angle)
break;
// Don't include the gold repeating boxes here please.
// They're likely facets of the level's design and therefore required to progress.
emblem = M_GetLevelEmblems(-1);
}
if (i == MT_ROSY)
if (!emblem)
{
if (!(gametype == GT_COOP || (mthing->options & MTF_EXTRA)))
return; // she doesn't hang out here
else if (mariomode)
i = MT_TOAD; // don't remove on penalty of death
else if (!(netgame || multiplayer) && players[consoleplayer].skin == 3)
return; // no doubles
CONS_Debug(DBG_GAMELOGIC, "No map emblem for map %d with tag %d found!\n", gamemap, mthing->angle);
return false;
}
if (i == MT_TOKEN && ((gametype != GT_COOP && gametype != GT_COMPETITION) || tokenbits == 30 || tokenlist & (1 << tokenbits++)))
return; // you already got this token, or there are too many, or the gametype's not right
if (i == MT_EMBLEM && (netgame || multiplayer || (modifiedgame && !savemoddata))) // No cheating!!
return;
j = emblem - emblemlocations;
// Objectplace landing point
noreturns:
I_Assert(emblemlocations[j].sprite >= 'A' && emblemlocations[j].sprite <= 'Z');
P_SetMobjState(mobj, mobj->info->spawnstate + (emblemlocations[j].sprite - 'A'));
// spawn it
x = mthing->x << FRACBITS;
y = mthing->y << FRACBITS;
ss = R_PointInSubsector(x, y);
mobj->health = j + 1;
emcolor = M_GetEmblemColor(&emblemlocations[j]); // workaround for compiler complaint about bad function casting
mobj->color = (UINT8)emcolor;
if (i == MT_NIGHTSBUMPER)
z = (
#ifdef ESLOPE
ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) :
#endif
ss->sector->floorheight) + ((mthing->options >> ZSHIFT) << FRACBITS);
else if (i == MT_AXIS || i == MT_AXISTRANSFER || i == MT_AXISTRANSFERLINE)
z = ONFLOORZ;
else if (i == MT_SPIKEBALL || P_WeaponOrPanel(i) || i == MT_EMERALDSPAWN || i == MT_TOKEN || i == MT_EMBLEM)
if (emblemlocations[j].collected
|| (emblemlocations[j].type == ET_SKIN && emblemlocations[j].var != players[0].skin))
{
if (mthing->options & MTF_OBJECTFLIP)
{
z = (
#ifdef ESLOPE
ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) :
#endif
ss->sector->ceilingheight);
if (mthing->options & MTF_AMBUSH) // Special flag for rings
z -= 24*FRACUNIT;
if (mthing->options >> ZSHIFT)
z -= (mthing->options >> ZSHIFT)*FRACUNIT;
P_UnsetThingPosition(mobj);
mobj->flags |= MF_NOCLIP;
mobj->flags &= ~MF_SPECIAL;
mobj->flags |= MF_NOBLOCKMAP;
mobj->frame |= (tr_trans50 << FF_TRANSSHIFT);
P_SetThingPosition(mobj);
}
else
{
mobj->frame &= ~FF_TRANSMASK;
z -= mobjinfo[i].height; //Don't forget the height!
}
else
if (emblemlocations[j].type == ET_GLOBAL)
{
z = (
#ifdef ESLOPE
ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) :
#endif
ss->sector->floorheight);
if (mthing->options & MTF_AMBUSH) // Special flag for rings
z += 24*FRACUNIT;
if (mthing->options >> ZSHIFT)
z += (mthing->options >> ZSHIFT)*FRACUNIT;
mobj->reactiontime = emblemlocations[j].var;
if (emblemlocations[j].var & GE_NIGHTSITEM)
{
mobj->flags |= MF_NIGHTSITEM;
mobj->flags &= ~MF_SPECIAL;
mobj->flags2 |= MF2_DONTDRAW;
}
}
}
return true;
}
if (z == ONFLOORZ)
mthing->z = 0;
else
mthing->z = (INT16)(z>>FRACBITS);
static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle)
{
fixed_t mlength, mmaxlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor, widthfactor;
angle_t mspokeangle;
mobjtype_t chainlink, macetype, firsttype, linktype;
boolean mdosound, mdocenter, mchainlike = false;
mobj_t *spawnee = NULL, *hprev = mobj;
mobjflag_t mflagsapply;
mobjflag2_t mflags2apply;
mobjeflag_t meflagsapply;
INT32 line;
const size_t mthingi = (size_t)(mthing - mapthings);
// Find the corresponding linedef special, using angle as tag
// P_FindSpecialLineFromTag works here now =D
line = P_FindSpecialLineFromTag(9, mthing->angle, -1);
if (line == -1)
{
CONS_Debug(DBG_GAMELOGIC, "Mace chain (mapthing #%s) needs to be tagged to a #9 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle);
return false;
}
/*
mapthing -
MTF_AMBUSH :
MT_SPRINGBALLPOINT - upgrade from yellow to red spring
anything else - bigger mace/chain theory
MTF_OBJECTSPECIAL - force silent
MTF_GRAVFLIP - flips objects, doesn't affect chain arrangements
Parameter value : number of "spokes"
linedef -
ML_NOCLIMB :
MT_CHAINPOINT/MT_CHAINMACEPOINT with ML_EFFECT1 applied - Direction not controllable
anything else - no functionality
ML_EFFECT1 : Swings instead of spins
ML_EFFECT2 : Linktype is replaced with macetype for all spokes not ending in chains (inverted for MT_FIREBARPOINT)
ML_EFFECT3 : Spawn a bonus linktype at the hinge point
ML_EFFECT4 : Don't clip inside the ground
ML_EFFECT5 : Don't stop thinking when too far away
*/
mlength = abs(lines[line].dx >> FRACBITS);
mspeed = abs(lines[line].dy >> (FRACBITS - 4));
mphase = (sides[lines[line].sidenum[0]].textureoffset >> FRACBITS) % 360;
if ((mminlength = -sides[lines[line].sidenum[0]].rowoffset >> FRACBITS) < 0)
mminlength = 0;
else if (mminlength > mlength - 1)
mminlength = mlength - 1;
mpitch = (lines[line].frontsector->floorheight >> FRACBITS) % 360;
myaw = (lines[line].frontsector->ceilingheight >> FRACBITS) % 360;
mnumspokes = mthing->extrainfo + 1;
mspokeangle = FixedAngle((360*FRACUNIT)/mnumspokes) >> ANGLETOFINESHIFT;
if (lines[line].backsector)
{
mpinch = (lines[line].backsector->floorheight >> FRACBITS) % 360;
mroll = (lines[line].backsector->ceilingheight >> FRACBITS) % 360;
mnumnospokes = (sides[lines[line].sidenum[1]].textureoffset >> FRACBITS);
if ((mwidth = sides[lines[line].sidenum[1]].rowoffset >> FRACBITS) < 0)
mwidth = 0;
}
else
{
fixed_t offset = 0;
boolean flip = (!!(mobjinfo[i].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP));
// base positions
if (flip)
z = (
#ifdef ESLOPE
ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) :
#endif
ss->sector->ceilingheight) - mobjinfo[i].height;
else
z = (
#ifdef ESLOPE
ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) :
#endif
ss->sector->floorheight);
mpinch = mroll = mnumnospokes = mwidth = 0;
CONS_Debug(DBG_GAMELOGIC, "Mace/Chain (mapthing #%s):\n"
"Length is %d (minus %d)\n"
"Speed is %d\n"
"Phase is %d\n"
"Yaw is %d\n"
"Pitch is %d\n"
"No. of spokes is %d (%d antispokes)\n"
"Pinch is %d\n"
"Roll is %d\n"
"Width is %d\n",
sizeu1(mthingi), mlength, mminlength, mspeed, mphase, myaw, mpitch, mnumspokes, mnumnospokes, mpinch, mroll, mwidth);
if (mnumnospokes > 0 && (mnumnospokes < mnumspokes))
mnumnospokes = mnumspokes/mnumnospokes;
else
mnumnospokes = ((mobj->type == MT_CHAINMACEPOINT) ? (mnumspokes) : 0);
// offsetting
if (mthing->options >> ZSHIFT)
offset = ((mthing->options >> ZSHIFT) << FRACBITS);
else if (i == MT_CRAWLACOMMANDER || i == MT_DETON || i == MT_JETTBOMBER || i == MT_JETTGUNNER || i == MT_EGGMOBILE2)
offset = 33*FRACUNIT;
else if (i == MT_EGGMOBILE)
offset = 128*FRACUNIT;
else if (i == MT_GOLDBUZZ || i == MT_REDBUZZ)
offset = 288*FRACUNIT;
mobj->lastlook = mspeed;
mobj->movecount = mobj->lastlook;
mobj->angle = FixedAngle(myaw << FRACBITS);
*doangle = false;
mobj->threshold = (FixedAngle(mpitch << FRACBITS) >> ANGLETOFINESHIFT);
mobj->movefactor = mpinch;
mobj->movedir = 0;
// applying offsets! (if any)
if (flip)
// Mobjtype selection
switch (mobj->type)
{
case MT_SPRINGBALLPOINT:
macetype = ((mthing->options & MTF_AMBUSH)
? MT_REDSPRINGBALL
: MT_YELLOWSPRINGBALL);
chainlink = MT_SMALLMACECHAIN;
break;
case MT_FIREBARPOINT:
macetype = ((mthing->options & MTF_AMBUSH)
? MT_BIGFIREBAR
: MT_SMALLFIREBAR);
chainlink = MT_NULL;
break;
case MT_CUSTOMMACEPOINT:
macetype = (mobjtype_t)sides[lines[line].sidenum[0]].toptexture;
if (lines[line].backsector)
chainlink = (mobjtype_t)sides[lines[line].sidenum[1]].toptexture;
else
chainlink = MT_NULL;
break;
case MT_CHAINPOINT:
if (mthing->options & MTF_AMBUSH)
{
if (offset)
z -= offset;
else
z = ONCEILINGZ;
macetype = MT_BIGGRABCHAIN;
chainlink = MT_BIGMACECHAIN;
}
else
{
if (offset)
z += offset;
else
z = ONFLOORZ;
macetype = MT_SMALLGRABCHAIN;
chainlink = MT_SMALLMACECHAIN;
}
mchainlike = true;
break;
default:
if (mthing->options & MTF_AMBUSH)
{
macetype = MT_BIGMACE;
chainlink = MT_BIGMACECHAIN;
}
if (z == ONFLOORZ)
mthing->z = 0;
else
mthing->z = (INT16)(z>>FRACBITS);
{
macetype = MT_SMALLMACE;
chainlink = MT_SMALLMACECHAIN;
}
break;
}
mobj = P_SpawnMobj(x, y, z, i);
mobj->spawnpoint = mthing;
if (!macetype && !chainlink)
return true;
#ifdef HAVE_BLUA
if (LUAh_MapThingSpawn(mobj, mthing))
if (mobj->type == MT_CHAINPOINT)
{
if (P_MobjWasRemoved(mobj))
return;
if (!mlength)
return true;
}
else if (P_MobjWasRemoved(mobj))
return;
else
#endif
switch(mobj->type)
mlength++;
firsttype = macetype;
// Adjustable direction
if (lines[line].flags & ML_NOCLIMB)
mobj->flags |= MF_SLIDEME;
// Swinging
if (lines[line].flags & ML_EFFECT1)
{
case MT_EMBLEM:
mobj->flags2 |= MF2_STRONGBOX;
mmin = ((mnumnospokes > 1) ? 1 : 0);
}
else
mmin = mnumspokes;
// If over distance away, don't move UNLESS this flag is applied
if (lines[line].flags & ML_EFFECT5)
mobj->flags2 |= MF2_BOSSNOTRAP;
// Make the links the same type as the end - repeated below
if ((mobj->type != MT_CHAINPOINT) && (((lines[line].flags & ML_EFFECT2) == ML_EFFECT2) != (mobj->type == MT_FIREBARPOINT))) // exclusive or
{
linktype = macetype;
radiusfactor = 2; // Double the radius.
}
else
radiusfactor = (((linktype = chainlink) == MT_NULL) ? 2 : 1);
if (!mchainlike)
mchainlike = (firsttype == chainlink);
widthfactor = (mchainlike ? 1 : 2);
mflagsapply = ((lines[line].flags & ML_EFFECT4) ? 0 : (MF_NOCLIP | MF_NOCLIPHEIGHT));
mflags2apply = ((mthing->options & MTF_OBJECTFLIP) ? MF2_OBJECTFLIP : 0);
meflagsapply = ((mthing->options & MTF_OBJECTFLIP) ? MFE_VERTICALFLIP : 0);
msound = (mchainlike ? 0 : (mwidth & 1));
// Quick and easy preparatory variable setting
mphase = (FixedAngle(mphase << FRACBITS) >> ANGLETOFINESHIFT);
mroll = (FixedAngle(mroll << FRACBITS) >> ANGLETOFINESHIFT);
#define makemace(mobjtype, dist, moreflags2) {\
spawnee = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobjtype);\
P_SetTarget(&spawnee->tracer, mobj);\
spawnee->threshold = mphase;\
spawnee->friction = mroll;\
spawnee->movefactor = mwidthset;\
spawnee->movecount = dist;\
spawnee->angle = myaw;\
spawnee->flags |= (MF_NOGRAVITY|mflagsapply);\
spawnee->flags2 |= (mflags2apply|moreflags2);\
spawnee->eflags |= meflagsapply;\
P_SetTarget(&hprev->hnext, spawnee);\
P_SetTarget(&spawnee->hprev, hprev);\
hprev = spawnee;\
}
mdosound = (mspeed && !(mthing->options & MTF_OBJECTSPECIAL));
mdocenter = (macetype && (lines[line].flags & ML_EFFECT3));
// The actual spawning of spokes
while (mnumspokes-- > 0)
{
INT32 j;
emblem_t *emblem = M_GetLevelEmblems(gamemap);
skincolors_t emcolor;
// Offsets
if (lines[line].flags & ML_EFFECT1) // Swinging
mroll = (mroll - mspokeangle) & FINEMASK;
else // Spinning
mphase = (mphase - mspokeangle) & FINEMASK;
while (emblem)
if (mnumnospokes && !(mnumspokes % mnumnospokes)) // Skipping a "missing" spoke
{
if ((emblem->type == ET_GLOBAL || emblem->type == ET_SKIN) && emblem->tag == mthing->angle)
break;
if (mobj->type != MT_CHAINMACEPOINT)
continue;
emblem = M_GetLevelEmblems(-1);
linktype = chainlink;
firsttype = ((mthing->options & MTF_AMBUSH) ? MT_BIGGRABCHAIN : MT_SMALLGRABCHAIN);
mmaxlength = 1 + (mlength - 1) * radiusfactor;
radiusfactor = widthfactor = 1;
}
if (!emblem)
else
{
CONS_Debug(DBG_GAMELOGIC, "No map emblem for map %d with tag %d found!\n", gamemap, mthing->angle);
break;
if (mobj->type == MT_CHAINMACEPOINT)
{
// Make the links the same type as the end - repeated above
if (lines[line].flags & ML_EFFECT2)
{
linktype = macetype;
radiusfactor = 2;
}
else
radiusfactor = (((linktype = chainlink) == MT_NULL) ? 2 : 1);
firsttype = macetype;
widthfactor = 2;
}
mmaxlength = mlength;
}
j = emblem - emblemlocations;
mwidthset = mwidth;
mlengthset = mminlength;
if (mdocenter) // Innermost link
makemace(linktype, 0, 0);
I_Assert(emblemlocations[j].sprite >= 'A' && emblemlocations[j].sprite <= 'Z');
P_SetMobjState(mobj, mobj->info->spawnstate + (emblemlocations[j].sprite - 'A'));
// Out from the center...
if (linktype)
{
while ((++mlengthset) < mmaxlength)
makemace(linktype, radiusfactor*mlengthset, 0);
}
else
mlengthset = mmaxlength;
mobj->health = j + 1;
emcolor = M_GetEmblemColor(&emblemlocations[j]); // workaround for compiler complaint about bad function casting
mobj->color = (UINT8)emcolor;
// Outermost mace/link
if (firsttype)
makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH);
if (emblemlocations[j].collected
|| (emblemlocations[j].type == ET_SKIN && emblemlocations[j].var != players[0].skin))
if (!mwidth)
{
P_UnsetThingPosition(mobj);
mobj->flags |= MF_NOCLIP;
mobj->flags &= ~MF_SPECIAL;
mobj->flags |= MF_NOBLOCKMAP;
mobj->frame |= (tr_trans50 << FF_TRANSSHIFT);
P_SetThingPosition(mobj);
if (mdosound && mnumspokes <= mmin) // Can it make a sound?
spawnee->flags2 |= MF2_BOSSNOTRAP;
}
else
{
mobj->frame &= ~FF_TRANSMASK;
if (emblemlocations[j].type == ET_GLOBAL)
// Across the bar!
if (!firsttype)
mwidthset = -mwidth;
else if (mwidth > 0)
{
mobj->reactiontime = emblemlocations[j].var;
if (emblemlocations[j].var & GE_NIGHTSITEM)
while ((mwidthset -= widthfactor) > -mwidth)
{
mobj->flags |= MF_NIGHTSITEM;
mobj->flags &= ~MF_SPECIAL;
mobj->flags2 |= MF2_DONTDRAW;
makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH);
if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound?
spawnee->flags2 |= MF2_BOSSNOTRAP;
}
}
else
{
while ((mwidthset += widthfactor) < -mwidth)
{
makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH);
if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound?
spawnee->flags2 |= MF2_BOSSNOTRAP;
}
}
mwidth = -mwidth;
// Outermost mace/link again!
if (firsttype)
makemace(firsttype, radiusfactor*(mlengthset--), MF2_AMBUSH);
// ...and then back into the center!
if (linktype)
while (mlengthset > mminlength)
makemace(linktype, radiusfactor*(mlengthset--), 0);
if (mdocenter) // Innermost link
makemace(linktype, 0, 0);
}
}
#undef makemace
return true;
}
static boolean P_SetupParticleGen(mapthing_t *mthing, mobj_t *mobj)
{
fixed_t radius, speed;
INT32 type, numdivisions, anglespeed, ticcount;
angle_t angledivision;
INT32 line;
const size_t mthingi = (size_t)(mthing - mapthings);
// Find the corresponding linedef special, using angle as tag
line = P_FindSpecialLineFromTag(15, mthing->angle, -1);
if (line == -1)
{
CONS_Debug(DBG_GAMELOGIC, "Particle generator (mapthing #%s) needs to be tagged to a #15 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle);
return false;
}
if (sides[lines[line].sidenum[0]].toptexture)
type = sides[lines[line].sidenum[0]].toptexture; // Set as object type in p_setup.c...
else
type = (INT32)MT_PARTICLE;
if (!lines[line].backsector
|| (ticcount = (sides[lines[line].sidenum[1]].textureoffset >> FRACBITS)) < 1)
ticcount = 3;
numdivisions = (mthing->options >> ZSHIFT);
if (numdivisions)
{
radius = R_PointToDist2(lines[line].v1->x, lines[line].v1->y, lines[line].v2->x, lines[line].v2->y);
anglespeed = (sides[lines[line].sidenum[0]].rowoffset >> FRACBITS) % 360;
angledivision = 360/numdivisions;
}
else
{
numdivisions = 1; // Simple trick to make A_ParticleSpawn simpler.
radius = 0;
anglespeed = 0;
angledivision = 0;
}
speed = abs(sides[lines[line].sidenum[0]].textureoffset);
if (mthing->options & MTF_OBJECTFLIP)
speed *= -1;
CONS_Debug(DBG_GAMELOGIC, "Particle Generator (mapthing #%s):\n"
"Radius is %d\n"
"Speed is %d\n"
"Anglespeed is %d\n"
"Numdivisions is %d\n"
"Angledivision is %d\n"
"Type is %d\n"
"Tic seperation is %d\n",
sizeu1(mthingi), radius, speed, anglespeed, numdivisions, angledivision, type, ticcount);
mobj->angle = 0;
mobj->movefactor = speed;
mobj->lastlook = numdivisions;
mobj->movedir = angledivision*ANG1;
mobj->movecount = anglespeed*ANG1;
mobj->friction = radius;
mobj->threshold = type;
mobj->reactiontime = ticcount;
mobj->cvmem = line;
mobj->watertop = mobj->waterbottom = 0;
return true;
}
static boolean P_SetupNiGHTSDrone(mapthing_t* mthing, mobj_t* mobj)
{
boolean flip = mthing->options & MTF_OBJECTFLIP;
boolean topaligned = (mthing->options & MTF_OBJECTSPECIAL) && !(mthing->options & MTF_EXTRA);
boolean middlealigned = (mthing->options & MTF_EXTRA) && !(mthing->options & MTF_OBJECTSPECIAL);
boolean bottomoffsetted = !(mthing->options & MTF_OBJECTSPECIAL) && !(mthing->options & MTF_EXTRA);
INT16 timelimit = mthing->angle & 0xFFF;
fixed_t hitboxradius = ((mthing->angle & 0xF000) >> 12)*32*FRACUNIT;
fixed_t hitboxheight = mthing->extrainfo*32*FRACUNIT;
fixed_t oldheight = mobj->height;
fixed_t dronemanoffset, goaloffset, sparkleoffset, droneboxmandiff, dronemangoaldiff;
if (timelimit > 0)
mobj->health = timelimit;
if (hitboxradius > 0)
mobj->radius = hitboxradius;
if (hitboxheight > 0)
mobj->height = hitboxheight;
else
mobj->height = mobjinfo[MT_NIGHTSDRONE].height;
droneboxmandiff = max(mobj->height - mobjinfo[MT_NIGHTSDRONE_MAN].height, 0);
dronemangoaldiff = max(mobjinfo[MT_NIGHTSDRONE_MAN].height - mobjinfo[MT_NIGHTSDRONE_GOAL].height, 0);
if (flip && mobj->height != oldheight)
P_TeleportMove(mobj, mobj->x, mobj->y, mobj->z - (mobj->height - oldheight));
if (!flip)
{
if (topaligned) // Align droneman to top of hitbox
{
dronemanoffset = droneboxmandiff;
goaloffset = dronemangoaldiff/2 + dronemanoffset;
}
else if (middlealigned) // Align droneman to center of hitbox
{
dronemanoffset = droneboxmandiff/2;
goaloffset = dronemangoaldiff/2 + dronemanoffset;
}
else if (bottomoffsetted)
{
dronemanoffset = 24*FRACUNIT;
goaloffset = dronemangoaldiff + dronemanoffset;
}
else
{
dronemanoffset = 0;
goaloffset = dronemangoaldiff/2 + dronemanoffset;
}
sparkleoffset = goaloffset - FixedMul(15*FRACUNIT, mobj->scale);
}
else
{
mobj->eflags |= MFE_VERTICALFLIP;
mobj->flags2 |= MF2_OBJECTFLIP;
if (topaligned) // Align droneman to top of hitbox
{
dronemanoffset = 0;
goaloffset = dronemangoaldiff/2 + dronemanoffset;
}
else if (middlealigned) // Align droneman to center of hitbox
{
dronemanoffset = droneboxmandiff/2;
goaloffset = dronemangoaldiff/2 + dronemanoffset;
}
else if (bottomoffsetted)
{
dronemanoffset = droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale);
goaloffset = dronemangoaldiff + dronemanoffset;
}
else
{
dronemanoffset = droneboxmandiff;
goaloffset = dronemangoaldiff/2 + dronemanoffset;
}
sparkleoffset = goaloffset + FixedMul(15*FRACUNIT, mobj->scale);
}
// spawn visual elements
{
mobj_t* goalpost = P_SpawnMobjFromMobj(mobj, 0, 0, goaloffset, MT_NIGHTSDRONE_GOAL);
mobj_t* sparkle = P_SpawnMobjFromMobj(mobj, 0, 0, sparkleoffset, MT_NIGHTSDRONE_SPARKLING);
mobj_t* droneman = P_SpawnMobjFromMobj(mobj, 0, 0, dronemanoffset, MT_NIGHTSDRONE_MAN);
P_SetTarget(&mobj->target, goalpost);
P_SetTarget(&goalpost->target, sparkle);
P_SetTarget(&goalpost->tracer, droneman);
// correct Z position
if (flip)
{
P_TeleportMove(goalpost, goalpost->x, goalpost->y, mobj->z + goaloffset);
P_TeleportMove(sparkle, sparkle->x, sparkle->y, mobj->z + sparkleoffset);
P_TeleportMove(droneman, droneman->x, droneman->y, mobj->z + dronemanoffset);
}
// Remember position preference for later
mobj->flags &= ~(MF_SLIDEME|MF_GRENADEBOUNCE);
if (topaligned)
mobj->flags |= MF_SLIDEME;
else if (middlealigned)
mobj->flags |= MF_GRENADEBOUNCE;
else if (!bottomoffsetted)
mobj->flags |= MF_SLIDEME|MF_GRENADEBOUNCE;
// Remember old Z position and flags for correction detection
goalpost->movefactor = mobj->z;
goalpost->friction = mobj->height;
goalpost->threshold = mobj->flags & (MF_SLIDEME|MF_GRENADEBOUNCE);
}
return true;
}
static boolean P_SetupBooster(mapthing_t* mthing, mobj_t* mobj, boolean strong)
{
angle_t angle = FixedAngle(mthing->angle << FRACBITS);
fixed_t x1 = FINECOSINE((angle >> ANGLETOFINESHIFT) & FINEMASK);
fixed_t y1 = FINESINE((angle >> ANGLETOFINESHIFT) & FINEMASK);
fixed_t x2 = FINECOSINE(((angle + ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK);
fixed_t y2 = FINESINE(((angle + ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK);
statenum_t facestate = strong ? S_REDBOOSTERSEG_FACE : S_YELLOWBOOSTERSEG_FACE;
statenum_t leftstate = strong ? S_REDBOOSTERSEG_LEFT : S_YELLOWBOOSTERSEG_LEFT;
statenum_t rightstate = strong ? S_REDBOOSTERSEG_RIGHT : S_YELLOWBOOSTERSEG_RIGHT;
statenum_t rollerstate = strong ? S_REDBOOSTERROLLER : S_YELLOWBOOSTERROLLER;
mobj_t *seg = P_SpawnMobjFromMobj(mobj, 26*x1, 26*y1, 0, MT_BOOSTERSEG);
seg->angle = angle - ANGLE_90;
P_SetMobjState(seg, facestate);
seg = P_SpawnMobjFromMobj(mobj, -26*x1, -26*y1, 0, MT_BOOSTERSEG);
seg->angle = angle + ANGLE_90;
P_SetMobjState(seg, facestate);
seg = P_SpawnMobjFromMobj(mobj, 21*x2, 21*y2, 0, MT_BOOSTERSEG);
seg->angle = angle;
P_SetMobjState(seg, leftstate);
seg = P_SpawnMobjFromMobj(mobj, -21*x2, -21*y2, 0, MT_BOOSTERSEG);
seg->angle = angle;
P_SetMobjState(seg, rightstate);
seg = P_SpawnMobjFromMobj(mobj, 13*(x1 + x2), 13*(y1 + y2), 0, MT_BOOSTERROLLER);
seg->angle = angle;
P_SetMobjState(seg, rollerstate);
seg = P_SpawnMobjFromMobj(mobj, 13*(x1 - x2), 13*(y1 - y2), 0, MT_BOOSTERROLLER);
seg->angle = angle;
P_SetMobjState(seg, rollerstate);
seg = P_SpawnMobjFromMobj(mobj, -13*(x1 + x2), -13*(y1 + y2), 0, MT_BOOSTERROLLER);
seg->angle = angle;
P_SetMobjState(seg, rollerstate);
seg = P_SpawnMobjFromMobj(mobj, -13*(x1 - x2), -13*(y1 - y2), 0, MT_BOOSTERROLLER);
seg->angle = angle;
P_SetMobjState(seg, rollerstate);
return true;
}
static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean *doangle)
{
#ifdef HAVE_BLUA
boolean override = LUAh_MapThingSpawn(mobj, mthing);
if (P_MobjWasRemoved(mobj))
return false;
if (override)
return true;
#endif
switch (mobj->type)
{
case MT_EMBLEM:
{
if (!P_SetupEmblem(mthing, mobj))
return false;
break;
}
case MT_SKYBOX:
......@@ -12019,7 +12549,7 @@ You should think about modifying the deathmatch starts to take full advantage of
if (mthing->angle)
mobj->health = mthing->angle;
else
mobj->health = FixedMul(ss->sector->ceilingheight-ss->sector->floorheight, 3*(FRACUNIT/4))>>FRACBITS;
mobj->health = FixedMul(mobj->subsector->sector->ceilingheight - mobj->subsector->sector->floorheight, 3*(FRACUNIT/4)) >> FRACBITS;
break;
case MT_METALSONIC_RACE:
case MT_METALSONIC_BATTLE:
......@@ -12034,7 +12564,7 @@ You should think about modifying the deathmatch starts to take full advantage of
break;
case MT_BALLOON:
if (mthing->angle > 0)
mobj->color = ((mthing->angle-1) % (MAXSKINCOLORS-1))+1;
mobj->color = ((mthing->angle - 1) % (MAXSKINCOLORS - 1)) + 1;
break;
#define makesoftwarecorona(mo, h) \
corona = P_SpawnMobjFromMobj(mo, 0, 0, h<<FRACBITS, MT_PARTICLE);\
......@@ -12085,10 +12615,7 @@ You should think about modifying the deathmatch starts to take full advantage of
}
break;
case MT_WATERDRIP:
if (mthing->angle)
mobj->tics = 3*TICRATE + mthing->angle;
else
mobj->tics = 3*TICRATE;
mobj->tics = 3*TICRATE + mthing->angle;
break;
case MT_FLAMEJET:
case MT_VERTICALFLAMEJET:
......@@ -12106,410 +12633,32 @@ You should think about modifying the deathmatch starts to take full advantage of
case MT_CHAINPOINT:
case MT_FIREBARPOINT:
case MT_CUSTOMMACEPOINT:
{
fixed_t mlength, mmaxlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor, widthfactor;
angle_t mspokeangle;
mobjtype_t chainlink, macetype, firsttype, linktype;
boolean mdosound, mdocenter, mchainlike = false;
mobj_t *spawnee = NULL, *hprev = mobj;
mobjflag_t mflagsapply;
mobjflag2_t mflags2apply;
mobjeflag_t meflagsapply;
INT32 line;
const size_t mthingi = (size_t)(mthing - mapthings);
// Find the corresponding linedef special, using angle as tag
// P_FindSpecialLineFromTag works here now =D
line = P_FindSpecialLineFromTag(9, mthing->angle, -1);
if (line == -1)
{
CONS_Debug(DBG_GAMELOGIC, "Mace chain (mapthing #%s) needs to be tagged to a #9 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle);
return;
}
/*
mapthing -
MTF_AMBUSH :
MT_SPRINGBALLPOINT - upgrade from yellow to red spring
anything else - bigger mace/chain theory
MTF_OBJECTSPECIAL - force silent
MTF_GRAVFLIP - flips objects, doesn't affect chain arrangements
Parameter value : number of "spokes"
linedef -
ML_NOCLIMB :
MT_CHAINPOINT/MT_CHAINMACEPOINT with ML_EFFECT1 applied - Direction not controllable
anything else - no functionality
ML_EFFECT1 : Swings instead of spins
ML_EFFECT2 : Linktype is replaced with macetype for all spokes not ending in chains (inverted for MT_FIREBARPOINT)
ML_EFFECT3 : Spawn a bonus linktype at the hinge point
ML_EFFECT4 : Don't clip inside the ground
ML_EFFECT5 : Don't stop thinking when too far away
*/
mlength = abs(lines[line].dx >> FRACBITS);
mspeed = abs(lines[line].dy >> (FRACBITS - 4));
mphase = (sides[lines[line].sidenum[0]].textureoffset >> FRACBITS) % 360;
if ((mminlength = -sides[lines[line].sidenum[0]].rowoffset>>FRACBITS) < 0)
mminlength = 0;
else if (mminlength > mlength-1)
mminlength = mlength-1;
mpitch = (lines[line].frontsector->floorheight >> FRACBITS) % 360;
myaw = (lines[line].frontsector->ceilingheight >> FRACBITS) % 360;
mnumspokes = mthing->extrainfo + 1;
mspokeangle = FixedAngle((360*FRACUNIT)/mnumspokes)>>ANGLETOFINESHIFT;
if (lines[line].backsector)
{
mpinch = (lines[line].backsector->floorheight >> FRACBITS) % 360;
mroll = (lines[line].backsector->ceilingheight >> FRACBITS) % 360;
mnumnospokes = (sides[lines[line].sidenum[1]].textureoffset >> FRACBITS);
if ((mwidth = sides[lines[line].sidenum[1]].rowoffset >> FRACBITS) < 0)
mwidth = 0;
}
else
mpinch = mroll = mnumnospokes = mwidth = 0;
CONS_Debug(DBG_GAMELOGIC, "Mace/Chain (mapthing #%s):\n"
"Length is %d (minus %d)\n"
"Speed is %d\n"
"Phase is %d\n"
"Yaw is %d\n"
"Pitch is %d\n"
"No. of spokes is %d (%d antispokes)\n"
"Pinch is %d\n"
"Roll is %d\n"
"Width is %d\n",
sizeu1(mthingi), mlength, mminlength, mspeed, mphase, myaw, mpitch, mnumspokes, mnumnospokes, mpinch, mroll, mwidth);
if (mnumnospokes > 0 && (mnumnospokes < mnumspokes))
mnumnospokes = mnumspokes/mnumnospokes;
if (!P_SetupMace(mthing, mobj, doangle))
return false;
break;
case MT_PARTICLEGEN:
if (!P_SetupParticleGen(mthing, mobj))
return false;
break;
case MT_ROCKSPAWNER:
mobj->threshold = mthing->angle;
mobj->movecount = mthing->extrainfo;
break;
case MT_POPUPTURRET:
if (mthing->angle)
mobj->threshold = mthing->angle;
else
mnumnospokes = ((mobj->type == MT_CHAINMACEPOINT) ? (mnumspokes) : 0);
mobj->lastlook = mspeed;
mobj->movecount = mobj->lastlook;
mobj->angle = FixedAngle(myaw*FRACUNIT);
doangle = false;
mobj->threshold = (FixedAngle(mpitch*FRACUNIT)>>ANGLETOFINESHIFT);
mobj->movefactor = mpinch;
mobj->movedir = 0;
// Mobjtype selection
switch(mobj->type)
{
case MT_SPRINGBALLPOINT:
macetype = ((mthing->options & MTF_AMBUSH)
? MT_REDSPRINGBALL
: MT_YELLOWSPRINGBALL);
chainlink = MT_SMALLMACECHAIN;
break;
case MT_FIREBARPOINT:
macetype = ((mthing->options & MTF_AMBUSH)
? MT_BIGFIREBAR
: MT_SMALLFIREBAR);
chainlink = MT_NULL;
break;
case MT_CUSTOMMACEPOINT:
macetype = (mobjtype_t)sides[lines[line].sidenum[0]].toptexture;
if (lines[line].backsector)
chainlink = (mobjtype_t)sides[lines[line].sidenum[1]].toptexture;
else
chainlink = MT_NULL;
break;
case MT_CHAINPOINT:
if (mthing->options & MTF_AMBUSH)
{
macetype = MT_BIGGRABCHAIN;
chainlink = MT_BIGMACECHAIN;
}
else
{
macetype = MT_SMALLGRABCHAIN;
chainlink = MT_SMALLMACECHAIN;
}
mchainlike = true;
break;
default:
if (mthing->options & MTF_AMBUSH)
{
macetype = MT_BIGMACE;
chainlink = MT_BIGMACECHAIN;
}
else
{
macetype = MT_SMALLMACE;
chainlink = MT_SMALLMACECHAIN;
}
break;
}
if (!macetype && !chainlink)
break;
if (mobj->type == MT_CHAINPOINT)
{
if (!mlength)
break;
}
else
mlength++;
firsttype = macetype;
// Adjustable direction
if (lines[line].flags & ML_NOCLIMB)
mobj->flags |= MF_SLIDEME;
// Swinging
if (lines[line].flags & ML_EFFECT1)
{
mobj->flags2 |= MF2_STRONGBOX;
mmin = ((mnumnospokes > 1) ? 1 : 0);
}
else
mmin = mnumspokes;
// If over distance away, don't move UNLESS this flag is applied
if (lines[line].flags & ML_EFFECT5)
mobj->flags2 |= MF2_BOSSNOTRAP;
// Make the links the same type as the end - repeated below
if ((mobj->type != MT_CHAINPOINT) && (((lines[line].flags & ML_EFFECT2) == ML_EFFECT2) != (mobj->type == MT_FIREBARPOINT))) // exclusive or
{
linktype = macetype;
radiusfactor = 2; // Double the radius.
}
else
radiusfactor = (((linktype = chainlink) == MT_NULL) ? 2 : 1);
if (!mchainlike)
mchainlike = (firsttype == chainlink);
widthfactor = (mchainlike ? 1 : 2);
mflagsapply = ((lines[line].flags & ML_EFFECT4) ? 0 : (MF_NOCLIP|MF_NOCLIPHEIGHT));
mflags2apply = ((mthing->options & MTF_OBJECTFLIP) ? MF2_OBJECTFLIP : 0);
meflagsapply = ((mthing->options & MTF_OBJECTFLIP) ? MFE_VERTICALFLIP : 0);
msound = (mchainlike ? 0 : (mwidth & 1));
// Quick and easy preparatory variable setting
mphase = (FixedAngle(mphase*FRACUNIT)>>ANGLETOFINESHIFT);
mroll = (FixedAngle(mroll*FRACUNIT)>>ANGLETOFINESHIFT);
#define makemace(mobjtype, dist, moreflags2) {\
spawnee = P_SpawnMobj(mobj->x, mobj->y, mobj->z, mobjtype);\
P_SetTarget(&spawnee->tracer, mobj);\
spawnee->threshold = mphase;\
spawnee->friction = mroll;\
spawnee->movefactor = mwidthset;\
spawnee->movecount = dist;\
spawnee->angle = myaw;\
spawnee->flags |= (MF_NOGRAVITY|mflagsapply);\
spawnee->flags2 |= (mflags2apply|moreflags2);\
spawnee->eflags |= meflagsapply;\
P_SetTarget(&hprev->hnext, spawnee);\
P_SetTarget(&spawnee->hprev, hprev);\
hprev = spawnee;\
}
mdosound = (mspeed && !(mthing->options & MTF_OBJECTSPECIAL));
mdocenter = (macetype && (lines[line].flags & ML_EFFECT3));
// The actual spawning of spokes
while (mnumspokes-- > 0)
{
// Offsets
if (lines[line].flags & ML_EFFECT1) // Swinging
mroll = (mroll - mspokeangle) & FINEMASK;
else // Spinning
mphase = (mphase - mspokeangle) & FINEMASK;
if (mnumnospokes && !(mnumspokes % mnumnospokes)) // Skipping a "missing" spoke
{
if (mobj->type != MT_CHAINMACEPOINT)
continue;
linktype = chainlink;
firsttype = ((mthing->options & MTF_AMBUSH) ? MT_BIGGRABCHAIN : MT_SMALLGRABCHAIN);
mmaxlength = 1 + (mlength - 1)*radiusfactor;
radiusfactor = widthfactor = 1;
}
else
{
if (mobj->type == MT_CHAINMACEPOINT)
{
// Make the links the same type as the end - repeated above
if (lines[line].flags & ML_EFFECT2)
{
linktype = macetype;
radiusfactor = 2;
}
else
radiusfactor = (((linktype = chainlink) == MT_NULL) ? 2 : 1);
firsttype = macetype;
widthfactor = 2;
}
mmaxlength = mlength;
}
mwidthset = mwidth;
mlengthset = mminlength;
if (mdocenter) // Innermost link
makemace(linktype, 0, 0);
// Out from the center...
if (linktype)
{
while ((++mlengthset) < mmaxlength)
makemace(linktype, radiusfactor*mlengthset, 0);
}
else
mlengthset = mmaxlength;
// Outermost mace/link
if (firsttype)
makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH);
if (!mwidth)
{
if (mdosound && mnumspokes <= mmin) // Can it make a sound?
spawnee->flags2 |= MF2_BOSSNOTRAP;
}
else
{
// Across the bar!
if (!firsttype)
mwidthset = -mwidth;
else if (mwidth > 0)
{
while ((mwidthset -= widthfactor) > -mwidth)
{
makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH);
if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound?
spawnee->flags2 |= MF2_BOSSNOTRAP;
}
}
else
{
while ((mwidthset += widthfactor) < -mwidth)
{
makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH);
if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound?
spawnee->flags2 |= MF2_BOSSNOTRAP;
}
}
mwidth = -mwidth;
// Outermost mace/link again!
if (firsttype)
makemace(firsttype, radiusfactor*(mlengthset--), MF2_AMBUSH);
// ...and then back into the center!
if (linktype)
while (mlengthset > mminlength)
makemace(linktype, radiusfactor*(mlengthset--), 0);
if (mdocenter) // Innermost link
makemace(linktype, 0, 0);
}
}
#undef makemace
break;
}
case MT_PARTICLEGEN:
{
fixed_t radius, speed;
INT32 type, numdivisions, anglespeed, ticcount;
angle_t angledivision;
INT32 line;
const size_t mthingi = (size_t)(mthing - mapthings);
// Find the corresponding linedef special, using angle as tag
line = P_FindSpecialLineFromTag(15, mthing->angle, -1);
if (line == -1)
{
CONS_Debug(DBG_GAMELOGIC, "Particle generator (mapthing #%s) needs to be tagged to a #15 parameter line (trying to find tag %d).\n", sizeu1(mthingi), mthing->angle);
return;
}
if (sides[lines[line].sidenum[0]].toptexture)
type = sides[lines[line].sidenum[0]].toptexture; // Set as object type in p_setup.c...
else
type = (INT32)MT_PARTICLE;
if (!lines[line].backsector
|| (ticcount = (sides[lines[line].sidenum[1]].textureoffset >> FRACBITS)) < 1)
ticcount = 3;
numdivisions = (mthing->options >> ZSHIFT);
if (numdivisions)
{
radius = R_PointToDist2(lines[line].v1->x, lines[line].v1->y, lines[line].v2->x, lines[line].v2->y);
anglespeed = (sides[lines[line].sidenum[0]].rowoffset >> FRACBITS) % 360;
angledivision = 360/numdivisions;
}
else
{
numdivisions = 1; // Simple trick to make A_ParticleSpawn simpler.
radius = 0;
anglespeed = 0;
angledivision = 0;
}
speed = abs(sides[lines[line].sidenum[0]].textureoffset);
if (mthing->options & MTF_OBJECTFLIP)
speed *= -1;
CONS_Debug(DBG_GAMELOGIC, "Particle Generator (mapthing #%s):\n"
"Radius is %d\n"
"Speed is %d\n"
"Anglespeed is %d\n"
"Numdivisions is %d\n"
"Angledivision is %d\n"
"Type is %d\n"
"Tic seperation is %d\n",
sizeu1(mthingi), radius, speed, anglespeed, numdivisions, angledivision, type, ticcount);
mobj->angle = 0;
mobj->movefactor = speed;
mobj->lastlook = numdivisions;
mobj->movedir = angledivision*ANG1;
mobj->movecount = anglespeed*ANG1;
mobj->friction = radius;
mobj->threshold = type;
mobj->reactiontime = ticcount;
mobj->cvmem = line;
mobj->watertop = mobj->waterbottom = 0;
break;
}
case MT_ROCKSPAWNER:
mobj->threshold = mthing->angle;
mobj->movecount = mthing->extrainfo;
break;
case MT_POPUPTURRET:
if (mthing->angle)
mobj->threshold = mthing->angle;
else
mobj->threshold = (TICRATE*2)-1;
break;
case MT_NIGHTSBUMPER:
// Lower 4 bits specify the angle of
// the bumper in 30 degree increments.
mobj->threshold = (mthing->options & 15) % 12; // It loops over, etc
P_SetMobjState(mobj, mobj->info->spawnstate+mobj->threshold);
break;
case MT_EGGCAPSULE:
if (mthing->angle <= 0)
mthing->angle = 20; // prevent 0 health
mobj->threshold = (TICRATE*2)-1;
break;
case MT_NIGHTSBUMPER:
// Lower 4 bits specify the angle of
// the bumper in 30 degree increments.
mobj->threshold = (mthing->options & 15) % 12; // It loops over, etc
P_SetMobjState(mobj, mobj->info->spawnstate + mobj->threshold);
break;
case MT_EGGCAPSULE:
if (mthing->angle <= 0)
mthing->angle = 20; // prevent 0 health
mobj->health = mthing->angle;
mobj->threshold = min(mthing->extrainfo, 7);
......@@ -12522,122 +12671,8 @@ ML_EFFECT5 : Don't stop thinking when too far away
mobj->health = mthing->extrainfo;
break;
case MT_NIGHTSDRONE:
{
boolean flip = mthing->options & MTF_OBJECTFLIP;
boolean topaligned = (mthing->options & MTF_OBJECTSPECIAL) && !(mthing->options & MTF_EXTRA);
boolean middlealigned = (mthing->options & MTF_EXTRA) && !(mthing->options & MTF_OBJECTSPECIAL);
boolean bottomoffsetted = !(mthing->options & MTF_OBJECTSPECIAL) && !(mthing->options & MTF_EXTRA);
INT16 timelimit = mthing->angle & 0xFFF;
fixed_t hitboxradius = ((mthing->angle & 0xF000) >> 12) * 32 * FRACUNIT;
fixed_t hitboxheight = mthing->extrainfo * 32 * FRACUNIT;
fixed_t oldheight = mobj->height;
fixed_t dronemanoffset, goaloffset, sparkleoffset, droneboxmandiff, dronemangoaldiff;
if (timelimit > 0)
mobj->health = timelimit;
if (hitboxradius > 0)
mobj->radius = hitboxradius;
if (hitboxheight > 0)
mobj->height = hitboxheight;
else
mobj->height = mobjinfo[MT_NIGHTSDRONE].height;
droneboxmandiff = max(mobj->height - mobjinfo[MT_NIGHTSDRONE_MAN].height, 0);
dronemangoaldiff = max(mobjinfo[MT_NIGHTSDRONE_MAN].height - mobjinfo[MT_NIGHTSDRONE_GOAL].height, 0);
if (flip && mobj->height != oldheight)
P_TeleportMove(mobj, mobj->x, mobj->y, mobj->z - (mobj->height - oldheight));
if (!flip)
{
if (topaligned) // Align droneman to top of hitbox
{
dronemanoffset = droneboxmandiff;
goaloffset = dronemangoaldiff / 2 + dronemanoffset;
}
else if (middlealigned) // Align droneman to center of hitbox
{
dronemanoffset = droneboxmandiff / 2;
goaloffset = dronemangoaldiff / 2 + dronemanoffset;
}
else if (bottomoffsetted)
{
dronemanoffset = 24*FRACUNIT;
goaloffset = dronemangoaldiff + dronemanoffset;
}
else
{
dronemanoffset = 0;
goaloffset = dronemangoaldiff / 2 + dronemanoffset;
}
sparkleoffset = goaloffset - FixedMul(15*FRACUNIT, mobj->scale);
}
else
{
mobj->eflags |= MFE_VERTICALFLIP;
mobj->flags2 |= MF2_OBJECTFLIP;
if (topaligned) // Align droneman to top of hitbox
{
dronemanoffset = 0;
goaloffset = dronemangoaldiff / 2 + dronemanoffset;
}
else if (middlealigned) // Align droneman to center of hitbox
{
dronemanoffset = droneboxmandiff / 2;
goaloffset = dronemangoaldiff / 2 + dronemanoffset;
}
else if (bottomoffsetted)
{
dronemanoffset = droneboxmandiff - FixedMul(24*FRACUNIT, mobj->scale);
goaloffset = dronemangoaldiff + dronemanoffset;
}
else
{
dronemanoffset = droneboxmandiff;
goaloffset = dronemangoaldiff / 2 + dronemanoffset;
}
sparkleoffset = goaloffset + FixedMul(15*FRACUNIT, mobj->scale);
}
// spawn visual elements
{
mobj_t *goalpost = P_SpawnMobjFromMobj(mobj, 0, 0, goaloffset, MT_NIGHTSDRONE_GOAL);
mobj_t *sparkle = P_SpawnMobjFromMobj(mobj, 0, 0, sparkleoffset, MT_NIGHTSDRONE_SPARKLING);
mobj_t *droneman = P_SpawnMobjFromMobj(mobj, 0, 0, dronemanoffset, MT_NIGHTSDRONE_MAN);
P_SetTarget(&mobj->target, goalpost);
P_SetTarget(&goalpost->target, sparkle);
P_SetTarget(&goalpost->tracer, droneman);
// correct Z position
if (flip)
{
P_TeleportMove(goalpost, goalpost->x, goalpost->y, mobj->z + goaloffset);
P_TeleportMove(sparkle, sparkle->x, sparkle->y, mobj->z + sparkleoffset);
P_TeleportMove(droneman, droneman->x, droneman->y, mobj->z + dronemanoffset);
}
// Remember position preference for later
mobj->flags &= ~(MF_SLIDEME | MF_GRENADEBOUNCE);
if (topaligned)
mobj->flags |= MF_SLIDEME;
else if (middlealigned)
mobj->flags |= MF_GRENADEBOUNCE;
else if (!bottomoffsetted)
mobj->flags |= MF_SLIDEME | MF_GRENADEBOUNCE;
// Remember old Z position and flags for correction detection
goalpost->movefactor = mobj->z;
goalpost->friction = mobj->height;
goalpost->threshold = mobj->flags & (MF_SLIDEME | MF_GRENADEBOUNCE);
}
}
if (!P_SetupNiGHTSDrone(mthing, mobj))
return false;
break;
case MT_HIVEELEMENTAL:
if (mthing->extrainfo)
......@@ -12648,7 +12683,7 @@ ML_EFFECT5 : Don't stop thinking when too far away
case MT_GLAREGOYLEDOWN:
case MT_GLAREGOYLELONG:
if (mthing->angle >= 360)
mobj->tics += 7*(mthing->angle / 360) + 1; // starting delay
mobj->tics += 7*(mthing->angle/360) + 1; // starting delay
break;
case MT_DSZSTALAGMITE:
case MT_DSZ2STALAGMITE:
......@@ -12659,39 +12694,39 @@ ML_EFFECT5 : Don't stop thinking when too far away
}
break;
case MT_THZTREE:
{ // Spawn the branches
angle_t mobjangle = FixedAngle((mthing->angle % 113)<<FRACBITS);
P_SpawnMobjFromMobj(mobj, 1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_22h;
P_SpawnMobjFromMobj(mobj, 0, 1*FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_157h;
P_SpawnMobjFromMobj(mobj, -1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270;
}
break;
{ // Spawn the branches
angle_t mobjangle = FixedAngle((mthing->angle % 113) << FRACBITS);
P_SpawnMobjFromMobj(mobj, FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_22h;
P_SpawnMobjFromMobj(mobj, 0, FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_157h;
P_SpawnMobjFromMobj(mobj, -FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270;
}
break;
case MT_CEZPOLE1:
case MT_CEZPOLE2:
{ // Spawn the banner
angle_t mobjangle = FixedAngle(mthing->angle<<FRACBITS);
P_SpawnMobjFromMobj(mobj,
P_ReturnThrustX(mobj, mobjangle, 4<<FRACBITS),
P_ReturnThrustY(mobj, mobjangle, 4<<FRACBITS),
0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2))->angle = mobjangle + ANGLE_90;
}
break;
{ // Spawn the banner
angle_t mobjangle = FixedAngle(mthing->angle << FRACBITS);
P_SpawnMobjFromMobj(mobj,
P_ReturnThrustX(mobj, mobjangle, 4 << FRACBITS),
P_ReturnThrustY(mobj, mobjangle, 4 << FRACBITS),
0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2))->angle = mobjangle + ANGLE_90;
}
break;
case MT_HHZTREE_TOP:
{ // Spawn the branches
angle_t mobjangle = FixedAngle(mthing->angle<<FRACBITS) & (ANGLE_90-1);
mobj_t *leaf;
{ // Spawn the branches
angle_t mobjangle = FixedAngle(mthing->angle << FRACBITS) & (ANGLE_90 - 1);
mobj_t* leaf;
#define doleaf(x, y) \
leaf = P_SpawnMobjFromMobj(mobj, x, y, 0, MT_HHZTREE_PART);\
leaf->angle = mobjangle;\
P_SetMobjState(leaf, leaf->info->seestate);\
mobjangle += ANGLE_90
doleaf(1*FRACUNIT, 0);
doleaf(0, 1*FRACUNIT);
doleaf(-1*FRACUNIT, 0);
doleaf(0, -1*FRACUNIT);
doleaf(FRACUNIT, 0);
doleaf(0, FRACUNIT);
doleaf(-FRACUNIT, 0);
doleaf(0, -FRACUNIT);
#undef doleaf
}
break;
}
break;
case MT_SMASHINGSPIKEBALL:
if (mthing->angle > 0)
mobj->tics += mthing->angle;
......@@ -12722,94 +12757,27 @@ ML_EFFECT5 : Don't stop thinking when too far away
angle_t fa = (angle >> ANGLETOFINESHIFT) & FINEMASK;
fixed_t xoffs = FINECOSINE(fa);
fixed_t yoffs = FINESINE(fa);
mobj_t *leaf = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, 0, MT_BIGFERNLEAF);
mobj_t* leaf = P_SpawnMobjFromMobj(mobj, xoffs, yoffs, 0, MT_BIGFERNLEAF);
leaf->angle = angle;
angle += ANGLE_45;
}
break;
}
case MT_REDBOOSTER:
{
angle_t angle = FixedAngle(mthing->angle << FRACBITS);
fixed_t x1 = FINECOSINE((angle >> ANGLETOFINESHIFT) & FINEMASK);
fixed_t y1 = FINESINE((angle >> ANGLETOFINESHIFT) & FINEMASK);
fixed_t x2 = FINECOSINE(((angle+ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK);
fixed_t y2 = FINESINE(((angle+ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK);
mobj_t *seg = P_SpawnMobjFromMobj(mobj, 26*x1, 26*y1, 0, MT_BOOSTERSEG);
seg->angle = angle-ANGLE_90;
P_SetMobjState(seg, S_REDBOOSTERSEG_FACE);
seg = P_SpawnMobjFromMobj(mobj, -26*x1, -26*y1, 0, MT_BOOSTERSEG);
seg->angle = angle+ANGLE_90;
P_SetMobjState(seg, S_REDBOOSTERSEG_FACE);
seg = P_SpawnMobjFromMobj(mobj, 21*x2, 21*y2, 0, MT_BOOSTERSEG);
seg->angle = angle;
P_SetMobjState(seg, S_REDBOOSTERSEG_LEFT);
seg = P_SpawnMobjFromMobj(mobj, -21*x2, -21*y2, 0, MT_BOOSTERSEG);
seg->angle = angle;
P_SetMobjState(seg, S_REDBOOSTERSEG_RIGHT);
seg = P_SpawnMobjFromMobj(mobj, 13*(x1+x2), 13*(y1+y2), 0, MT_BOOSTERROLLER);
seg->angle = angle;
P_SetMobjState(seg, S_REDBOOSTERROLLER);
seg = P_SpawnMobjFromMobj(mobj, 13*(x1-x2), 13*(y1-y2), 0, MT_BOOSTERROLLER);
seg->angle = angle;
P_SetMobjState(seg, S_REDBOOSTERROLLER);
seg = P_SpawnMobjFromMobj(mobj, -13*(x1+x2), -13*(y1+y2), 0, MT_BOOSTERROLLER);
seg->angle = angle;
P_SetMobjState(seg, S_REDBOOSTERROLLER);
seg = P_SpawnMobjFromMobj(mobj, -13*(x1-x2), -13*(y1-y2), 0, MT_BOOSTERROLLER);
seg->angle = angle;
P_SetMobjState(seg, S_REDBOOSTERROLLER);
break;
}
case MT_YELLOWBOOSTER:
{
angle_t angle = FixedAngle(mthing->angle << FRACBITS);
fixed_t x1 = FINECOSINE((angle >> ANGLETOFINESHIFT) & FINEMASK);
fixed_t y1 = FINESINE((angle >> ANGLETOFINESHIFT) & FINEMASK);
fixed_t x2 = FINECOSINE(((angle+ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK);
fixed_t y2 = FINESINE(((angle+ANGLE_90) >> ANGLETOFINESHIFT) & FINEMASK);
mobj_t *seg = P_SpawnMobjFromMobj(mobj, 26*x1, 26*y1, 0, MT_BOOSTERSEG);
seg->angle = angle-ANGLE_90;
P_SetMobjState(seg, S_YELLOWBOOSTERSEG_FACE);
seg = P_SpawnMobjFromMobj(mobj, -26*x1, -26*y1, 0, MT_BOOSTERSEG);
seg->angle = angle+ANGLE_90;
P_SetMobjState(seg, S_YELLOWBOOSTERSEG_FACE);
seg = P_SpawnMobjFromMobj(mobj, 21*x2, 21*y2, 0, MT_BOOSTERSEG);
seg->angle = angle;
P_SetMobjState(seg, S_YELLOWBOOSTERSEG_LEFT);
seg = P_SpawnMobjFromMobj(mobj, -21*x2, -21*y2, 0, MT_BOOSTERSEG);
seg->angle = angle;
P_SetMobjState(seg, S_YELLOWBOOSTERSEG_RIGHT);
seg = P_SpawnMobjFromMobj(mobj, 13*(x1+x2), 13*(y1+y2), 0, MT_BOOSTERROLLER);
seg->angle = angle;
P_SetMobjState(seg, S_YELLOWBOOSTERROLLER);
seg = P_SpawnMobjFromMobj(mobj, 13*(x1-x2), 13*(y1-y2), 0, MT_BOOSTERROLLER);
seg->angle = angle;
P_SetMobjState(seg, S_YELLOWBOOSTERROLLER);
seg = P_SpawnMobjFromMobj(mobj, -13*(x1+x2), -13*(y1+y2), 0, MT_BOOSTERROLLER);
seg->angle = angle;
P_SetMobjState(seg, S_YELLOWBOOSTERROLLER);
seg = P_SpawnMobjFromMobj(mobj, -13*(x1-x2), -13*(y1-y2), 0, MT_BOOSTERROLLER);
seg->angle = angle;
P_SetMobjState(seg, S_YELLOWBOOSTERROLLER);
break;
}
default:
if (!P_SetupBooster(mthing, mobj, mobj->type == MT_REDBOOSTER))
return false;
break;
}
if (mobj->flags & MF_BOSS)
{
if (mthing->options & MTF_OBJECTSPECIAL) // No egg trap for this boss
mobj->flags2 |= MF2_BOSSNOTRAP;
}
case MT_AXIS:
// Inverted if uppermost bit is set
if (mthing->angle & 16384)
mobj->flags2 |= MF2_AMBUSH;
if (i == MT_AXIS || i == MT_AXISTRANSFER || i == MT_AXISTRANSFERLINE) // Axis Points
{
if (mthing->angle > 0)
mobj->radius = (mthing->angle & 16383) << FRACBITS;
// FALLTHRU
case MT_AXISTRANSFER:
case MT_AXISTRANSFERLINE:
// Mare it belongs to
mobj->threshold = min(mthing->extrainfo, 7);
......@@ -12817,38 +12785,29 @@ ML_EFFECT5 : Don't stop thinking when too far away
mobj->health = mthing->options;
mobj->flags2 |= MF2_AXIS;
if (i == MT_AXIS)
{
// Inverted if uppermost bit is set
if (mthing->angle & 16384)
mobj->flags2 |= MF2_AMBUSH;
if (mthing->angle > 0)
mobj->radius = (mthing->angle & 16383)*FRACUNIT;
}
}
else if (i == MT_TOKEN)
{
break;
case MT_TOKEN:
// We advanced tokenbits earlier due to the return check.
// Subtract 1 here for the correct value.
mobj->health = 1 << (tokenbits - 1);
}
else if (i == MT_CYBRAKDEMON && mthing->options & MTF_AMBUSH)
{
mobj_t *elecmobj;
elecmobj = P_SpawnMobj(x, y, z, MT_CYBRAKDEMON_ELECTRIC_BARRIER);
P_SetTarget(&elecmobj->target, mobj);
elecmobj->angle = FixedAngle(mthing->angle<<FRACBITS);;
elecmobj->destscale = mobj->scale*2;
P_SetScale(elecmobj, elecmobj->destscale);
}
else if (i == MT_STARPOST)
break;
case MT_CYBRAKDEMON:
if (mthing->options & MTF_AMBUSH)
{
mobj_t* elecmobj;
elecmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_CYBRAKDEMON_ELECTRIC_BARRIER);
P_SetTarget(&elecmobj->target, mobj);
elecmobj->angle = FixedAngle(mthing->angle << FRACBITS);
elecmobj->destscale = mobj->scale*2;
P_SetScale(elecmobj, elecmobj->destscale);
}
break;
case MT_STARPOST:
{
thinker_t *th;
mobj_t *mo2;
thinker_t* th;
mobj_t* mo2;
boolean foundanother = false;
mobj->health = (mthing->angle / 360) + 1;
mobj->health = (mthing->angle/360) + 1;
// See if other starposts exist in this level that have the same value.
for (th = thlist[THINK_MOBJ].next; th != &thlist[THINK_MOBJ]; th = th->next)
......@@ -12856,7 +12815,7 @@ ML_EFFECT5 : Don't stop thinking when too far away
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue;
mo2 = (mobj_t *)th;
mo2 = (mobj_t*)th;
if (mo2 == mobj)
continue;
......@@ -12870,14 +12829,14 @@ ML_EFFECT5 : Don't stop thinking when too far away
if (!foundanother)
numstarposts++;
break;
}
else if (i == MT_SPIKE)
{
case MT_SPIKE:
// Pop up spikes!
if (mthing->options & MTF_OBJECTSPECIAL)
{
mobj->flags &= ~MF_SCENERY;
mobj->fuse = (16 - mthing->extrainfo) * (mthing->angle + mobj->info->speed) / 16;
mobj->fuse = (16 - mthing->extrainfo)*(mthing->angle + mobj->info->speed)/16;
if (mthing->options & MTF_EXTRA)
P_SetMobjState(mobj, mobj->info->meleestate);
}
......@@ -12889,14 +12848,13 @@ ML_EFFECT5 : Don't stop thinking when too far away
mobj->flags |= MF_SOLID;
P_SetThingPosition(mobj);
}
}
else if (i == MT_WALLSPIKE)
{
break;
case MT_WALLSPIKE:
// Pop up spikes!
if (mthing->options & MTF_OBJECTSPECIAL)
{
mobj->flags &= ~MF_SCENERY;
mobj->fuse = (16 - mthing->extrainfo) * ((mthing->angle/360) + mobj->info->speed) / 16;
mobj->fuse = (16 - mthing->extrainfo)*((mthing->angle/360) + mobj->info->speed)/16;
if (mthing->options & MTF_EXTRA)
P_SetMobjState(mobj, mobj->info->meleestate);
}
......@@ -12904,64 +12862,51 @@ ML_EFFECT5 : Don't stop thinking when too far away
if (!(mthing->options & MTF_AMBUSH) && !metalrecording)
{
P_UnsetThingPosition(mobj);
mobj->flags &= ~(MF_NOBLOCKMAP|MF_NOCLIPHEIGHT);
mobj->flags &= ~(MF_NOBLOCKMAP | MF_NOCLIPHEIGHT);
mobj->flags |= MF_SOLID;
P_SetThingPosition(mobj);
}
// spawn base
{
const angle_t mobjangle = FixedAngle(mthing->angle<<FRACBITS); // the mobj's own angle hasn't been set quite yet so...
const angle_t mobjangle = FixedAngle(mthing->angle << FRACBITS); // the mobj's own angle hasn't been set quite yet so...
const fixed_t baseradius = mobj->radius - mobj->scale;
mobj_t *base = P_SpawnMobj(
mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius),
mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius),
mobj->z, MT_WALLSPIKEBASE);
mobj_t* base = P_SpawnMobj(
mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius),
mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius),
mobj->z, MT_WALLSPIKEBASE);
base->angle = mobjangle + ANGLE_90;
base->destscale = mobj->destscale;
P_SetScale(base, mobj->scale);
P_SetTarget(&base->target, mobj);
P_SetTarget(&mobj->tracer, base);
}
}
//count 10 ring boxes into the number of rings equation too.
if (i == MT_RING_BOX && nummaprings >= 0)
nummaprings += 10;
if (i == MT_BIGTUMBLEWEED || i == MT_LITTLETUMBLEWEED)
{
break;
case MT_RING_BOX:
//count 10 ring boxes into the number of rings equation too.
if (nummaprings >= 0)
nummaprings += 10;
break;
case MT_BIGTUMBLEWEED:
case MT_LITTLETUMBLEWEED:
if (mthing->options & MTF_AMBUSH)
{
mobj->momz += FixedMul(16*FRACUNIT, mobj->scale);
if (P_RandomChance(FRACUNIT/2))
mobj->momx += FixedMul(16*FRACUNIT, mobj->scale);
else
mobj->momx -= FixedMul(16*FRACUNIT, mobj->scale);
if (P_RandomChance(FRACUNIT/2))
mobj->momy += FixedMul(16*FRACUNIT, mobj->scale);
else
mobj->momy -= FixedMul(16*FRACUNIT,mobj->scale);
fixed_t offset = FixedMul(16*FRACUNIT, mobj->scale);
mobj->momx += P_RandomChance(FRACUNIT/2) ? offset : -offset;
mobj->momy += P_RandomChance(FRACUNIT/2) ? offset : -offset;
mobj->momz += offset;
}
}
// CTF flag pointers
if (i == MT_REDFLAG)
{
break;
case MT_REDFLAG:
redflag = mobj;
rflagpoint = mobj->spawnpoint;
}
if (i == MT_BLUEFLAG)
{
break;
case MT_BLUEFLAG:
blueflag = mobj;
bflagpoint = mobj->spawnpoint;
}
// special push/pull stuff
if (i == MT_PUSH || i == MT_PULL)
{
break;
case MT_PUSH:
case MT_PULL:
mobj->health = 0; // Default behaviour: pushing uses XY, fading uses XYZ
if (mthing->options & MTF_AMBUSH)
......@@ -12970,23 +12915,129 @@ ML_EFFECT5 : Don't stop thinking when too far away
mobj->health |= 2; // If object special is set, fade using XY
if (G_IsSpecialStage(gamemap))
{
if (i == MT_PUSH)
P_SetMobjState(mobj, S_GRAVWELLGREEN);
if (i == MT_PULL)
P_SetMobjState(mobj, S_GRAVWELLRED);
}
P_SetMobjState(mobj, (mobj->type == MT_PUSH) ? S_GRAVWELLGREEN : S_GRAVWELLRED);
break;
default:
break;
}
if (mobj->flags & MF_BOSS)
{
if (mthing->options & MTF_OBJECTSPECIAL) // No egg trap for this boss
mobj->flags2 |= MF2_BOSSNOTRAP;
}
return true;
}
static void P_SetAmbush(mobj_t *mobj)
{
if (mobj->type == MT_YELLOWDIAG || mobj->type == MT_REDDIAG || mobj->type == MT_BLUEDIAG)
mobj->angle += ANGLE_22h;
if (mobj->flags & MF_NIGHTSITEM)
{
// Spawn already displayed
mobj->flags |= MF_SPECIAL;
mobj->flags &= ~MF_NIGHTSITEM;
}
if (mobj->flags & MF_PUSHABLE)
mobj->flags &= ~MF_PUSHABLE;
if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0)
{
// flag for strong/weak random boxes
// any monitor with nonzero speed is allowed to respawn like this
mobj->flags2 |= MF2_AMBUSH;
}
else if (mobj->type != MT_AXIS &&
mobj->type != MT_AXISTRANSFER &&
mobj->type != MT_AXISTRANSFERLINE &&
mobj->type != MT_NIGHTSBUMPER &&
mobj->type != MT_STARPOST)
mobj->flags2 |= MF2_AMBUSH;
}
static void P_SetObjectSpecial(mobj_t *mobj)
{
if (mobj->type == MT_YELLOWDIAG || mobj->type == MT_REDDIAG || mobj->type == MT_BLUEDIAG)
mobj->flags |= MF_NOGRAVITY;
if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0)
{
// flag for strong/weak random boxes
// any monitor with nonzero speed is allowed to respawn like this
mobj->flags2 |= MF2_STRONGBOX;
}
// Requires you to be in bonus time to activate
if (mobj->flags & MF_NIGHTSITEM)
mobj->flags2 |= MF2_STRONGBOX;
// Pushables bounce and slide coolly with object special flag set
if (mobj->flags & MF_PUSHABLE)
{
mobj->flags2 |= MF2_SLIDEPUSH;
mobj->flags |= MF_BOUNCE;
}
}
//
// P_SpawnMapThing
// The fields of the mapthing should
// already be in host byte order.
//
void P_SpawnMapThing(mapthing_t *mthing)
{
mobjtype_t i;
mobj_t *mobj;
fixed_t x, y, z;
boolean doangle = true;
if (!mthing->type)
return; // Ignore type-0 things as NOPs
if (mthing->type == 3328) // 3D Mode start Thing
return;
if (!objectplacing && P_SpawnNonMobjMapThing(mthing))
return;
i = P_GetMobjtype(mthing->type);
if (i == MT_UNKNOWN)
CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y);
// Skip all returning/substitution code in objectplace.
if (!objectplacing)
{
if (!P_AllowMobjSpawn(mthing, i))
return;
i = P_GetMobjtypeSubstitute(mthing, i);
if (i == MT_NULL) // Don't spawn mobj
return;
}
// spawn it
x = mthing->x << FRACBITS;
y = mthing->y << FRACBITS;
z = P_GetMobjSpawnHeight(i, mthing, x, y);
mobj = P_SpawnMobj(x, y, z, i);
mobj->spawnpoint = mthing;
if (!P_SetupSpawnedMapThing(mthing, mobj, &doangle))
return;
if (doangle)
mobj->angle = FixedAngle(mthing->angle<<FRACBITS);
mthing->mobj = mobj;
// ignore MTF_ flags and return early
if (i == MT_NIGHTSBUMPER)
{
mthing->mobj = mobj;
return;
}
if ((mthing->options & MTF_AMBUSH)
&& (mthing->options & MTF_OBJECTSPECIAL)
......@@ -12995,67 +13046,10 @@ ML_EFFECT5 : Don't stop thinking when too far away
else
{
if (mthing->options & MTF_AMBUSH)
{
if (i == MT_YELLOWDIAG || i == MT_REDDIAG || i == MT_BLUEDIAG)
mobj->angle += ANGLE_22h;
if (i == MT_YELLOWHORIZ || i == MT_REDHORIZ || i == MT_BLUEHORIZ)
{
if (mthing->options & MTF_OBJECTFLIP)
mobj->z -= 16*FRACUNIT;
else
mobj->z += 16*FRACUNIT;
}
if (mobj->flags & MF_NIGHTSITEM)
{
// Spawn already displayed
mobj->flags |= MF_SPECIAL;
mobj->flags &= ~MF_NIGHTSITEM;
}
if (mobj->flags & MF_PUSHABLE)
mobj->flags &= ~MF_PUSHABLE;
if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0)
{
// flag for strong/weak random boxes
// any monitor with nonzero speed is allowed to respawn like this
mobj->flags2 |= MF2_AMBUSH;
}
else if (mthing->type != mobjinfo[MT_AXIS].doomednum &&
mthing->type != mobjinfo[MT_AXISTRANSFER].doomednum &&
mthing->type != mobjinfo[MT_AXISTRANSFERLINE].doomednum &&
mthing->type != mobjinfo[MT_NIGHTSBUMPER].doomednum &&
mthing->type != mobjinfo[MT_STARPOST].doomednum)
mobj->flags2 |= MF2_AMBUSH;
}
P_SetAmbush(mobj);
if (mthing->options & MTF_OBJECTSPECIAL)
{
if (i == MT_YELLOWDIAG || i == MT_REDDIAG || i == MT_BLUEDIAG)
mobj->flags |= MF_NOGRAVITY;
if ((mobj->flags & MF_MONITOR) && mobj->info->speed != 0)
{
// flag for strong/weak random boxes
// any monitor with nonzero speed is allowed to respawn like this
mobj->flags2 |= MF2_STRONGBOX;
}
// Requires you to be in bonus time to activate
if (mobj->flags & MF_NIGHTSITEM)
mobj->flags2 |= MF2_STRONGBOX;
// Pushables bounce and slide coolly with object special flag set
if (mobj->flags & MF_PUSHABLE)
{
mobj->flags2 |= MF2_SLIDEPUSH;
mobj->flags |= MF_BOUNCE;
}
}
P_SetObjectSpecial(mobj);
}
// Generic reverse gravity for individual objects flag.
......@@ -13078,564 +13072,373 @@ ML_EFFECT5 : Don't stop thinking when too far away
// Final set of not being able to draw nightsitems.
if (mobj->flags & MF_NIGHTSITEM)
mobj->flags2 |= MF2_DONTDRAW;
mthing->mobj = mobj;
}
void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
static void P_SpawnHoop(mapthing_t* mthing, fixed_t x, fixed_t y, fixed_t z, sector_t* sec, INT32 hoopsize, fixed_t sizefactor)
{
mobjtype_t ringthing = MT_RING;
mobj_t *mobj = NULL;
INT32 r, i;
fixed_t x, y, z, finalx, finaly, finalz;
sector_t *sec;
mobj_t *nextmobj = NULL;
mobj_t *hoopcenter;
TMatrix *pitchmatrix, *yawmatrix;
fixed_t radius = hoopsize*sizefactor;
INT32 i;
angle_t fa;
TVector v, *res;
angle_t closestangle, fa;
boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap));
x = mthing->x << FRACBITS;
y = mthing->y << FRACBITS;
sec = R_PointInSubsector(x, y)->sector;
// NiGHTS hoop!
if (mthing->type == 1705)
{
mobj_t *nextmobj = NULL;
mobj_t *hoopcenter;
INT16 spewangle;
z = mthing->options << FRACBITS;
hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER);
hoopcenter->spawnpoint = mthing;
// Screw these damn hoops, I need this thinker.
//hoopcenter->flags |= MF_NOTHINK;
z +=
z +=
#ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif
sec->floorheight;
sec->floorheight;
hoopcenter->z = z - hoopcenter->height/2;
hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER);
hoopcenter->spawnpoint = mthing;
hoopcenter->z -= hoopcenter->height/2;
P_UnsetThingPosition(hoopcenter);
hoopcenter->x = x;
hoopcenter->y = y;
P_SetThingPosition(hoopcenter);
P_UnsetThingPosition(hoopcenter);
hoopcenter->x = x;
hoopcenter->y = y;
P_SetThingPosition(hoopcenter);
// Scale 0-255 to 0-359 =(
closestangle = FixedAngle(FixedMul((mthing->angle>>8)*FRACUNIT,
360*(FRACUNIT/256)));
// Scale 0-255 to 0-359 =(
hoopcenter->movedir = ((mthing->angle & 255)*360)/256; // Pitch
pitchmatrix = RotateXMatrix(FixedAngle(hoopcenter->movedir << FRACBITS));
hoopcenter->movecount = (((UINT16)mthing->angle >> 8)*360)/256; // Yaw
yawmatrix = RotateZMatrix(FixedAngle(hoopcenter->movecount << FRACBITS));
hoopcenter->movedir = FixedInt(FixedMul((mthing->angle&255)*FRACUNIT,
360*(FRACUNIT/256)));
hoopcenter->movecount = FixedInt(AngleFixed(closestangle));
// For the hoop when it flies away
hoopcenter->extravalue1 = hoopsize;
hoopcenter->extravalue2 = radius/12;
// For the hoop when it flies away
hoopcenter->extravalue1 = 32;
hoopcenter->extravalue2 = 8 * FRACUNIT;
spewangle = (INT16)hoopcenter->movedir;
// Create the hoop!
for (i = 0; i < 32; i++)
{
fa = i*(FINEANGLES/32);
v[0] = FixedMul(FINECOSINE(fa),96*FRACUNIT);
v[1] = 0;
v[2] = FixedMul(FINESINE(fa),96*FRACUNIT);
v[3] = FRACUNIT;
res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT)));
M_Memcpy(&v, res, sizeof (v));
res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
M_Memcpy(&v, res, sizeof (v));
finalx = x + v[0];
finaly = y + v[1];
finalz = z + v[2];
mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOP);
// Create the hoop!
for (i = 0; i < hoopsize; i++)
{
fa = i*(FINEANGLES/hoopsize);
v[0] = FixedMul(FINECOSINE(fa), radius);
v[1] = 0;
v[2] = FixedMul(FINESINE(fa), radius);
v[3] = FRACUNIT;
if (maptol & TOL_XMAS)
P_SetMobjState(mobj, mobj->info->seestate + (i & 1));
res = VectorMatrixMultiply(v, *pitchmatrix);
M_Memcpy(&v, res, sizeof(v));
res = VectorMatrixMultiply(v, *yawmatrix);
M_Memcpy(&v, res, sizeof(v));
mobj->z -= mobj->height/2;
P_SetTarget(&mobj->target, hoopcenter); // Link the sprite to the center.
mobj->fuse = 0;
mobj = P_SpawnMobj(x + v[0], y + v[1], z + v[2], MT_HOOP);
mobj->z -= mobj->height/2;
// Link all the sprites in the hoop together
if (nextmobj)
{
P_SetTarget(&mobj->hprev, nextmobj);
P_SetTarget(&mobj->hprev->hnext, mobj);
}
else
P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL));
if (maptol & TOL_XMAS)
P_SetMobjState(mobj, mobj->info->seestate + (i & 1));
nextmobj = mobj;
}
P_SetTarget(&mobj->target, hoopcenter); // Link the sprite to the center.
mobj->fuse = 0;
// Create the collision detectors!
for (i = 0; i < 16; i++)
// Link all the sprites in the hoop together
if (nextmobj)
{
fa = i*FINEANGLES/16;
v[0] = FixedMul(FINECOSINE(fa),32*FRACUNIT);
v[1] = 0;
v[2] = FixedMul(FINESINE(fa),32*FRACUNIT);
v[3] = FRACUNIT;
res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT)));
M_Memcpy(&v, res, sizeof (v));
res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
M_Memcpy(&v, res, sizeof (v));
finalx = x + v[0];
finaly = y + v[1];
finalz = z + v[2];
mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOPCOLLIDE);
mobj->z -= mobj->height/2;
// Link all the collision sprites together.
P_SetTarget(&mobj->hnext, NULL);
P_SetTarget(&mobj->hprev, nextmobj);
P_SetTarget(&mobj->hprev->hnext, mobj);
nextmobj = mobj;
}
// Create the collision detectors!
for (i = 0; i < 16; i++)
{
fa = i*FINEANGLES/16;
v[0] = FixedMul(FINECOSINE(fa),64*FRACUNIT);
v[1] = 0;
v[2] = FixedMul(FINESINE(fa),64*FRACUNIT);
v[3] = FRACUNIT;
res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT)));
M_Memcpy(&v, res, sizeof (v));
res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
M_Memcpy(&v, res, sizeof (v));
finalx = x + v[0];
finaly = y + v[1];
finalz = z + v[2];
mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOPCOLLIDE);
mobj->z -= mobj->height/2;
// Link all the collision sprites together.
P_SetTarget(&mobj->hnext, NULL);
P_SetTarget(&mobj->hprev, nextmobj);
P_SetTarget(&mobj->hprev->hnext, mobj);
else
P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL));
nextmobj = mobj;
}
return;
nextmobj = mobj;
}
// CUSTOMIZABLE NiGHTS hoop!
else if (mthing->type == 1713)
{
mobj_t *nextmobj = NULL;
mobj_t *hoopcenter;
INT16 spewangle;
INT32 hoopsize;
INT32 hoopplacement;
// Save our flags!
z = (mthing->options>>ZSHIFT) << FRACBITS;
hoopcenter = P_SpawnMobj(x, y, z, MT_HOOPCENTER);
hoopcenter->spawnpoint = mthing;
z +=
#ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif
sec->floorheight;
hoopcenter->z = z - hoopcenter->height/2;
P_UnsetThingPosition(hoopcenter);
hoopcenter->x = x;
hoopcenter->y = y;
P_SetThingPosition(hoopcenter);
// Scale 0-255 to 0-359 =(
closestangle = FixedAngle(FixedMul((mthing->angle>>8)*FRACUNIT,
360*(FRACUNIT/256)));
hoopcenter->movedir = FixedInt(FixedMul((mthing->angle&255)*FRACUNIT,
360*(FRACUNIT/256)));
hoopcenter->movecount = FixedInt(AngleFixed(closestangle));
spewangle = (INT16)hoopcenter->movedir;
// Super happy fun time
// For each flag add 4 fracunits to the size
// Default (0 flags) is 8 fracunits
hoopsize = 8 + (4 * (mthing->options & 0xF));
hoopplacement = hoopsize * (4*FRACUNIT);
// Create the collision detectors!
// Create them until the size is less than 8
// But always create at least ONE set of collision detectors
do
{
if (hoopsize >= 32)
hoopsize -= 16;
else
hoopsize /= 2;
// For the hoop when it flies away
hoopcenter->extravalue1 = hoopsize;
hoopcenter->extravalue2 = FixedDiv(hoopplacement, 12*FRACUNIT);
radius = hoopsize*sizefactor;
// Create the hoop!
for (i = 0; i < hoopsize; i++)
{
fa = i*(FINEANGLES/hoopsize);
v[0] = FixedMul(FINECOSINE(fa), hoopplacement);
v[0] = FixedMul(FINECOSINE(fa), radius);
v[1] = 0;
v[2] = FixedMul(FINESINE(fa), hoopplacement);
v[2] = FixedMul(FINESINE(fa), radius);
v[3] = FRACUNIT;
res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT)));
M_Memcpy(&v, res, sizeof (v));
res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
M_Memcpy(&v, res, sizeof (v));
finalx = x + v[0];
finaly = y + v[1];
finalz = z + v[2];
mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOP);
if (maptol & TOL_XMAS)
P_SetMobjState(mobj, mobj->info->seestate + (i & 1));
res = VectorMatrixMultiply(v, *pitchmatrix);
M_Memcpy(&v, res, sizeof(v));
res = VectorMatrixMultiply(v, *yawmatrix);
M_Memcpy(&v, res, sizeof(v));
mobj = P_SpawnMobj(x + v[0], y + v[1], z + v[2], MT_HOOPCOLLIDE);
mobj->z -= mobj->height/2;
P_SetTarget(&mobj->target, hoopcenter); // Link the sprite to the center.
mobj->fuse = 0;
// Link all the sprites in the hoop together
if (nextmobj)
{
P_SetTarget(&mobj->hprev, nextmobj);
P_SetTarget(&mobj->hprev->hnext, mobj);
}
else
P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL));
// Link all the collision sprites together.
P_SetTarget(&mobj->hnext, NULL);
P_SetTarget(&mobj->hprev, nextmobj);
P_SetTarget(&mobj->hprev->hnext, mobj);
nextmobj = mobj;
}
} while (hoopsize >= 8);
}
// Create the collision detectors!
// Create them until the size is less than 8
// But always create at least ONE set of collision detectors
do
{
if (hoopsize >= 32)
hoopsize -= 16;
else
hoopsize /= 2;
hoopplacement = hoopsize * (4*FRACUNIT);
for (i = 0; i < hoopsize; i++)
{
fa = i*FINEANGLES/hoopsize;
v[0] = FixedMul(FINECOSINE(fa), hoopplacement);
v[1] = 0;
v[2] = FixedMul(FINESINE(fa), hoopplacement);
v[3] = FRACUNIT;
res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT)));
M_Memcpy(&v, res, sizeof (v));
res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
M_Memcpy(&v, res, sizeof (v));
finalx = x + v[0];
finaly = y + v[1];
finalz = z + v[2];
mobj = P_SpawnMobj(finalx, finaly, finalz, MT_HOOPCOLLIDE);
mobj->z -= mobj->height/2;
// Link all the collision sprites together.
P_SetTarget(&mobj->hnext, NULL);
P_SetTarget(&mobj->hprev, nextmobj);
P_SetTarget(&mobj->hprev->hnext, mobj);
nextmobj = mobj;
}
} while (hoopsize >= 8);
return;
}
// ***
// Special placement patterns
// ***
static void P_SpawnRingItem(mapthing_t *mthing, fixed_t x, fixed_t y, boolean bonustime, boolean nightsreplace)
{
mobjtype_t ringthing = MT_RING;
mobj_t *mobj = NULL;
fixed_t z;
// Vertical Rings - Stack of 5 (handles both red and yellow)
else if (mthing->type == 600 || mthing->type == 601)
// Which ringthing to use
if (mthing->type == mobjinfo[MT_BLUESPHERE].doomednum)
ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE;
else if (mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum)
ringthing = MT_BOMBSPHERE;
else
{
INT32 dist = 64*FRACUNIT;
if (mthing->type == 601)
dist = 128*FRACUNIT;
if (ultimatemode)
return; // No rings in Ultimate!
if (nightsreplace)
ringthing = MT_NIGHTSSTAR;
else if (mthing->type == mobjinfo[MT_COIN].doomednum)
ringthing = MT_COIN;
else if (mthing->type == mobjinfo[MT_REDTEAMRING].doomednum) // No team rings in non-CTF
ringthing = (gametype == GT_CTF) ? MT_REDTEAMRING : MT_RING;
else if (mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum) // Ditto
ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING;
}
if (mthing->options & MTF_OBJECTFLIP)
{
z = (
#ifdef ESLOPE
sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
#endif
sec->ceilingheight) - mobjinfo[ringthing].height;
if (mthing->options >> ZSHIFT)
z -= ((mthing->options >> ZSHIFT) << FRACBITS);
}
else
{
z = (
#ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif
sec->floorheight);
if (mthing->options >> ZSHIFT)
z += ((mthing->options >> ZSHIFT) << FRACBITS);
}
for (r = 1; r <= 5; r++)
{
if (mthing->options & MTF_OBJECTFLIP)
z -= dist;
else
z += dist;
z = P_GetMobjSpawnHeight(ringthing, mthing, x, y);
mobj = P_SpawnMobj(x, y, z, ringthing);
mobj->spawnpoint = mthing;
mobj = P_SpawnMobj(x, y, z, ringthing);
if (mthing->options & MTF_OBJECTFLIP)
{
mobj->eflags |= MFE_VERTICALFLIP;
mobj->flags2 |= MF2_OBJECTFLIP;
}
if (mthing->options & MTF_OBJECTFLIP)
{
mobj->eflags |= MFE_VERTICALFLIP;
mobj->flags2 |= MF2_OBJECTFLIP;
}
mobj->angle = FixedAngle(mthing->angle << FRACBITS);
mthing->mobj = mobj;
if (mthing->options & MTF_AMBUSH)
mobj->flags2 |= MF2_AMBUSH;
mobj->angle = FixedAngle(mthing->angle*FRACUNIT);
if (mthing->options & MTF_AMBUSH)
mobj->flags2 |= MF2_AMBUSH;
if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP))
P_SetMobjState(mobj, mobj->info->raisestate);
else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
P_SetMobjState(mobj, mobj->info->seestate);
}
if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
P_SetMobjState(mobj, mobj->info->seestate);
}
}
// Diagonal rings (handles both types)
else if (mthing->type == 602 || mthing->type == 603) // Diagonal rings (5)
{
INT32 iterations = 5;
if (mthing->type == 603)
iterations = 10;
static void P_SpawnVerticalSpringRings(mapthing_t *mthing, fixed_t x, fixed_t y, sector_t* sec, boolean nightsreplace)
{
mobjtype_t ringthing = MT_RING;
mobj_t* mobj = NULL;
fixed_t z;
INT32 r;
if (ultimatemode)
return; // No rings in Ultimate!
INT32 dist = 64*FRACUNIT;
if (mthing->type == 601)
dist = 128*FRACUNIT;
if (nightsreplace)
ringthing = MT_NIGHTSSTAR;
if (ultimatemode)
return; // No rings in Ultimate!
closestangle = FixedAngle(mthing->angle*FRACUNIT);
fa = (closestangle >> ANGLETOFINESHIFT);
if (nightsreplace)
ringthing = MT_NIGHTSSTAR;
if (mthing->options & MTF_OBJECTFLIP)
{
z = (
#ifdef ESLOPE
sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
#endif
sec->ceilingheight) - mobjinfo[ringthing].height;
if (mthing->options >> ZSHIFT)
z -= ((mthing->options >> ZSHIFT) << FRACBITS);
}
else
{
z = (
if (mthing->options & MTF_OBJECTFLIP)
{
z = (
#ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
#endif
sec->floorheight);
if (mthing->options >> ZSHIFT)
z += ((mthing->options >> ZSHIFT) << FRACBITS);
}
for (r = 1; r <= iterations; r++)
{
x += FixedMul(64*FRACUNIT, FINECOSINE(fa));
y += FixedMul(64*FRACUNIT, FINESINE(fa));
if (mthing->options & MTF_OBJECTFLIP)
z -= 64*FRACUNIT;
else
z += 64*FRACUNIT;
mobj = P_SpawnMobj(x, y, z, ringthing);
if (mthing->options & MTF_OBJECTFLIP)
{
mobj->eflags |= MFE_VERTICALFLIP;
mobj->flags2 |= MF2_OBJECTFLIP;
}
mobj->angle = closestangle;
if (mthing->options & MTF_AMBUSH)
mobj->flags2 |= MF2_AMBUSH;
if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
P_SetMobjState(mobj, mobj->info->seestate);
}
sec->ceilingheight) - mobjinfo[ringthing].height;
if (mthing->z)
z -= (mthing->z << FRACBITS);
}
// Rings of items (all six of them)
else if (mthing->type >= 604 && mthing->type <= 609)
else
{
INT32 numitems = 8;
INT32 size = 96*FRACUNIT;
if (mthing->type & 1)
{
numitems = 16;
size = 192*FRACUNIT;
}
z =
z = (
#ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif
sec->floorheight;
if (mthing->options >> ZSHIFT)
z += ((mthing->options >> ZSHIFT) << FRACBITS);
sec->floorheight);
if (mthing->z)
z += (mthing->z << FRACBITS);
}
for (r = 1; r <= 5; r++)
{
if (mthing->options & MTF_OBJECTFLIP)
z -= dist;
else
z += dist;
closestangle = FixedAngle(mthing->angle*FRACUNIT);
mobj = P_SpawnMobj(x, y, z, ringthing);
switch (mthing->type)
if (mthing->options & MTF_OBJECTFLIP)
{
case 604:
case 605:
if (ultimatemode)
return; // No rings in Ultimate!
if (nightsreplace)
ringthing = MT_NIGHTSSTAR;
break;
case 608:
case 609:
/*ringthing = (i & 1) ? MT_RING : MT_BLUESPHERE; -- i == 0 is bluesphere
break;*/
case 606:
case 607:
ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE;
break;
default:
break;
mobj->eflags |= MFE_VERTICALFLIP;
mobj->flags2 |= MF2_OBJECTFLIP;
}
// Create the hoop!
for (i = 0; i < numitems; i++)
{
if (mthing->type == 608 || mthing->type == 609)
{
if (i & 1)
{
if (ultimatemode)
continue; // No rings in Ultimate!
ringthing = (nightsreplace) ? MT_NIGHTSSTAR : MT_RING;
}
else
ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE;
}
mobj->angle = FixedAngle(mthing->angle << FRACBITS);
if (mthing->options & MTF_AMBUSH)
mobj->flags2 |= MF2_AMBUSH;
fa = i*FINEANGLES/numitems;
v[0] = FixedMul(FINECOSINE(fa),size);
v[1] = 0;
v[2] = FixedMul(FINESINE(fa),size);
v[3] = FRACUNIT;
if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
P_SetMobjState(mobj, mobj->info->seestate);
}
}
res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
M_Memcpy(&v, res, sizeof (v));
static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, sector_t* sec, boolean nightsreplace)
{
mobjtype_t ringthing = MT_RING;
mobj_t *mobj = NULL;
fixed_t z;
INT32 r;
angle_t closestangle, fa;
finalx = x + v[0];
finaly = y + v[1];
finalz = z + v[2];
INT32 iterations = 5;
if (mthing->type == 603)
iterations = 10;
mobj = P_SpawnMobj(finalx, finaly, finalz, ringthing);
mobj->z -= mobj->height/2;
if (ultimatemode)
return; // No rings in Ultimate!
if (mthing->options & MTF_OBJECTFLIP)
{
mobj->eflags |= MFE_VERTICALFLIP;
mobj->flags2 |= MF2_OBJECTFLIP;
}
if (nightsreplace)
ringthing = MT_NIGHTSSTAR;
mobj->angle = closestangle;
if (mthing->options & MTF_AMBUSH)
mobj->flags2 |= MF2_AMBUSH;
closestangle = FixedAngle(mthing->angle << FRACBITS);
fa = (closestangle >> ANGLETOFINESHIFT);
if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP))
P_SetMobjState(mobj, mobj->info->raisestate);
else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
P_SetMobjState(mobj, mobj->info->seestate);
}
if (mthing->options & MTF_OBJECTFLIP)
{
z = (
#ifdef ESLOPE
sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
#endif
sec->ceilingheight) - mobjinfo[ringthing].height;
if (mthing->z)
z -= (mthing->z << FRACBITS);
}
// All manners of rings and coins
else
{
z = (
#ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif
sec->floorheight);
if (mthing->z)
z += (mthing->z << FRACBITS);
}
// Which ringthing to use
if (mthing->type == mobjinfo[MT_BLUESPHERE].doomednum)
ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE;
else if (mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum)
ringthing = MT_BOMBSPHERE;
for (r = 1; r <= iterations; r++)
{
x += FixedMul(64*FRACUNIT, FINECOSINE(fa));
y += FixedMul(64*FRACUNIT, FINESINE(fa));
if (mthing->options & MTF_OBJECTFLIP)
z -= 64*FRACUNIT;
else
{
if (ultimatemode)
return; // No rings in Ultimate!
z += 64*FRACUNIT;
if (nightsreplace)
ringthing = MT_NIGHTSSTAR;
else if (mthing->type == mobjinfo[MT_COIN].doomednum)
ringthing = MT_COIN;
else if (mthing->type == mobjinfo[MT_REDTEAMRING].doomednum) // No team rings in non-CTF
ringthing = (gametype == GT_CTF) ? MT_REDTEAMRING : MT_RING;
else if (mthing->type == mobjinfo[MT_BLUETEAMRING].doomednum) // Ditto
ringthing = (gametype == GT_CTF) ? MT_BLUETEAMRING : MT_RING;
}
mobj = P_SpawnMobj(x, y, z, ringthing);
// Set proper height
if (mthing->options & MTF_OBJECTFLIP)
{
z = (
#ifdef ESLOPE
sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
#endif
sec->ceilingheight) - mobjinfo[ringthing].height;
if (mthing->options >> ZSHIFT)
z -= ((mthing->options >> ZSHIFT) << FRACBITS);
mobj->eflags |= MFE_VERTICALFLIP;
mobj->flags2 |= MF2_OBJECTFLIP;
}
else
{
z =
mobj->angle = closestangle;
if (mthing->options & MTF_AMBUSH)
mobj->flags2 |= MF2_AMBUSH;
if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
P_SetMobjState(mobj, mobj->info->seestate);
}
}
static void P_SpawnItemCircle(mapthing_t* mthing, fixed_t x, fixed_t y, sector_t* sec, boolean bonustime, boolean nightsreplace)
{
mobjtype_t ringthing = MT_RING;
mobj_t *mobj = NULL;
fixed_t z, finalx, finaly, finalz;
angle_t closestangle, fa;
INT32 i;
TVector v, *res;
INT32 numitems = 8;
INT32 size = 96*FRACUNIT;
if (mthing->type & 1)
{
numitems = 16;
size = 192*FRACUNIT;
}
z =
#ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif
sec->floorheight;
if (mthing->options >> ZSHIFT)
z += ((mthing->options >> ZSHIFT) << FRACBITS);
}
sec->floorheight;
if (mthing->z)
z += (mthing->z << FRACBITS);
closestangle = FixedAngle(mthing->angle << FRACBITS);
switch (mthing->type)
{
case 604:
case 605:
if (ultimatemode)
return; // No rings in Ultimate!
if (nightsreplace)
ringthing = MT_NIGHTSSTAR;
break;
case 608:
case 609:
/*ringthing = (i & 1) ? MT_RING : MT_BLUESPHERE; -- i == 0 is bluesphere
break;*/
case 606:
case 607:
ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE;
break;
default:
break;
}
if (mthing->options & MTF_AMBUSH) // Special flag for rings
// Create the hoop!
for (i = 0; i < numitems; i++)
{
if (mthing->type == 608 || mthing->type == 609)
{
if (mthing->options & MTF_OBJECTFLIP)
z -= 24*FRACUNIT;
if (i & 1)
{
if (ultimatemode)
continue; // No rings in Ultimate!
ringthing = (nightsreplace) ? MT_NIGHTSSTAR : MT_RING;
}
else
z += 24*FRACUNIT;
ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE;
}
mthing->z = (INT16)(z>>FRACBITS);
fa = i * FINEANGLES/numitems;
v[0] = FixedMul(FINECOSINE(fa), size);
v[1] = 0;
v[2] = FixedMul(FINESINE(fa), size);
v[3] = FRACUNIT;
mobj = P_SpawnMobj(x, y, z, ringthing);
mobj->spawnpoint = mthing;
res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
M_Memcpy(&v, res, sizeof(v));
finalx = x + v[0];
finaly = y + v[1];
finalz = z + v[2];
mobj = P_SpawnMobj(finalx, finaly, finalz, ringthing);
mobj->z -= mobj->height/2;
if (mthing->options & MTF_OBJECTFLIP)
{
......@@ -13643,8 +13446,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
mobj->flags2 |= MF2_OBJECTFLIP;
}
mobj->angle = FixedAngle(mthing->angle*FRACUNIT);
mthing->mobj = mobj;
mobj->angle = closestangle;
if (mthing->options & MTF_AMBUSH)
mobj->flags2 |= MF2_AMBUSH;
......@@ -13655,6 +13457,47 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
}
}
void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
{
fixed_t x = mthing->x << FRACBITS;
fixed_t y = mthing->y << FRACBITS;
fixed_t z = mthing->z << FRACBITS;
sector_t *sec = R_PointInSubsector(x, y)->sector;
boolean nightsreplace = ((maptol & TOL_NIGHTS) && !G_IsSpecialStage(gamemap));
switch (mthing->type)
{
// Special placement patterns
case 600: // 5 vertical rings (yellow spring)
case 601: // 5 vertical rings (red spring)
P_SpawnVerticalSpringRings(mthing, x, y, sec, nightsreplace);
return;
case 602: // 5 diagonal rings (yellow spring)
case 603: // 10 diagonal rings (red spring)
P_SpawnDiagonalSpringRings(mthing, x, y, sec, nightsreplace);
return;
case 604: // Circle of rings (8 items)
case 605: // Circle of rings (16 bits)
case 606: // Circle of blue spheres (8 items)
case 607: // Circle of blue spheres (16 items)
case 608: // Circle of rings and blue spheres (8 items)
case 609: // Circle of rings and blue spheres (16 items)
P_SpawnItemCircle(mthing, x, y, sec, bonustime, nightsreplace);
return;
// Hoops
case 1705: // Generic NiGHTS hoop
P_SpawnHoop(mthing, x, y, z, sec, 24, 4*FRACUNIT);
return;
case 1713: // Customizable NiGHTS hoop
// For each flag add 16 fracunits to the size
// Default (0 flags) is 32 fracunits
P_SpawnHoop(mthing, x, y, z, sec, 8 + (4*(mthing->options & 0xF)), 4*FRACUNIT);
return;
default: // All manners of rings and coins
P_SpawnRingItem(mthing, x, y, bonustime, nightsreplace);
}
}
//
// P_CheckMissileSpawn
// Moves the missile forward a bit and possibly explodes it right there.
......
......@@ -781,9 +781,10 @@ static void P_NetArchiveWorld(void)
UINT8 *put;
// reload the map just to see difference
mapsector_t *ms;
mapsidedef_t *msd;
maplinedef_t *mld;
virtres_t* virt = vres_GetMap(lastloadedmaplumpnum);
mapsector_t *ms = (mapsector_t*) vres_Find(virt, "SECTORS")->data;
mapsidedef_t *msd = (mapsidedef_t*) vres_Find(virt, "SIDEDEFS")->data;
maplinedef_t *mld = (maplinedef_t*) vres_Find(virt, "LINEDEFS")->data;
const sector_t *ss = sectors;
UINT8 diff, diff2, diff3;
......@@ -793,26 +794,6 @@ static void P_NetArchiveWorld(void)
WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD);
put = save_p;
if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3
{ // HACK: Open wad file rather quickly so we can get the data from the relevant lumps
UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
#define retrieve_mapdata(d, f)\
d = Z_Malloc((f)->size, PU_CACHE, NULL); \
M_Memcpy(d, wadData + (f)->filepos, (f)->size)
retrieve_mapdata(ms, fileinfo + ML_SECTORS);
retrieve_mapdata(mld, fileinfo + ML_LINEDEFS);
retrieve_mapdata(msd, fileinfo + ML_SIDEDEFS);
#undef retrieve_mapdata
Z_Free(wadData); // we're done with this now
}
else // phew it's just a WAD
{
ms = W_CacheLumpNum(lastloadedmaplumpnum+ML_SECTORS, PU_CACHE);
mld = W_CacheLumpNum(lastloadedmaplumpnum+ML_LINEDEFS, PU_CACHE);
msd = W_CacheLumpNum(lastloadedmaplumpnum+ML_SIDEDEFS, PU_CACHE);
}
for (i = 0; i < numsectors; i++, ss++, ms++)
{
diff = diff2 = diff3 = 0;
......@@ -1037,6 +1018,7 @@ static void P_NetArchiveWorld(void)
WRITEUINT16(put, 0xffff);
R_ClearTextureNumCache(false);
vres_Free(virt);
save_p = put;
}
......
......@@ -367,27 +367,12 @@ UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade)
return mapheaderinfo[map-1]->grades[mare].grade[grade-1];
}
/** Loads the vertexes for a level.
*
* \param lump VERTEXES lump number.
* \sa ML_VERTEXES
*/
static inline void P_LoadRawVertexes(UINT8 *data, size_t i)
// Loads the vertexes for a level.
static inline void P_LoadRawVertexes(UINT8 *data)
{
mapvertex_t *ml;
vertex_t *li;
numvertexes = i / sizeof (mapvertex_t);
if (numvertexes <= 0)
I_Error("Level has no vertices"); // instead of crashing
// Allocate zone memory for buffer.
vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL);
ml = (mapvertex_t *)data;
li = vertexes;
mapvertex_t *ml = (mapvertex_t *)data;
vertex_t *li = vertexes;
size_t i;
// Copy and convert vertex coordinates, internal representation as fixed.
for (i = 0; i < numvertexes; i++, li++, ml++)
......@@ -397,13 +382,6 @@ static inline void P_LoadRawVertexes(UINT8 *data, size_t i)
}
}
static inline void P_LoadVertexes(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawVertexes(data, W_LumpLength(lumpnum));
Z_Free(data);
}
/** Computes the length of a seg in fracunits.
*
* \param seg Seg to compute length for.
......@@ -435,25 +413,15 @@ static inline float P_SegLengthFloat(seg_t *seg)
}
#endif
/** Loads the SEGS resource from a level.
*
* \param lump Lump number of the SEGS resource.
* \sa ::ML_SEGS
*/
static void P_LoadRawSegs(UINT8 *data, size_t i)
// Loads the SEGS resource from a level.
static void P_LoadRawSegs(UINT8 *data)
{
INT32 linedef, side;
mapseg_t *ml;
seg_t *li;
mapseg_t *ml = (mapseg_t*)data;
seg_t *li = segs;
line_t *ldef;
size_t i;
numsegs = i / sizeof (mapseg_t);
if (numsegs <= 0)
I_Error("Level has no segs"); // instead of crashing
segs = Z_Calloc(numsegs * sizeof (*segs), PU_LEVEL, NULL);
ml = (mapseg_t *)data;
li = segs;
for (i = 0; i < numsegs; i++, li++, ml++)
{
li->v1 = &vertexes[SHORT(ml->v1)];
......@@ -478,7 +446,7 @@ static void P_LoadRawSegs(UINT8 *data, size_t i)
li->side = side = SHORT(ml->side);
li->sidedef = &sides[ldef->sidenum[side]];
li->frontsector = sides[ldef->sidenum[side]].sector;
if (ldef-> flags & ML_TWOSIDED)
if (ldef->flags & ML_TWOSIDED)
li->backsector = sides[ldef->sidenum[side^1]].sector;
else
li->backsector = 0;
......@@ -488,30 +456,12 @@ static void P_LoadRawSegs(UINT8 *data, size_t i)
}
}
static void P_LoadSegs(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawSegs(data, W_LumpLength(lumpnum));
Z_Free(data);
}
/** Loads the SSECTORS resource from a level.
*
* \param lump Lump number of the SSECTORS resource.
* \sa ::ML_SSECTORS
*/
static inline void P_LoadRawSubsectors(void *data, size_t i)
// Loads the SSECTORS resource from a level.
static inline void P_LoadRawSubsectors(void *data)
{
mapsubsector_t *ms;
subsector_t *ss;
numsubsectors = i / sizeof (mapsubsector_t);
if (numsubsectors <= 0)
I_Error("Level has no subsectors (did you forget to run it through a nodesbuilder?)");
ss = subsectors = Z_Calloc(numsubsectors * sizeof (*subsectors), PU_LEVEL, NULL);
ms = (mapsubsector_t *)data;
mapsubsector_t *ms = (mapsubsector_t*)data;
subsector_t *ss = subsectors;
size_t i;
for (i = 0; i < numsubsectors; i++, ss++, ms++)
{
......@@ -525,13 +475,6 @@ static inline void P_LoadRawSubsectors(void *data, size_t i)
}
}
static void P_LoadSubsectors(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawSubsectors(data, W_LumpLength(lumpnum));
Z_Free(data);
}
//
// levelflats
//
......@@ -698,20 +641,12 @@ INT32 P_CheckLevelFlat(const char *flatname)
}
// Sets up the ingame sectors structures.
// Lumpnum is the lumpnum of a SECTORS lump.
static void P_LoadRawSectors(UINT8 *data, size_t i)
static void P_LoadRawSectors(UINT8 *data)
{
mapsector_t *ms;
sector_t *ss;
mapsector_t *ms = (mapsector_t *)data;
sector_t *ss = sectors;
levelflat_t *foundflats;
// We count how many sectors we got.
numsectors = i / sizeof (mapsector_t);
if (numsectors <= 0)
I_Error("Level has no sectors");
// Allocate as much memory as we need into the global sectors table.
sectors = Z_Calloc(numsectors*sizeof (*sectors), PU_LEVEL, NULL);
size_t i;
// Allocate a big chunk of memory as big as our MAXLEVELFLATS limit.
//Fab : FIXME: allocate for whatever number of flats - 512 different flats per level should be plenty
......@@ -722,8 +657,6 @@ static void P_LoadRawSectors(UINT8 *data, size_t i)
numlevelflats = 0;
// For each counted sector, copy the sector raw data from our cache pointer ms, to the global table pointer ss.
ms = (mapsector_t *)data;
ss = sectors;
for (i = 0; i < numsectors; i++, ss++, ms++)
{
ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
......@@ -805,29 +738,15 @@ static void P_LoadRawSectors(UINT8 *data, size_t i)
P_SetupLevelFlatAnims();
}
static void P_LoadSectors(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawSectors(data, W_LumpLength(lumpnum));
Z_Free(data);
}
//
// P_LoadNodes
//
static void P_LoadRawNodes(UINT8 *data, size_t i)
static void P_LoadRawNodes(UINT8 *data)
{
UINT8 j, k;
mapnode_t *mn;
node_t *no;
numnodes = i / sizeof (mapnode_t);
if (numnodes <= 0)
I_Error("Level has no nodes");
nodes = Z_Calloc(numnodes * sizeof (*nodes), PU_LEVEL, NULL);
mn = (mapnode_t *)data;
no = nodes;
mapnode_t *mn = (mapnode_t*)data;
node_t *no = nodes;
size_t i;
for (i = 0; i < numnodes; i++, no++, mn++)
{
......@@ -844,13 +763,6 @@ static void P_LoadRawNodes(UINT8 *data, size_t i)
}
}
static void P_LoadNodes(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawNodes(data, W_LumpLength(lumpnum));
Z_Free(data);
}
//
// P_ReloadRings
// Used by NiGHTS, clears all ring/wing/etc items and respawns them
......@@ -906,10 +818,6 @@ void P_ReloadRings(void)
{
mt->mobj = NULL;
// Z for objects Tails 05-26-2002
mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)
->sector->floorheight>>FRACBITS);
P_SpawnHoopsAndRings(mt, true);
}
}
......@@ -1006,20 +914,16 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum)
}
#endif
static void P_PrepareRawThings(UINT8 *data, size_t i)
static void P_PrepareRawThings(UINT8 *data)
{
mapthing_t *mt;
size_t i;
nummapthings = i / (5 * sizeof (INT16));
mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL);
// Spawn axis points first so they are
// at the front of the list for fast searching.
mt = mapthings;
for (i = 0; i < nummapthings; i++, mt++)
for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
{
mt->x = READINT16(data);
mt->y = READINT16(data);
mt->angle = READINT16(data);
mt->type = READUINT16(data);
mt->options = READUINT16(data);
......@@ -1027,6 +931,66 @@ static void P_PrepareRawThings(UINT8 *data, size_t i)
mt->type &= 4095;
if (mt->type == 1705 || (mt->type == 750 && mt->extrainfo))
mt->z = mt->options; // NiGHTS Hoops use the full flags bits to set the height.
else
mt->z = mt->options >> ZSHIFT;
}
}
static void P_SpawnEmeraldHunt(void)
{
INT32 emer1, emer2, emer3;
INT32 timeout = 0; // keeps from getting stuck
emer1 = emer2 = emer3 = 0;
//increment spawn numbers because zero is valid.
emer1 = (P_RandomKey(numhuntemeralds)) + 1;
while (timeout++ < 100)
{
emer2 = (P_RandomKey(numhuntemeralds)) + 1;
if (emer2 != emer1)
break;
}
timeout = 0;
while (timeout++ < 100)
{
emer3 = (P_RandomKey(numhuntemeralds)) + 1;
if (emer3 != emer2 && emer3 != emer1)
break;
}
//decrement spawn values to the actual number because zero is valid.
if (emer1--)
P_SpawnMobj(huntemeralds[emer1]->x<<FRACBITS,
huntemeralds[emer1]->y<<FRACBITS,
huntemeralds[emer1]->z<<FRACBITS, MT_EMERHUNT);
if (emer2--)
P_SetMobjStateNF(P_SpawnMobj(huntemeralds[emer2]->x<<FRACBITS,
huntemeralds[emer2]->y<<FRACBITS,
huntemeralds[emer2]->z<<FRACBITS, MT_EMERHUNT),
mobjinfo[MT_EMERHUNT].spawnstate+1);
if (emer3--)
P_SetMobjStateNF(P_SpawnMobj(huntemeralds[emer3]->x<<FRACBITS,
huntemeralds[emer3]->y<<FRACBITS,
huntemeralds[emer3]->z<<FRACBITS, MT_EMERHUNT),
mobjinfo[MT_EMERHUNT].spawnstate+2);
}
static void P_LoadThings(boolean loademblems)
{
size_t i;
mapthing_t *mt;
// Spawn axis points first so they are at the front of the list for fast searching.
for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
{
switch (mt->type)
{
case 1700: // MT_AXIS
......@@ -1039,35 +1003,11 @@ static void P_PrepareRawThings(UINT8 *data, size_t i)
break;
}
}
}
static void P_PrepareThings(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_PrepareRawThings(data, W_LumpLength(lumpnum));
Z_Free(data);
}
static void P_LoadThings(boolean loademblems)
{
size_t i;
mapthing_t *mt;
// Loading the things lump itself into memory is now handled in P_PrepareThings, above
mt = mapthings;
numhuntemeralds = 0;
for (i = 0; i < nummapthings; i++, mt++)
{
sector_t *mtsector = R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)->sector;
// Z for objects
mt->z = (INT16)(
#ifdef ESLOPE
mtsector->f_slope ? P_GetZAt(mtsector->f_slope, mt->x << FRACBITS, mt->y << FRACBITS) :
#endif
mtsector->floorheight)>>FRACBITS;
for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
{
if (mt->type == 1700 // MT_AXIS
|| mt->type == 1701 // MT_AXISTRANSFER
|| mt->type == 1702) // MT_AXISTRANSFERLINE
......@@ -1082,49 +1022,7 @@ static void P_LoadThings(boolean loademblems)
// random emeralds for hunt
if (numhuntemeralds)
{
INT32 emer1, emer2, emer3;
INT32 timeout = 0; // keeps from getting stuck
emer1 = emer2 = emer3 = 0;
//increment spawn numbers because zero is valid.
emer1 = (P_RandomKey(numhuntemeralds)) + 1;
while (timeout++ < 100)
{
emer2 = (P_RandomKey(numhuntemeralds)) + 1;
if (emer2 != emer1)
break;
}
timeout = 0;
while (timeout++ < 100)
{
emer3 = (P_RandomKey(numhuntemeralds)) + 1;
if (emer3 != emer2 && emer3 != emer1)
break;
}
//decrement spawn values to the actual number because zero is valid.
if (emer1--)
P_SpawnMobj(huntemeralds[emer1]->x<<FRACBITS,
huntemeralds[emer1]->y<<FRACBITS,
huntemeralds[emer1]->z<<FRACBITS, MT_EMERHUNT);
if (emer2--)
P_SetMobjStateNF(P_SpawnMobj(huntemeralds[emer2]->x<<FRACBITS,
huntemeralds[emer2]->y<<FRACBITS,
huntemeralds[emer2]->z<<FRACBITS, MT_EMERHUNT),
mobjinfo[MT_EMERHUNT].spawnstate+1);
if (emer3--)
P_SetMobjStateNF(P_SpawnMobj(huntemeralds[emer3]->x<<FRACBITS,
huntemeralds[emer3]->y<<FRACBITS,
huntemeralds[emer3]->z<<FRACBITS, MT_EMERHUNT),
mobjinfo[MT_EMERHUNT].spawnstate+2);
}
P_SpawnEmeraldHunt();
if (metalrecording) // Metal Sonic gets no rings to distract him.
return;
......@@ -1140,11 +1038,6 @@ static void P_LoadThings(boolean loademblems)
|| mt->type == 1705 || mt->type == 1713) // hoops
{
mt->mobj = NULL;
// Z for objects Tails 05-26-2002
mt->z = (INT16)(R_PointInSubsector(mt->x << FRACBITS, mt->y << FRACBITS)
->sector->floorheight>>FRACBITS);
P_SpawnHoopsAndRings(mt, false);
}
}
......@@ -1193,33 +1086,46 @@ void P_WriteThings(lumpnum_t lumpnum)
CONS_Printf(M_GetText("newthings%d.lmp saved.\n"), gamemap);
}
static void P_LoadRawLineDefs(UINT8 *data, size_t i)
static void P_LoadRawLineDefs(UINT8 *data)
{
maplinedef_t *mld;
line_t *ld;
vertex_t *v1, *v2;
numlines = i / sizeof (maplinedef_t);
if (numlines <= 0)
I_Error("Level has no linedefs");
lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL);
maplinedef_t *mld = (maplinedef_t *)data;
line_t *ld = lines;
size_t i;
mld = (maplinedef_t *)data;
ld = lines;
for (i = 0; i < numlines; i++, mld++, ld++)
{
ld->flags = SHORT(mld->flags);
ld->special = SHORT(mld->special);
ld->tag = SHORT(mld->tag);
v1 = ld->v1 = &vertexes[SHORT(mld->v1)];
v2 = ld->v2 = &vertexes[SHORT(mld->v2)];
ld->dx = v2->x - v1->x;
ld->dy = v2->y - v1->y;
ld->v1 = &vertexes[SHORT(mld->v1)];
ld->v2 = &vertexes[SHORT(mld->v2)];
ld->sidenum[0] = SHORT(mld->sidenum[0]);
ld->sidenum[1] = SHORT(mld->sidenum[1]);
}
}
static void P_SetupLines(void)
{
line_t *ld = lines;
size_t i;
for (i = 0; i < numlines; i++, ld++)
{
vertex_t *v1 = ld->v1;
vertex_t *v2 = ld->v2;
#ifdef WALLSPLATS
ld->splats = NULL;
#endif
#ifdef POLYOBJECTS
ld->polyobj = NULL;
#endif
ld->dx = v2->x - v1->x;
ld->dy = v2->y - v1->y;
if (!ld->dx)
ld->slopetype = ST_VERTICAL;
else if (!ld->dy)
......@@ -1251,62 +1157,46 @@ static void P_LoadRawLineDefs(UINT8 *data, size_t i)
ld->bbox[BOXTOP] = v1->y;
}
ld->sidenum[0] = SHORT(mld->sidenum[0]);
ld->sidenum[1] = SHORT(mld->sidenum[1]);
{
// cph 2006/09/30 - fix sidedef errors right away.
// cph 2002/07/20 - these errors are fatal if not fixed, so apply them
UINT8 j;
for (j=0; j < 2; j++)
{
if (ld->sidenum[j] != 0xffff && ld->sidenum[j] >= (UINT16)numsides)
{
ld->sidenum[j] = 0xffff;
CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s has out-of-range sidedef number\n", sizeu1(numlines-i-1));
}
}
}
ld->frontsector = ld->backsector = NULL;
ld->validcount = 0;
ld->firsttag = ld->nexttag = -1;
ld->callcount = 0;
// killough 11/98: fix common wad errors (missing sidedefs):
// killough 11/98: fix common wad errors (missing sidedefs):
if (ld->sidenum[0] == 0xffff)
{
ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side
// cph - print a warning about the bug
CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s missing first sidedef\n", sizeu1(numlines-i-1));
CONS_Debug(DBG_SETUP, "Linedef %s missing first sidedef\n", sizeu1(numlines-i-1));
}
if ((ld->sidenum[1] == 0xffff) && (ld->flags & ML_TWOSIDED))
{
ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side
// cph - print a warning about the bug
CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s has two-sided flag set, but no second sidedef\n", sizeu1(numlines-i-1));
CONS_Debug(DBG_SETUP, "Linedef %s has two-sided flag set, but no second sidedef\n", sizeu1(numlines-i-1));
}
if (ld->sidenum[0] != 0xffff && ld->special)
sides[ld->sidenum[0]].special = ld->special;
if (ld->sidenum[1] != 0xffff && ld->special)
sides[ld->sidenum[1]].special = ld->special;
#ifdef POLYOBJECTS
ld->polyobj = NULL;
#endif
}
}
static void P_LoadLineDefs(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawLineDefs(data, W_LumpLength(lumpnum));
Z_Free(data);
}
static void P_LoadLineDefs2(void)
{
size_t i = numlines;
......@@ -1409,22 +1299,6 @@ static void P_LoadLineDefs2(void)
}
}
static inline void P_LoadRawSideDefs(size_t i)
{
numsides = i / sizeof (mapsidedef_t);
if (numsides <= 0)
I_Error("Level has no sidedefs");
sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL);
}
static inline void P_LoadSideDefs(lumpnum_t lumpnum)
{
P_LoadRawSideDefs(W_LumpLength(lumpnum));
}
static void P_LoadRawSideDefs2(void *data)
{
UINT16 i;
......@@ -1585,15 +1459,6 @@ static void P_LoadRawSideDefs2(void *data)
R_ClearTextureNumCache(true);
}
// Delay loading texture names until after loaded linedefs.
static void P_LoadSideDefs2(lumpnum_t lumpnum)
{
UINT8 *data = W_CacheLumpNum(lumpnum, PU_STATIC);
P_LoadRawSideDefs2(data);
Z_Free(data);
}
static boolean LineInBlock(fixed_t cx1, fixed_t cy1, fixed_t cx2, fixed_t cy2, fixed_t bx1, fixed_t by1)
{
fixed_t bbox[4];
......@@ -1873,84 +1738,11 @@ static void P_ReadBlockMapLump(INT16 *wadblockmaplump, size_t count)
}
}
//
// P_LoadBlockMap
//
// Levels might not have a blockmap, so if one does not exist
// this should return false.
static boolean P_LoadBlockMap(lumpnum_t lumpnum)
{
#if 0
(void)lumpnum;
return false;
#else
size_t count;
const char *lumpname = W_CheckNameForNum(lumpnum);
// Check if the lump exists, and if it's named "BLOCKMAP"
if (!lumpname || memcmp(lumpname, "BLOCKMAP", 8) != 0)
{
return false;
}
count = W_LumpLength(lumpnum);
if (!count || count >= 0x20000)
return false;
{
INT16 *wadblockmaplump = malloc(count); //INT16 *wadblockmaplump = W_CacheLumpNum (lump, PU_LEVEL);
if (!wadblockmaplump)
return false;
W_ReadLump(lumpnum, wadblockmaplump);
count /= 2;
P_ReadBlockMapLump(wadblockmaplump, count);
free(wadblockmaplump);
}
bmaporgx = blockmaplump[0]<<FRACBITS;
bmaporgy = blockmaplump[1]<<FRACBITS;
bmapwidth = blockmaplump[2];
bmapheight = blockmaplump[3];
// clear out mobj chains
count = sizeof (*blocklinks)* bmapwidth*bmapheight;
blocklinks = Z_Calloc(count, PU_LEVEL, NULL);
blockmap = blockmaplump+4;
#ifdef POLYOBJECTS
// haleyjd 2/22/06: setup polyobject blockmap
count = sizeof(*polyblocklinks) * bmapwidth * bmapheight;
polyblocklinks = Z_Calloc(count, PU_LEVEL, NULL);
#endif
return true;
/* Original
blockmaplump = W_CacheLumpNum(lump, PU_LEVEL);
blockmap = blockmaplump+4;
count = W_LumpLength (lump)/2;
for (i = 0; i < count; i++)
blockmaplump[i] = SHORT(blockmaplump[i]);
bmaporgx = blockmaplump[0]<<FRACBITS;
bmaporgy = blockmaplump[1]<<FRACBITS;
bmapwidth = blockmaplump[2];
bmapheight = blockmaplump[3];
}
// clear out mobj chains
count = sizeof (*blocklinks)*bmapwidth*bmapheight;
blocklinks = Z_Calloc(count, PU_LEVEL, NULL);
return true;
*/
#endif
}
// This needs to be a separate function
// because making both the WAD and PK3 loading code use
// the same functions is trickier than it looks for blockmap
// -- Monster Iestyn 09/01/18
static boolean P_LoadRawBlockMap(UINT8 *data, size_t count, const char *lumpname)
static boolean P_LoadRawBlockMap(UINT8 *data, size_t count)
{
#if 0
(void)data;
......@@ -1958,12 +1750,6 @@ static boolean P_LoadRawBlockMap(UINT8 *data, size_t count, const char *lumpname
(void)lumpname;
return false;
#else
// Check if the lump is named "BLOCKMAP"
if (!lumpname || memcmp(lumpname, "BLOCKMAP", 8) != 0)
{
CONS_Printf("No blockmap lump found for pk3!\n");
return false;
}
if (!count || count >= 0x20000)
return false;
......@@ -2089,56 +1875,139 @@ static void P_GroupLines(void)
}
}
//
// P_LoadReject
//
// Detect if the REJECT lump is valid,
// if not, rejectmatrix will be NULL
static void P_LoadReject(lumpnum_t lumpnum)
// PK3 version
// -- Monster Iestyn 09/01/18
static void P_LoadRawReject(UINT8 *data, size_t count)
{
size_t count;
const char *lumpname = W_CheckNameForNum(lumpnum);
// Check if the lump exists, and if it's named "REJECT"
if (!lumpname || memcmp(lumpname, "REJECT\0\0", 8) != 0)
if (!count) // zero length, someone probably used ZDBSP
{
rejectmatrix = NULL;
CONS_Debug(DBG_SETUP, "P_LoadReject: No valid REJECT lump found\n");
return;
CONS_Debug(DBG_SETUP, "P_LoadRawReject: REJECT lump has size 0, will not be loaded\n");
}
count = W_LumpLength(lumpnum);
if (!count) // zero length, someone probably used ZDBSP
else
{
rejectmatrix = NULL;
CONS_Debug(DBG_SETUP, "P_LoadReject: REJECT lump has size 0, will not be loaded\n");
rejectmatrix = Z_Malloc(count, PU_LEVEL, NULL); // allocate memory for the reject matrix
M_Memcpy(rejectmatrix, data, count); // copy the data into it
}
}
static void P_LoadMapBSP(const virtres_t* virt)
{
virtlump_t* virtssectors = vres_Find(virt, "SSECTORS");
virtlump_t* virtsegs = vres_Find(virt, "SEGS");
virtlump_t* virtnodes = vres_Find(virt, "NODES");
numsubsectors = virtssectors->size / sizeof(mapsubsector_t);
numnodes = virtnodes->size / sizeof(mapnode_t);
numsegs = virtsegs->size / sizeof(mapseg_t);
if (numsubsectors <= 0)
I_Error("Level has no subsectors (did you forget to run it through a nodesbuilder?)");
if (numnodes <= 0)
I_Error("Level has no nodes");
if (numsegs <= 0)
I_Error("Level has no segs");
subsectors = Z_Calloc(numsubsectors * sizeof(*subsectors), PU_LEVEL, NULL);
nodes = Z_Calloc(numnodes * sizeof(*nodes), PU_LEVEL, NULL);
segs = Z_Calloc(numsegs * sizeof(*segs), PU_LEVEL, NULL);
// Nodes
P_LoadRawSubsectors(virtssectors->data);
P_LoadRawNodes(virtnodes->data);
P_LoadRawSegs(virtsegs->data);
}
static void P_LoadMapLUT(const virtres_t* virt)
{
virtlump_t* virtblockmap = vres_Find(virt, "BLOCKMAP");
virtlump_t* virtreject = vres_Find(virt, "REJECT");
// Lookup tables
if (virtreject)
P_LoadRawReject(virtreject->data, virtreject->size);
else
rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL);
rejectmatrix = NULL;
if (!(virtblockmap && P_LoadRawBlockMap(virtblockmap->data, virtblockmap->size)))
P_CreateBlockMap();
}
// PK3 version
// -- Monster Iestyn 09/01/18
static void P_LoadRawReject(UINT8 *data, size_t count, const char *lumpname)
static void P_LoadMapData(const virtres_t* virt)
{
// Check if the lump is named "REJECT"
if (!lumpname || memcmp(lumpname, "REJECT\0\0", 8) != 0)
virtlump_t* virtvertexes = NULL, * virtsectors = NULL, * virtsidedefs = NULL, * virtlinedefs = NULL, * virtthings = NULL;
#ifdef UDMF
virtlump_t* textmap = vres_Find(virt, "TEXTMAP");
// Count map data.
if (textmap)
{
rejectmatrix = NULL;
CONS_Debug(DBG_SETUP, "P_LoadRawReject: No valid REJECT lump found\n");
return;
nummapthings = 0;
numlines = 0;
numsides = 0;
numvertexes = 0;
numsectors = 0;
// Count how many entries for each type we got in textmap.
//TextmapCount(vtextmap->data, vtextmap->size);
}
else
#endif
{
virtthings = vres_Find(virt, "THINGS");
virtvertexes = vres_Find(virt, "VERTEXES");
virtsectors = vres_Find(virt, "SECTORS");
virtsidedefs = vres_Find(virt, "SIDEDEFS");
virtlinedefs = vres_Find(virt, "LINEDEFS");
if (!virtthings)
I_Error("THINGS lump not found");
if (!virtvertexes)
I_Error("VERTEXES lump not found");
if (!virtsectors)
I_Error("SECTORS lump not found");
if (!virtsidedefs)
I_Error("SIDEDEFS lump not found");
if (!virtlinedefs)
I_Error("LINEDEFS lump not found");
// Traditional doom map format just assumes the number of elements from the lump sizes.
numvertexes = virtvertexes->size / sizeof (mapvertex_t);
numsectors = virtsectors->size / sizeof (mapsector_t);
numsides = virtsidedefs->size / sizeof (mapsidedef_t);
numlines = virtlinedefs->size / sizeof (maplinedef_t);
nummapthings = virtthings->size / (5 * sizeof (INT16));
}
if (!count) // zero length, someone probably used ZDBSP
if (numvertexes <= 0)
I_Error("Level has no vertices");
if (numsectors <= 0)
I_Error("Level has no sectors");
if (numsides <= 0)
I_Error("Level has no sidedefs");
if (numlines <= 0)
I_Error("Level has no linedefs");
vertexes = Z_Calloc(numvertexes * sizeof (*vertexes), PU_LEVEL, NULL);
sectors = Z_Calloc(numsectors * sizeof (*sectors), PU_LEVEL, NULL);
sides = Z_Calloc(numsides * sizeof (*sides), PU_LEVEL, NULL);
lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL);
mapthings = Z_Calloc(nummapthings * sizeof (*mapthings), PU_LEVEL, NULL);
#ifdef UDMF
if (textmap)
{
rejectmatrix = NULL;
CONS_Debug(DBG_SETUP, "P_LoadRawReject: REJECT lump has size 0, will not be loaded\n");
}
else
#endif
{
rejectmatrix = Z_Malloc(count, PU_LEVEL, NULL); // allocate memory for the reject matrix
M_Memcpy(rejectmatrix, data, count); // copy the data into it
// Strict map data
P_LoadRawVertexes(virtvertexes->data);
P_LoadRawSectors(virtsectors->data);
P_LoadRawLineDefs(virtlinedefs->data);
P_SetupLines();
P_LoadRawSideDefs2(virtsidedefs->data);
}
}
......@@ -2317,6 +2186,8 @@ void P_LoadThingsOnly(void)
// Search through all the thinkers.
thinker_t *think;
INT32 i, viewid = -1, centerid = -1; // for skyboxes
virtres_t* virt = vres_GetMap(lastloadedmaplumpnum);
virtlump_t* vth = vres_Find(virt, "THINGS");
// check if these are any of the normal viewpoint/centerpoint mobjs in the level or not
if (skyboxmo[0] || skyboxmo[1])
......@@ -2328,7 +2199,6 @@ void P_LoadThingsOnly(void)
centerid = i; // save id just in case
}
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
......@@ -2338,18 +2208,11 @@ void P_LoadThingsOnly(void)
P_LevelInitStuff();
if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3
{ // HACK: Open wad file rather quickly so we can use the things lump
UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
fileinfo += ML_THINGS; // we only need the THINGS lump
P_PrepareRawThings(wadData + fileinfo->filepos, fileinfo->size);
Z_Free(wadData); // we're done with this now
}
else // phew it's just a WAD
P_PrepareThings(lastloadedmaplumpnum + ML_THINGS);
P_PrepareRawThings(vth->data);
P_LoadThings(true);
vres_Free(virt);
// restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that
skyboxmo[0] = skyboxviewpnts[(viewid >= 0) ? viewid : 0];
skyboxmo[1] = skyboxcenterpnts[(centerid >= 0) ? centerid : 0];
......@@ -2381,7 +2244,7 @@ static INT32 P_MakeBufferMD5(const char *buffer, size_t len, void *resblock)
#endif
}
static void P_MakeMapMD5(lumpnum_t maplumpnum, void *dest)
static void P_MakeMapMD5(virtres_t* virt, void *dest)
{
unsigned char linemd5[16];
unsigned char sectormd5[16];
......@@ -2392,20 +2255,15 @@ static void P_MakeMapMD5(lumpnum_t maplumpnum, void *dest)
// Create a hash for the current map
// get the actual lumps!
UINT8 *datalines = W_CacheLumpNum(maplumpnum + ML_LINEDEFS, PU_CACHE);
UINT8 *datasectors = W_CacheLumpNum(maplumpnum + ML_SECTORS, PU_CACHE);
UINT8 *datathings = W_CacheLumpNum(maplumpnum + ML_THINGS, PU_CACHE);
UINT8 *datasides = W_CacheLumpNum(maplumpnum + ML_SIDEDEFS, PU_CACHE);
P_MakeBufferMD5((char*)datalines, W_LumpLength(maplumpnum + ML_LINEDEFS), linemd5);
P_MakeBufferMD5((char*)datasectors, W_LumpLength(maplumpnum + ML_SECTORS), sectormd5);
P_MakeBufferMD5((char*)datathings, W_LumpLength(maplumpnum + ML_THINGS), thingmd5);
P_MakeBufferMD5((char*)datasides, W_LumpLength(maplumpnum + ML_SIDEDEFS), sidedefmd5);
virtlump_t* virtlines = vres_Find(virt, "LINEDEFS");
virtlump_t* virtsectors = vres_Find(virt, "SECTORS");
virtlump_t* virtmthings = vres_Find(virt, "THINGS");
virtlump_t* virtsides = vres_Find(virt, "SIDEDEFS");
Z_Free(datalines);
Z_Free(datasectors);
Z_Free(datathings);
Z_Free(datasides);
P_MakeBufferMD5((char*)virtlines->data, virtlines->size, linemd5);
P_MakeBufferMD5((char*)virtsectors->data, virtsectors->size, sectormd5);
P_MakeBufferMD5((char*)virtmthings->data, virtmthings->size, thingmd5);
P_MakeBufferMD5((char*)virtsides->data, virtsides->size, sidedefmd5);
for (i = 0; i < 16; i++)
resmd5[i] = (linemd5[i] + sectormd5[i] + thingmd5[i] + sidedefmd5[i]) & 0xFF;
......@@ -2641,7 +2499,6 @@ boolean P_SetupLevel(boolean skipprecip)
INT32 i, loadprecip = 1, ranspecialwipe = 0;
INT32 loademblems = 1;
INT32 fromnetsave = 0;
boolean loadedbm = false;
sector_t *ss;
boolean chase;
levelloading = true;
......@@ -2890,110 +2747,39 @@ boolean P_SetupLevel(boolean skipprecip)
// SRB2 determines the sky texture to be used depending on the map header.
P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true);
P_MakeMapMD5(lastloadedmaplumpnum, &mapmd5);
// HACK ALERT: Cache the WAD, get the map data into the tables, free memory.
// As it is implemented right now, we're assuming an uncompressed WAD.
// (As in, a normal PWAD, not ZWAD or anything. The lump itself can be compressed.)
// We're not accounting for extra lumps and scrambled lump positions. Any additional data will cause an error.
if (W_IsLumpWad(lastloadedmaplumpnum))
{
// Remember that we're assuming that the WAD will have a specific set of lumps in a specific order.
UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
//filelump_t *fileinfo = wadData + ((wadinfo_t *)wadData)->infotableofs;
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
UINT32 numlumps = ((wadinfo_t *)wadData)->numlumps;
if (numlumps < ML_REJECT) // at least 9 lumps should be in the wad for a map to be loaded
{
I_Error("Bad WAD file for map %s!\n", maplumpname);
}
numdmstarts = numredctfstarts = numbluectfstarts = 0;
if (numlumps > ML_BLOCKMAP) // enough room for a BLOCKMAP lump at least
{
loadedbm = P_LoadRawBlockMap(
wadData + (fileinfo + ML_BLOCKMAP)->filepos,
(fileinfo + ML_BLOCKMAP)->size,
(fileinfo + ML_BLOCKMAP)->name);
}
P_LoadRawVertexes(wadData + (fileinfo + ML_VERTEXES)->filepos, (fileinfo + ML_VERTEXES)->size);
P_LoadRawSectors(wadData + (fileinfo + ML_SECTORS)->filepos, (fileinfo + ML_SECTORS)->size);
P_LoadRawSideDefs((fileinfo + ML_SIDEDEFS)->size);
P_LoadRawLineDefs(wadData + (fileinfo + ML_LINEDEFS)->filepos, (fileinfo + ML_LINEDEFS)->size);
P_LoadRawSideDefs2(wadData + (fileinfo + ML_SIDEDEFS)->filepos);
P_LoadRawSubsectors(wadData + (fileinfo + ML_SSECTORS)->filepos, (fileinfo + ML_SSECTORS)->size);
P_LoadRawNodes(wadData + (fileinfo + ML_NODES)->filepos, (fileinfo + ML_NODES)->size);
P_LoadRawSegs(wadData + (fileinfo + ML_SEGS)->filepos, (fileinfo + ML_SEGS)->size);
if (numlumps > ML_REJECT) // enough room for a REJECT lump at least
{
P_LoadRawReject(
wadData + (fileinfo + ML_REJECT)->filepos,
(fileinfo + ML_REJECT)->size,
(fileinfo + ML_REJECT)->name);
}
// reset the player starts
for (i = 0; i < MAXPLAYERS; i++)
playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
// Important: take care of the ordering of the next functions.
if (!loadedbm)
P_CreateBlockMap(); // Graue 02-29-2004
P_LoadLineDefs2();
P_GroupLines();
numdmstarts = numredctfstarts = numbluectfstarts = 0;
for (i = 0; i < MAX_DM_STARTS; i++)
deathmatchstarts[i] = NULL;
// reset the player starts
for (i = 0; i < MAXPLAYERS; i++)
playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
for (i = 0; i < 2; i++)
skyboxmo[i] = NULL;
for (i = 0; i < MAX_DM_STARTS; i++)
deathmatchstarts[i] = NULL;
for (i = 0; i < 16; i++)
skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL;
for (i = 0; i < 2; i++)
skyboxmo[i] = NULL;
P_MapStart();
for (i = 0; i < 16; i++)
skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL;
if (lastloadedmaplumpnum)
{
virtres_t* virt = vres_GetMap(lastloadedmaplumpnum);
P_MapStart();
P_LoadMapData(virt);
P_LoadMapBSP(virt);
P_LoadMapLUT(virt);
P_PrepareRawThings(wadData + (fileinfo + ML_THINGS)->filepos, (fileinfo + ML_THINGS)->size);
Z_Free(wadData);
}
else
{
// Important: take care of the ordering of the next functions.
loadedbm = P_LoadBlockMap(lastloadedmaplumpnum + ML_BLOCKMAP);
P_LoadVertexes(lastloadedmaplumpnum + ML_VERTEXES);
P_LoadSectors(lastloadedmaplumpnum + ML_SECTORS);
P_LoadSideDefs(lastloadedmaplumpnum + ML_SIDEDEFS);
P_LoadLineDefs(lastloadedmaplumpnum + ML_LINEDEFS);
P_LoadSideDefs2(lastloadedmaplumpnum + ML_SIDEDEFS);
P_LoadSubsectors(lastloadedmaplumpnum + ML_SSECTORS);
P_LoadNodes(lastloadedmaplumpnum + ML_NODES);
P_LoadSegs(lastloadedmaplumpnum + ML_SEGS);
P_LoadReject(lastloadedmaplumpnum + ML_REJECT);
// Important: take care of the ordering of the next functions.
if (!loadedbm)
P_CreateBlockMap(); // Graue 02-29-2004
P_LoadLineDefs2();
P_GroupLines();
numdmstarts = numredctfstarts = numbluectfstarts = 0;
// reset the player starts
for (i = 0; i < MAXPLAYERS; i++)
playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
for (i = 0; i < MAX_DM_STARTS; i++)
deathmatchstarts[i] = NULL;
for (i = 0; i < 2; i++)
skyboxmo[i] = NULL;
for (i = 0; i < 16; i++)
skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL;
P_PrepareRawThings(vres_Find(virt, "THINGS")->data);
P_MapStart();
P_MakeMapMD5(virt, &mapmd5);
P_PrepareThings(lastloadedmaplumpnum + ML_THINGS);
vres_Free(virt);
}
// init gravity, tag lists,
......
......@@ -6441,7 +6441,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
INT32 j;
thinkerlist_t *secthinkers;
thinker_t *th;
virtres_t* virt = NULL;
// This used to be used, and *should* be used in the future,
// but currently isn't.
(void)fromnetsave;
......@@ -7193,17 +7193,10 @@ void P_SpawnSpecials(INT32 fromnetsave)
UINT8 *data;
UINT16 b;
if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3
{ // HACK: Open wad file rather quickly so we can get the data from the sidedefs lump
UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
fileinfo += ML_SIDEDEFS; // we only need the SIDEDEFS lump
data = Z_Malloc(fileinfo->size, PU_STATIC, NULL);
M_Memcpy(data, wadData + fileinfo->filepos, fileinfo->size); // copy data
Z_Free(wadData); // we're done with this now
}
else // phew it's just a WAD
data = W_CacheLumpNum(lastloadedmaplumpnum + ML_SIDEDEFS,PU_STATIC);
if (!virt)
virt = vres_GetMap(lastloadedmaplumpnum);
data = (UINT8*) vres_Find(virt, "SIDEDEFS")->data;
for (b = 0; b < (INT16)numsides; b++)
{
......@@ -7223,7 +7216,6 @@ void P_SpawnSpecials(INT32 fromnetsave)
I_Error("Make-Your-Own-FOF (tag %d) needs a value in the linedef's second side upper texture field.", lines[i].tag);
}
}
Z_Free(data);
}
else
I_Error("Make-Your-Own FOF (tag %d) found without a 2nd linedef side!", lines[i].tag);
......@@ -7449,6 +7441,9 @@ void P_SpawnSpecials(INT32 fromnetsave)
}
}
if (virt)
vres_Free(virt);
// Allocate each list
for (i = 0; i < numsectors; i++)
if(secthinkers[i].thinkers)
......
......@@ -1600,7 +1600,7 @@ void P_RestoreMusic(player_t *player)
P_PlayJingle(player, JT_SUPER);
// Invulnerability
else if (player->powers[pw_invulnerability] > 1)
else if (player->powers[pw_invulnerability] > 1 && !player->powers[pw_super])
{
strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]);
......@@ -4635,7 +4635,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
S_StartSound(player->mo, sfx_spin);
break;
}
if (player->dashspeed < player->maxdash)
if (player->dashspeed < player->maxdash && player->mindash != player->maxdash)
{
#define chargecalculation (6*(player->dashspeed - player->mindash))/(player->maxdash - player->mindash)
fixed_t soundcalculation = chargecalculation;
......@@ -5128,11 +5128,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
boolean elem = ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL);
player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
if (elem)
{
player->pflags |= PF_NOJUMPDAMAGE;
P_SetPlayerMobjState(player->mo, S_PLAY_FALL);
S_StartSound(player->mo, sfx_s3k43);
}
else
{
player->pflags &= ~PF_NOJUMPDAMAGE;
......@@ -5273,7 +5269,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
player->secondjump = 0;
player->pflags &= ~PF_THOKKED;
}
else if (player->pflags & PF_SLIDING || (gametype == GT_CTF && player->gotflag))
else if (player->pflags & PF_SLIDING || (gametype == GT_CTF && player->gotflag) || player->pflags & PF_SHIELDABILITY)
;
/*else if (P_SuperReady(player))
{
......
......@@ -2320,14 +2320,20 @@ static void ST_drawTeamHUD(void)
p = bflagico;
else
p = bmatcico;
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_teamscores))
#endif
V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p);
if (gametype == GT_CTF)
p = rflagico;
else
p = rmatcico;
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_teamscores))
#endif
V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p);
if (gametype != GT_CTF)
......@@ -2339,28 +2345,53 @@ static void ST_drawTeamHUD(void)
// Show which flags aren't at base.
for (i = 0; i < MAXPLAYERS; i++)
{
if (players[i].gotflag & GF_BLUEFLAG) // Blue flag isn't at base
if (players[i].gotflag & GF_BLUEFLAG // Blue flag isn't at base
#ifdef HAVE_BLUA
&& LUA_HudEnabled(hud_teamscores)
#endif
)
V_DrawScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(nonicon->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon);
if (players[i].gotflag & GF_REDFLAG) // Red flag isn't at base
if (players[i].gotflag & GF_REDFLAG // Red flag isn't at base
#ifdef HAVE_BLUA
&& LUA_HudEnabled(hud_teamscores)
#endif
)
V_DrawScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(nonicon2->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon2);
whichflag |= players[i].gotflag;
if ((whichflag & (GF_REDFLAG|GF_BLUEFLAG)) == (GF_REDFLAG|GF_BLUEFLAG))
break; // both flags were found, let's stop early
}
// Display a countdown timer showing how much time left until the flag returns to base.
{
if (blueflag && blueflag->fuse > 1)
if (blueflag && blueflag->fuse > 1
#ifdef HAVE_BLUA
&& LUA_HudEnabled(hud_teamscores)
#endif
)
V_DrawCenteredString(BASEVIDWIDTH/2 - SEP, 8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", (blueflag->fuse / TICRATE)));
if (redflag && redflag->fuse > 1)
if (redflag && redflag->fuse > 1
#ifdef HAVE_BLUA
&& LUA_HudEnabled(hud_teamscores)
#endif
)
V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", (redflag->fuse / TICRATE)));
}
}
num:
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_teamscores))
#endif
V_DrawCenteredString(BASEVIDWIDTH/2 - SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", bluescore));
#ifdef HAVE_BLUA
if (LUA_HudEnabled(hud_teamscores))
#endif
V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", redscore));
#undef SEP
......
......@@ -1888,3 +1888,101 @@ int W_VerifyNMUSlumps(const char *filename)
};
return W_VerifyFile(filename, NMUSlist, false);
}
/** \brief Generates a virtual resource used for level data loading.
*
* \param lumpnum_t reference
* \return Virtual resource
*
*/
virtres_t* vres_GetMap(lumpnum_t lumpnum)
{
UINT32 i;
virtres_t* vres = NULL;
virtlump_t* vlumps = NULL;
size_t numlumps = 0;
if (W_IsLumpWad(lumpnum))
{
// Remember that we're assuming that the WAD will have a specific set of lumps in a specific order.
UINT8 *wadData = W_CacheLumpNum(lumpnum, PU_LEVEL);
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs);
numlumps = ((wadinfo_t *)wadData)->numlumps;
vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL);
// Build the lumps.
for (i = 0; i < numlumps; i++)
{
vlumps[i].size = (size_t)(((filelump_t *)(fileinfo + i))->size);
// Play it safe with the name in this case.
memcpy(vlumps[i].name, (fileinfo + i)->name, 8);
vlumps[i].name[8] = '\0';
vlumps[i].data = Z_Malloc(vlumps[i].size, PU_LEVEL, NULL); // This is memory inefficient, sorry about that.
memcpy(vlumps[i].data, wadData + (fileinfo + i)->filepos, vlumps[i].size);
}
Z_Free(wadData);
}
else
{
// Count number of lumps until the end of resource OR up until next "MAPXX" lump.
lumpnum_t lumppos = lumpnum + 1;
for (i = LUMPNUM(lumppos); i < wadfiles[WADFILENUM(lumpnum)]->numlumps; i++, lumppos++, numlumps++)
if (memcmp(W_CheckNameForNum(lumppos), "MAP", 3) == 0)
break;
numlumps++;
vlumps = Z_Malloc(sizeof(virtlump_t)*numlumps, PU_LEVEL, NULL);
for (i = 0; i < numlumps; i++, lumpnum++)
{
vlumps[i].size = W_LumpLength(lumpnum);
memcpy(vlumps[i].name, W_CheckNameForNum(lumpnum), 8);
vlumps[i].name[8] = '\0';
vlumps[i].data = W_CacheLumpNum(lumpnum, PU_LEVEL);
}
}
vres = Z_Malloc(sizeof(virtres_t), PU_LEVEL, NULL);
vres->vlumps = vlumps;
vres->numlumps = numlumps;
return vres;
}
/** \brief Frees zone memory for a given virtual resource.
*
* \param Virtual resource
*/
void vres_Free(virtres_t* vres)
{
while (vres->numlumps--)
Z_Free(vres->vlumps[vres->numlumps].data);
Z_Free(vres->vlumps);
Z_Free(vres);
}
/** (Debug) Prints lumps from a virtual resource into console.
*/
/*
static void vres_Diag(const virtres_t* vres)
{
UINT32 i;
for (i = 0; i < vres->numlumps; i++)
CONS_Printf("%s\n", vres->vlumps[i].name);
}
*/
/** \brief Finds a lump in a given virtual resource.
*
* \param Virtual resource
* \param Lump name to look for
* \return Virtual lump if found, NULL otherwise
*
*/
virtlump_t* vres_Find(const virtres_t* vres, const char* name)
{
UINT32 i;
for (i = 0; i < vres->numlumps; i++)
if (fastcmp(name, vres->vlumps[i].name))
return &vres->vlumps[i];
return NULL;
}
......@@ -72,6 +72,25 @@ typedef struct
compmethod compression; // lump compression method
} lumpinfo_t;
// =========================================================================
// 'VIRTUAL' RESOURCES
// =========================================================================
typedef struct {
char name[9];
UINT8* data;
size_t size;
} virtlump_t;
typedef struct {
size_t numlumps;
virtlump_t* vlumps;
} virtres_t;
virtres_t* vres_GetMap(lumpnum_t);
void vres_Free(virtres_t*);
virtlump_t* vres_Find(const virtres_t*, const char*);
// =========================================================================
// DYNAMIC WAD LOADING
// =========================================================================
......