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
  • 21-installer-nodd
  • 64-gl-log
  • DJGPP
  • FALLTHRU
  • appveyor
  • blend-locking
  • boost-tickrate
  • changeskin_hook
  • cleanup-opengl
  • clear-sign-sprite
  • crawlacommander-sprites
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • disable-titlemap-in-netgames
  • discord
  • discord_next
  • dynres
  • exchndl-xp-fix
  • file-param-error
  • fix-major-issue
  • fix-mouse-grabbing
  • fix-node-player-mixups
  • fix-nonslope-slopes
  • flipfuncpointers
  • fof-lightlist-fixes
  • g_findmap-lua
  • gamepad_experiments
  • grr-lj
  • ignore-glsegs
  • input-display
  • input-display-translucency
  • io
  • joystick-juggling-maz
  • keycodes
  • keycodes-only
  • keysyms
  • keywords-back-again
  • larger-chat
  • ld413-mp-fix
  • libpng-version-support
  • lower-unpegged-fix
  • makefile-tinkering
  • map-components-signedness-fixes
  • master
  • masterserver-fd-fix
  • models-mkii
  • more-cleanup
  • more-lua-map-names
  • mserv-is-dumb-and-what-else-is-new
  • musicdef
  • next
  • parser-fixes
  • pictureformats
  • pictureformats-depth
  • pictureformats-software
  • prescott-march
  • public_flatsprite
  • public_hexang
  • reduced_palette
  • refactor-kicks
  • snac-bruh
  • software-clownery-mkii
  • spawn_z_refactor
  • spawnmapthing-refactor
  • thokker
  • thokker_next
  • thokker_rebase
  • timedemo-revise
  • timer_sdl2
  • toast_fixes
  • tokentweaks
  • travis-deployer
  • udmf
  • udmf-base
  • udmf-next
  • udmf-specials
  • ungrab-mouse-in-menus
  • vanilla-hotplug
  • vanilla-hotplug-stableid
  • virtres
  • word
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • td-release-v1.0.0
110 results

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
  • 21-installer-nodd
  • 64-gl-log
  • DJGPP
  • FALLTHRU
  • appveyor
  • blend-locking
  • boost-tickrate
  • changeskin_hook
  • cleanup-opengl
  • clear-sign-sprite
  • crawlacommander-sprites
  • cutscene-cleanup
  • dd-music-bypass
  • dd-music-fix
  • disable-titlemap-in-netgames
  • discord
  • discord_next
  • dynres
  • exchndl-xp-fix
  • file-param-error
  • fix-major-issue
  • fix-mouse-grabbing
  • fix-node-player-mixups
  • fix-nonslope-slopes
  • flipfuncpointers
  • fof-lightlist-fixes
  • g_findmap-lua
  • gamepad_experiments
  • grr-lj
  • ignore-glsegs
  • input-display
  • input-display-translucency
  • io
  • joystick-juggling-maz
  • keycodes
  • keycodes-only
  • keysyms
  • keywords-back-again
  • larger-chat
  • ld413-mp-fix
  • libpng-version-support
  • lower-unpegged-fix
  • makefile-tinkering
  • map-components-signedness-fixes
  • master
  • masterserver-fd-fix
  • models-mkii
  • more-cleanup
  • more-lua-map-names
  • mserv-is-dumb-and-what-else-is-new
  • musicdef
  • next
  • parser-fixes
  • pictureformats
  • pictureformats-depth
  • pictureformats-software
  • prescott-march
  • public_flatsprite
  • public_hexang
  • reduced_palette
  • refactor-kicks
  • snac-bruh
  • software-clownery-mkii
  • spawn_z_refactor
  • spawnmapthing-refactor
  • thokker
  • thokker_next
  • thokker_rebase
  • timedemo-revise
  • timer_sdl2
  • toast_fixes
  • tokentweaks
  • travis-deployer
  • udmf
  • udmf-base
  • udmf-next
  • udmf-specials
  • ungrab-mouse-in-menus
  • vanilla-hotplug
  • vanilla-hotplug-stableid
  • virtres
  • word
  • SRB2_release_2.1
  • SRB2_release_2.1.1
  • SRB2_release_2.1.10
  • SRB2_release_2.1.11
  • SRB2_release_2.1.12
  • SRB2_release_2.1.14
  • SRB2_release_2.1.15
  • SRB2_release_2.1.16
  • SRB2_release_2.1.16a
  • SRB2_release_2.1.17
  • SRB2_release_2.1.18
  • SRB2_release_2.1.19
  • SRB2_release_2.1.2
  • SRB2_release_2.1.20
  • SRB2_release_2.1.21
  • SRB2_release_2.1.22
  • SRB2_release_2.1.23
  • SRB2_release_2.1.24
  • SRB2_release_2.1.25
  • SRB2_release_2.1.3
  • SRB2_release_2.1.4
  • SRB2_release_2.1.5
  • SRB2_release_2.1.6
  • SRB2_release_2.1.7
  • SRB2_release_2.1.8
  • SRB2_release_2.1.9
  • SRB2_release_2.2.0
  • td-release-v1.0.0
110 results
Show changes
Commits on Source (70)
...@@ -10479,12 +10479,84 @@ static inline int lib_getenum(lua_State *L) ...@@ -10479,12 +10479,84 @@ static inline int lib_getenum(lua_State *L)
} else if (fastcmp(word,"paused")) { } else if (fastcmp(word,"paused")) {
lua_pushboolean(L, paused); lua_pushboolean(L, paused);
return 1; 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")) { } else if (fastcmp(word,"titlemap")) {
lua_pushinteger(L, titlemap); lua_pushinteger(L, titlemap);
return 1; return 1;
} else if (fastcmp(word,"titlemapinaction")) { } else if (fastcmp(word,"titlemapinaction")) {
lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF)); lua_pushboolean(L, (titlemapinaction != TITLEMAP_OFF));
return 1; 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")) { } else if (fastcmp(word,"gametype")) {
lua_pushinteger(L, gametype); lua_pushinteger(L, gametype);
return 1; return 1;
......
...@@ -2664,23 +2664,17 @@ static int lib_gSetCustomExitVars(lua_State *L) ...@@ -2664,23 +2664,17 @@ static int lib_gSetCustomExitVars(lua_State *L)
// Supported: // Supported:
// G_SetCustomExitVars(); [reset to defaults] // G_SetCustomExitVars(); [reset to defaults]
// G_SetCustomExitVars(int) [nextmap override only] // G_SetCustomExitVars(int) [nextmap override only]
// G_SetCustomExitVars(bool) [skipstats only] // G_SetCustomExitVars(nil, int) [skipstats only]
// G_SetCustomExitVars(int, bool) [both of the above] // G_SetCustomExitVars(int, int) [both of the above]
nextmapoverride = 0;
skipstats = 0;
if (n >= 1) if (n >= 1)
{ {
if (lua_isnumber(L, 1) || n >= 2) nextmapoverride = (INT16)luaL_optinteger(L, 1, 0);
{ skipstats = (INT16)luaL_optinteger(L, 2, 0);
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;
} }
// ---
return 0; return 0;
} }
......
...@@ -21,6 +21,7 @@ enum hud { ...@@ -21,6 +21,7 @@ enum hud {
// Match / CTF / Tag / Ringslinger // Match / CTF / Tag / Ringslinger
hud_weaponrings, hud_weaponrings,
hud_powerstones, hud_powerstones,
hud_teamscores,
// NiGHTS mode // NiGHTS mode
hud_nightslink, hud_nightslink,
hud_nightsdrill, hud_nightsdrill,
......
...@@ -48,6 +48,7 @@ static const char *const hud_disable_options[] = { ...@@ -48,6 +48,7 @@ static const char *const hud_disable_options[] = {
"weaponrings", "weaponrings",
"powerstones", "powerstones",
"teamscores",
"nightslink", "nightslink",
"nightsdrill", "nightsdrill",
......
...@@ -445,7 +445,7 @@ static int sectorlines_get(lua_State *L) ...@@ -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 // 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 // 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 // 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 /* OLD HACK
// check first linedef to figure which of its sectors owns this sector->lines pointer // 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) ...@@ -479,7 +479,7 @@ static int sectorlines_num(lua_State *L)
return luaL_error(L, "accessed sector_t.lines doesn't exist anymore."); return luaL_error(L, "accessed sector_t.lines doesn't exist anymore.");
// see comments in the _get function above // 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); lua_pushinteger(L, numoflines);
return 1; return 1;
} }
......
...@@ -1106,7 +1106,7 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c ...@@ -1106,7 +1106,7 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
#else #else
fixed_t cheight = sec->ceilingheight; fixed_t cheight = sec->ceilingheight;
#endif #endif
mt->options = (UINT16)((cheight - player->mo->z - player->mo->height)>>FRACBITS); mt->z = (UINT16)((cheight - player->mo->z - player->mo->height)>>FRACBITS);
} }
else else
{ {
...@@ -1115,12 +1115,11 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c ...@@ -1115,12 +1115,11 @@ static mapthing_t *OP_CreateNewMapThing(player_t *player, UINT16 type, boolean c
#else #else
fixed_t fheight = sec->floorheight; fixed_t fheight = sec->floorheight;
#endif #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->angle = (INT16)(FixedInt(AngleFixed(player->mo->angle)));
mt->options |= (UINT16)cv_opflags.value; mt->options = (mt->z << ZSHIFT) | (UINT16)cv_opflags.value;
return mt; return mt;
} }
......
...@@ -13614,12 +13614,12 @@ static boolean PIT_DustDevilLaunch(mobj_t *thing) ...@@ -13614,12 +13614,12 @@ static boolean PIT_DustDevilLaunch(mobj_t *thing)
} }
else else
{ //Player on the top of the tornado. { //Player on the top of the tornado.
P_ResetPlayer(player);
thing->z = dustdevil->z + dustdevil->height; thing->z = dustdevil->z + dustdevil->height;
thrust = 20 * FRACUNIT; thrust = 20 * FRACUNIT;
player->powers[pw_nocontrol] = 0; player->powers[pw_nocontrol] = 0;
S_StartSound(thing, sfx_wdjump); S_StartSound(thing, sfx_wdjump);
P_SetPlayerMobjState(thing, S_PLAY_FALL); P_SetPlayerMobjState(thing, S_PLAY_FALL);
player->pflags &= ~PF_JUMPED;
} }
thing->momz = thrust; thing->momz = thrust;
...@@ -14712,20 +14712,35 @@ void A_DragonWing(mobj_t *actor) ...@@ -14712,20 +14712,35 @@ void A_DragonWing(mobj_t *actor)
void A_DragonSegment(mobj_t *actor) void A_DragonSegment(mobj_t *actor)
{ {
mobj_t *target = actor->target; 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 dist;
fixed_t radius = actor->radius + target->radius; fixed_t radius;
angle_t hangle = R_PointToAngle2(target->x, target->y, actor->x, actor->y); angle_t hangle;
angle_t zangle = R_PointToAngle2(0, target->z, dist, actor->z); angle_t zangle;
fixed_t hdist = P_ReturnThrustX(target, zangle, radius); fixed_t hdist;
fixed_t xdist = P_ReturnThrustX(target, hangle, hdist); fixed_t xdist;
fixed_t ydist = P_ReturnThrustY(target, hangle, hdist); fixed_t ydist;
fixed_t zdist = P_ReturnThrustY(target, zangle, radius); fixed_t zdist;
#ifdef HAVE_BLUA #ifdef HAVE_BLUA
if (LUA_CallAction("A_DragonSegment", actor)) if (LUA_CallAction("A_DragonSegment", actor))
return; return;
#endif #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; actor->angle = hangle;
P_TeleportMove(actor, target->x + xdist, target->y + ydist, target->z + zdist); P_TeleportMove(actor, target->x + xdist, target->y + ydist, target->z + zdist);
} }
...@@ -7833,7 +7833,8 @@ void P_MobjThinker(mobj_t *mobj) ...@@ -7833,7 +7833,8 @@ void P_MobjThinker(mobj_t *mobj)
boolean dojump = false, targonground, love, makeheart = false; boolean dojump = false, targonground, love, makeheart = false;
if (mobj->target != player->mo) if (mobj->target != player->mo)
P_SetTarget(&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); love = (player->skin == 0 || player->skin == 5);
switch (stat) switch (stat)
...@@ -11120,6 +11121,19 @@ void P_PrecipitationEffects(void) ...@@ -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 // P_RespawnSpecials
// //
...@@ -11158,17 +11172,12 @@ void P_RespawnSpecials(void) ...@@ -11158,17 +11172,12 @@ void P_RespawnSpecials(void)
if (mthing) if (mthing)
{ {
mobjtype_t i; mobjtype_t i = P_GetMobjtype(mthing->type);
x = mthing->x << FRACBITS; x = mthing->x << FRACBITS;
y = mthing->y << FRACBITS; y = mthing->y << FRACBITS;
ss = R_PointInSubsector(x, y); ss = R_PointInSubsector(x, y);
// find which type to spawn if (i == MT_UNKNOWN) // prevent creation of objects with this type -- Monster Iestyn 17/12/17
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
{ {
// 3D Mode start Thing is unlikely to be added to the que, // 3D Mode start Thing is unlikely to be added to the que,
// so don't bother checking for that specific type // so don't bother checking for that specific type
...@@ -11550,43 +11559,109 @@ void P_MovePlayerToStarpost(INT32 playernum) ...@@ -11550,43 +11559,109 @@ void P_MovePlayerToStarpost(INT32 playernum)
mapthing_t *huntemeralds[MAXHUNTEMERALDS]; mapthing_t *huntemeralds[MAXHUNTEMERALDS];
INT32 numhuntemeralds; 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) static fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const mapthing_t* mthing, const fixed_t x, const fixed_t y)
return; // Ignore type-0 things as NOPs {
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. switch (mobjtype)
// Skip all returning code.
if (objectplacing)
{ {
// find which type to spawn // Bumpers never spawn flipped.
for (i = 0; i < NUMMOBJTYPES; i++) case MT_NIGHTSBUMPER:
if (mthing->type == mobjinfo[i].doomednum) flip = false;
break; break;
if (i == NUMMOBJTYPES) // Axis objects snap to the floor.
{ case MT_AXIS:
if (mthing->type == 3328) // 3D Mode start Thing case MT_AXISTRANSFER:
return; case MT_AXISTRANSFERLINE:
CONS_Alert(CONS_WARNING, M_GetText("Unknown thing type %d placed at (%d, %d)\n"), mthing->type, mthing->x, mthing->y); return ONFLOORZ;
i = MT_UNKNOWN;
} // Objects with a non-zero default height.
goto noreturns; 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 (!offset) // Snap to the surfaces when there's no offset set.
if (mthing->type == 33) {
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) if (numdmstarts < MAX_DM_STARTS)
{ {
...@@ -11594,10 +11669,9 @@ void P_SpawnMapThing(mapthing_t *mthing) ...@@ -11594,10 +11669,9 @@ void P_SpawnMapThing(mapthing_t *mthing)
mthing->type = 0; mthing->type = 0;
numdmstarts++; numdmstarts++;
} }
return; return true;
} }
else if (mthing->type == 34) // Red CTF starts
else if (mthing->type == 34) // Red CTF Starts
{ {
if (numredctfstarts < MAXPLAYERS) if (numredctfstarts < MAXPLAYERS)
{ {
...@@ -11605,10 +11679,9 @@ void P_SpawnMapThing(mapthing_t *mthing) ...@@ -11605,10 +11679,9 @@ void P_SpawnMapThing(mapthing_t *mthing)
mthing->type = 0; mthing->type = 0;
numredctfstarts++; numredctfstarts++;
} }
return; return true;
} }
else if (mthing->type == 35) // Blue CTF starts
else if (mthing->type == 35) // Blue CTF Starts
{ {
if (numbluectfstarts < MAXPLAYERS) if (numbluectfstarts < MAXPLAYERS)
{ {
...@@ -11616,106 +11689,154 @@ void P_SpawnMapThing(mapthing_t *mthing) ...@@ -11616,106 +11689,154 @@ void P_SpawnMapThing(mapthing_t *mthing)
mthing->type = 0; mthing->type = 0;
numbluectfstarts++; numbluectfstarts++;
} }
return; return true;
}
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;
} }
else if (metalrecording && mthing->type == mobjinfo[MT_METALSONIC_RACE].doomednum)
if (metalrecording && mthing->type == mobjinfo[MT_METALSONIC_RACE].doomednum)
{ // If recording, you ARE Metal Sonic. Do not spawn it, do not save normal spawnpoints. { // If recording, you ARE Metal Sonic. Do not spawn it, do not save normal spawnpoints.
playerstarts[0] = mthing; playerstarts[0] = mthing;
return; return true;
}
// 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;
} }
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. return false;
if (mobjinfo[i].flags & (MF_ENEMY|MF_BOSS) || i == MT_TOKEN || i == MT_STARPOST) }
return;
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 if (gametype != GT_COOP) // Don't place emeralds in non-coop modes
return; return false;
if (metalrecording) 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! 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. // Emerald Hunt is Coop only.
if (gametype != GT_COOP) if (gametype != GT_COOP)
return; return false;
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));
if (numhuntemeralds < MAXHUNTEMERALDS) if (numhuntemeralds < MAXHUNTEMERALDS)
huntemeralds[numhuntemeralds++] = mthing; huntemeralds[numhuntemeralds++] = mthing;
return; return false;
} case MT_EMERALDSPAWN:
if (i == MT_EMERALDSPAWN)
{
if (!cv_powerstones.value) if (!cv_powerstones.value)
return; return false;
if (!(gametype == GT_MATCH || gametype == GT_CTF)) if (!(gametype == GT_MATCH || gametype == GT_CTF))
return; return false;
runemeraldmanager = true; 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)) 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 (!G_RingSlingerGametype() || !cv_specialrings.value)
if (P_WeaponOrPanel(i)) 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 // Altering monitor spawns via cvars
// If MF_GRENADEBOUNCE is set in the monitor's info, // If MF_GRENADEBOUNCE is set in the monitor's info,
// skip this step. (Used for gold monitors) // skip this step. (Used for gold monitors)
...@@ -11725,267 +11846,676 @@ You should think about modifying the deathmatch starts to take full advantage of ...@@ -11725,267 +11846,676 @@ You should think about modifying the deathmatch starts to take full advantage of
if (gametype == GT_COMPETITION || gametype == GT_RACE) if (gametype == GT_COMPETITION || gametype == GT_RACE)
{ {
// Set powerup boxes to user settings for competition. // Set powerup boxes to user settings for competition.
if (cv_competitionboxes.value == 1) // Mystery switch (cv_competitionboxes.value)
i = MT_MYSTERY_BOX; {
else if (cv_competitionboxes.value == 2) // Teleport case 1: // Mystery
i = MT_MIXUP_BOX; return MT_MYSTERY_BOX;
else if (cv_competitionboxes.value == 3) // None case 2: // Teleport
return; // Don't spawn! return MT_MIXUP_BOX;
// default case: normal case 3: // None
return MT_NULL; // Don't spawn!
default:
return i;
}
} }
// Set powerup boxes to user settings for other netplay modes // Set powerup boxes to user settings for other netplay modes
else if (gametype != GT_COOP) else if (gametype != GT_COOP)
{ {
if (cv_matchboxes.value == 1) // Mystery switch (cv_matchboxes.value)
i = MT_MYSTERY_BOX;
else if (cv_matchboxes.value == 2) // Unchanging
{ {
case 1: // Mystery
return MT_MYSTERY_BOX;
case 2: // Unchanging
if (i == MT_MYSTERY_BOX) if (i == MT_MYSTERY_BOX)
return; // don't spawn return MT_NULL; // don't spawn
mthing->options &= ~(MTF_AMBUSH|MTF_OBJECTSPECIAL); // no random respawning! 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 (gametype != GT_CTF && (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX))
{ return MT_RING_BOX;
if (i == MT_RING_BLUEBOX || i == MT_RING_REDBOX)
i = MT_RING_BOX; if (modeattacking && i == MT_1UP_BOX) // 1UPs -->> Score TVs
else if (i == MT_BLUEFLAG || i == MT_REDFLAG)
return; // No flags in non-CTF modes!
}
else
{ {
if ((i == MT_BLUEFLAG && blueflag) || (i == MT_REDFLAG && redflag)) // Either or, doesn't matter which.
{ if (mthing->options & (MTF_AMBUSH | MTF_OBJECTSPECIAL))
CONS_Alert(CONS_ERROR, M_GetText("Only one flag per team allowed in CTF!\n")); return MT_SCORE10K_BOX; // 10,000
return; else
} return MT_SCORE1K_BOX; // 1,000
} }
if (!G_PlatformGametype() && (i == MT_SIGN || i == MT_STARPOST)) if (mariomode && i == MT_ROSY)
return; // Don't spawn exit signs or starposts in wrong game modes return MT_TOAD; // don't remove on penalty of death
if (modeattacking) // Record Attack special stuff return i;
{ }
// Don't spawn starposts that wouldn't be usable
if (i == MT_STARPOST)
return;
// 1UPs -->> Score TVs static boolean P_SetupEmblem(mapthing_t *mthing, mobj_t *mobj)
else if (i == MT_1UP_BOX) // 1UP {
{ INT32 j;
// Either or, doesn't matter which. emblem_t* emblem = M_GetLevelEmblems(gamemap);
if (mthing->options & (MTF_AMBUSH|MTF_OBJECTSPECIAL)) skincolors_t emcolor;
i = MT_SCORE10K_BOX; // 10,000
else
i = MT_SCORE1K_BOX; // 1,000
}
}
if (ultimatemode) while (emblem)
{ {
if (i == MT_PITY_BOX || i == MT_ELEMENTAL_BOX || i == MT_ATTRACT_BOX if ((emblem->type == ET_GLOBAL || emblem->type == ET_SKIN) && emblem->tag == mthing->angle)
|| i == MT_FORCE_BOX || i == MT_ARMAGEDDON_BOX || i == MT_WHIRLWIND_BOX break;
|| 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
// Don't include the gold repeating boxes here please. emblem = M_GetLevelEmblems(-1);
// They're likely facets of the level's design and therefore required to progress.
} }
if (i == MT_ROSY) if (!emblem)
{ {
if (!(gametype == GT_COOP || (mthing->options & MTF_EXTRA))) CONS_Debug(DBG_GAMELOGIC, "No map emblem for map %d with tag %d found!\n", gamemap, mthing->angle);
return; // she doesn't hang out here return false;
else if (mariomode)
i = MT_TOAD; // don't remove on penalty of death
else if (!(netgame || multiplayer) && players[consoleplayer].skin == 3)
return; // no doubles
} }
if (i == MT_TOKEN && ((gametype != GT_COOP && gametype != GT_COMPETITION) || tokenbits == 30 || tokenlist & (1 << tokenbits++))) j = emblem - emblemlocations;
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;
// Objectplace landing point I_Assert(emblemlocations[j].sprite >= 'A' && emblemlocations[j].sprite <= 'Z');
noreturns: P_SetMobjState(mobj, mobj->info->spawnstate + (emblemlocations[j].sprite - 'A'));
// spawn it mobj->health = j + 1;
x = mthing->x << FRACBITS; emcolor = M_GetEmblemColor(&emblemlocations[j]); // workaround for compiler complaint about bad function casting
y = mthing->y << FRACBITS; mobj->color = (UINT8)emcolor;
ss = R_PointInSubsector(x, y);
if (i == MT_NIGHTSBUMPER) if (emblemlocations[j].collected
z = ( || (emblemlocations[j].type == ET_SKIN && emblemlocations[j].var != players[0].skin))
#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 (mthing->options & MTF_OBJECTFLIP) P_UnsetThingPosition(mobj);
{ mobj->flags |= MF_NOCLIP;
z = ( mobj->flags &= ~MF_SPECIAL;
#ifdef ESLOPE mobj->flags |= MF_NOBLOCKMAP;
ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) : mobj->frame |= (tr_trans50 << FF_TRANSSHIFT);
#endif P_SetThingPosition(mobj);
ss->sector->ceilingheight); }
else
if (mthing->options & MTF_AMBUSH) // Special flag for rings {
z -= 24*FRACUNIT; mobj->frame &= ~FF_TRANSMASK;
if (mthing->options >> ZSHIFT)
z -= (mthing->options >> ZSHIFT)*FRACUNIT;
z -= mobjinfo[i].height; //Don't forget the height! if (emblemlocations[j].type == ET_GLOBAL)
}
else
{ {
z = ( mobj->reactiontime = emblemlocations[j].var;
#ifdef ESLOPE if (emblemlocations[j].var & GE_NIGHTSITEM)
ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : {
#endif mobj->flags |= MF_NIGHTSITEM;
ss->sector->floorheight); mobj->flags &= ~MF_SPECIAL;
mobj->flags2 |= MF2_DONTDRAW;
if (mthing->options & MTF_AMBUSH) // Special flag for rings }
z += 24*FRACUNIT;
if (mthing->options >> ZSHIFT)
z += (mthing->options >> ZSHIFT)*FRACUNIT;
} }
}
return true;
}
if (z == ONFLOORZ) static boolean P_SetupMace(mapthing_t *mthing, mobj_t *mobj, boolean *doangle)
mthing->z = 0; {
else fixed_t mlength, mmaxlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor, widthfactor;
mthing->z = (INT16)(z>>FRACBITS); 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 else
{ mpinch = mroll = mnumnospokes = mwidth = 0;
fixed_t offset = 0;
boolean flip = (!!(mobjinfo[i].flags & MF_SPAWNCEILING) ^ !!(mthing->options & MTF_OBJECTFLIP)); CONS_Debug(DBG_GAMELOGIC, "Mace/Chain (mapthing #%s):\n"
"Length is %d (minus %d)\n"
// base positions "Speed is %d\n"
if (flip) "Phase is %d\n"
z = ( "Yaw is %d\n"
#ifdef ESLOPE "Pitch is %d\n"
ss->sector->c_slope ? P_GetZAt(ss->sector->c_slope, x, y) : "No. of spokes is %d (%d antispokes)\n"
#endif "Pinch is %d\n"
ss->sector->ceilingheight) - mobjinfo[i].height; "Roll is %d\n"
else "Width is %d\n",
z = ( sizeu1(mthingi), mlength, mminlength, mspeed, mphase, myaw, mpitch, mnumspokes, mnumnospokes, mpinch, mroll, mwidth);
#ifdef ESLOPE
ss->sector->f_slope ? P_GetZAt(ss->sector->f_slope, x, y) : if (mnumnospokes > 0 && (mnumnospokes < mnumspokes))
#endif mnumnospokes = mnumspokes/mnumnospokes;
ss->sector->floorheight); else
mnumnospokes = ((mobj->type == MT_CHAINMACEPOINT) ? (mnumspokes) : 0);
// offsetting mobj->lastlook = mspeed;
if (mthing->options >> ZSHIFT) mobj->movecount = mobj->lastlook;
offset = ((mthing->options >> ZSHIFT) << FRACBITS); mobj->angle = FixedAngle(myaw << FRACBITS);
else if (i == MT_CRAWLACOMMANDER || i == MT_DETON || i == MT_JETTBOMBER || i == MT_JETTGUNNER || i == MT_EGGMOBILE2) *doangle = false;
offset = 33*FRACUNIT; mobj->threshold = (FixedAngle(mpitch << FRACBITS) >> ANGLETOFINESHIFT);
else if (i == MT_EGGMOBILE) mobj->movefactor = mpinch;
offset = 128*FRACUNIT; mobj->movedir = 0;
else if (i == MT_GOLDBUZZ || i == MT_REDBUZZ)
offset = 288*FRACUNIT;
// applying offsets! (if any) // Mobjtype selection
if (flip) 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) macetype = MT_BIGGRABCHAIN;
z -= offset; chainlink = MT_BIGMACECHAIN;
else
z = ONCEILINGZ;
} }
else else
{ {
if (offset) macetype = MT_SMALLGRABCHAIN;
z += offset; chainlink = MT_SMALLMACECHAIN;
else }
z = ONFLOORZ; mchainlike = true;
break;
default:
if (mthing->options & MTF_AMBUSH)
{
macetype = MT_BIGMACE;
chainlink = MT_BIGMACECHAIN;
} }
if (z == ONFLOORZ)
mthing->z = 0;
else else
mthing->z = (INT16)(z>>FRACBITS); {
macetype = MT_SMALLMACE;
chainlink = MT_SMALLMACECHAIN;
}
break;
} }
mobj = P_SpawnMobj(x, y, z, i); if (!macetype && !chainlink)
mobj->spawnpoint = mthing; return true;
#ifdef HAVE_BLUA if (mobj->type == MT_CHAINPOINT)
if (LUAh_MapThingSpawn(mobj, mthing))
{ {
if (P_MobjWasRemoved(mobj)) if (!mlength)
return; return true;
} }
else if (P_MobjWasRemoved(mobj))
return;
else else
#endif mlength++;
switch(mobj->type)
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; // Offsets
emblem_t *emblem = M_GetLevelEmblems(gamemap); if (lines[line].flags & ML_EFFECT1) // Swinging
skincolors_t emcolor; 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) if (mobj->type != MT_CHAINMACEPOINT)
break; continue;
emblem = M_GetLevelEmblems(-1); linktype = chainlink;
firsttype = ((mthing->options & MTF_AMBUSH) ? MT_BIGGRABCHAIN : MT_SMALLGRABCHAIN);
mmaxlength = 1 + (mlength - 1) * radiusfactor;
radiusfactor = widthfactor = 1;
} }
else
if (!emblem)
{ {
CONS_Debug(DBG_GAMELOGIC, "No map emblem for map %d with tag %d found!\n", gamemap, mthing->angle); if (mobj->type == MT_CHAINMACEPOINT)
break; {
// 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'); // Out from the center...
P_SetMobjState(mobj, mobj->info->spawnstate + (emblemlocations[j].sprite - 'A')); if (linktype)
{
while ((++mlengthset) < mmaxlength)
makemace(linktype, radiusfactor*mlengthset, 0);
}
else
mlengthset = mmaxlength;
mobj->health = j + 1; // Outermost mace/link
emcolor = M_GetEmblemColor(&emblemlocations[j]); // workaround for compiler complaint about bad function casting if (firsttype)
mobj->color = (UINT8)emcolor; makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH);
if (emblemlocations[j].collected if (!mwidth)
|| (emblemlocations[j].type == ET_SKIN && emblemlocations[j].var != players[0].skin))
{ {
P_UnsetThingPosition(mobj); if (mdosound && mnumspokes <= mmin) // Can it make a sound?
mobj->flags |= MF_NOCLIP; spawnee->flags2 |= MF2_BOSSNOTRAP;
mobj->flags &= ~MF_SPECIAL;
mobj->flags |= MF_NOBLOCKMAP;
mobj->frame |= (tr_trans50 << FF_TRANSSHIFT);
P_SetThingPosition(mobj);
} }
else else
{ {
mobj->frame &= ~FF_TRANSMASK; // Across the bar!
if (!firsttype)
if (emblemlocations[j].type == ET_GLOBAL) mwidthset = -mwidth;
else if (mwidth > 0)
{ {
mobj->reactiontime = emblemlocations[j].var; while ((mwidthset -= widthfactor) > -mwidth)
if (emblemlocations[j].var & GE_NIGHTSITEM)
{ {
mobj->flags |= MF_NIGHTSITEM; makemace(firsttype, radiusfactor*mlengthset, MF2_AMBUSH);
mobj->flags &= ~MF_SPECIAL; if (mdosound && (mwidthset == msound) && mnumspokes <= mmin) // Can it make a sound?
mobj->flags2 |= MF2_DONTDRAW; 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; break;
} }
case MT_SKYBOX: case MT_SKYBOX:
...@@ -12019,7 +12549,7 @@ You should think about modifying the deathmatch starts to take full advantage of ...@@ -12019,7 +12549,7 @@ You should think about modifying the deathmatch starts to take full advantage of
if (mthing->angle) if (mthing->angle)
mobj->health = mthing->angle; mobj->health = mthing->angle;
else 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; break;
case MT_METALSONIC_RACE: case MT_METALSONIC_RACE:
case MT_METALSONIC_BATTLE: case MT_METALSONIC_BATTLE:
...@@ -12034,7 +12564,7 @@ You should think about modifying the deathmatch starts to take full advantage of ...@@ -12034,7 +12564,7 @@ You should think about modifying the deathmatch starts to take full advantage of
break; break;
case MT_BALLOON: case MT_BALLOON:
if (mthing->angle > 0) if (mthing->angle > 0)
mobj->color = ((mthing->angle-1) % (MAXSKINCOLORS-1))+1; mobj->color = ((mthing->angle - 1) % (MAXSKINCOLORS - 1)) + 1;
break; break;
#define makesoftwarecorona(mo, h) \ #define makesoftwarecorona(mo, h) \
corona = P_SpawnMobjFromMobj(mo, 0, 0, h<<FRACBITS, MT_PARTICLE);\ 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 ...@@ -12085,10 +12615,7 @@ You should think about modifying the deathmatch starts to take full advantage of
} }
break; break;
case MT_WATERDRIP: case MT_WATERDRIP:
if (mthing->angle) mobj->tics = 3*TICRATE + mthing->angle;
mobj->tics = 3*TICRATE + mthing->angle;
else
mobj->tics = 3*TICRATE;
break; break;
case MT_FLAMEJET: case MT_FLAMEJET:
case MT_VERTICALFLAMEJET: case MT_VERTICALFLAMEJET:
...@@ -12106,410 +12633,32 @@ You should think about modifying the deathmatch starts to take full advantage of ...@@ -12106,410 +12633,32 @@ You should think about modifying the deathmatch starts to take full advantage of
case MT_CHAINPOINT: case MT_CHAINPOINT:
case MT_FIREBARPOINT: case MT_FIREBARPOINT:
case MT_CUSTOMMACEPOINT: case MT_CUSTOMMACEPOINT:
{ if (!P_SetupMace(mthing, mobj, doangle))
fixed_t mlength, mmaxlength, mlengthset, mspeed, mphase, myaw, mpitch, mminlength, mnumspokes, mpinch, mroll, mnumnospokes, mwidth, mwidthset, mmin, msound, radiusfactor, widthfactor; return false;
angle_t mspokeangle; break;
mobjtype_t chainlink, macetype, firsttype, linktype; case MT_PARTICLEGEN:
boolean mdosound, mdocenter, mchainlike = false; if (!P_SetupParticleGen(mthing, mobj))
mobj_t *spawnee = NULL, *hprev = mobj; return false;
mobjflag_t mflagsapply; break;
mobjflag2_t mflags2apply; case MT_ROCKSPAWNER:
mobjeflag_t meflagsapply; mobj->threshold = mthing->angle;
INT32 line; mobj->movecount = mthing->extrainfo;
const size_t mthingi = (size_t)(mthing - mapthings); break;
case MT_POPUPTURRET:
// Find the corresponding linedef special, using angle as tag if (mthing->angle)
// P_FindSpecialLineFromTag works here now =D mobj->threshold = mthing->angle;
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;
else else
mnumnospokes = ((mobj->type == MT_CHAINMACEPOINT) ? (mnumspokes) : 0); mobj->threshold = (TICRATE*2)-1;
break;
mobj->lastlook = mspeed; case MT_NIGHTSBUMPER:
mobj->movecount = mobj->lastlook; // Lower 4 bits specify the angle of
mobj->angle = FixedAngle(myaw*FRACUNIT); // the bumper in 30 degree increments.
doangle = false; mobj->threshold = (mthing->options & 15) % 12; // It loops over, etc
mobj->threshold = (FixedAngle(mpitch*FRACUNIT)>>ANGLETOFINESHIFT); P_SetMobjState(mobj, mobj->info->spawnstate + mobj->threshold);
mobj->movefactor = mpinch; break;
mobj->movedir = 0; case MT_EGGCAPSULE:
if (mthing->angle <= 0)
// Mobjtype selection mthing->angle = 20; // prevent 0 health
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->health = mthing->angle; mobj->health = mthing->angle;
mobj->threshold = min(mthing->extrainfo, 7); mobj->threshold = min(mthing->extrainfo, 7);
...@@ -12522,122 +12671,8 @@ ML_EFFECT5 : Don't stop thinking when too far away ...@@ -12522,122 +12671,8 @@ ML_EFFECT5 : Don't stop thinking when too far away
mobj->health = mthing->extrainfo; mobj->health = mthing->extrainfo;
break; break;
case MT_NIGHTSDRONE: case MT_NIGHTSDRONE:
{ if (!P_SetupNiGHTSDrone(mthing, mobj))
boolean flip = mthing->options & MTF_OBJECTFLIP; return false;
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);
}
}
break; break;
case MT_HIVEELEMENTAL: case MT_HIVEELEMENTAL:
if (mthing->extrainfo) if (mthing->extrainfo)
...@@ -12648,7 +12683,7 @@ ML_EFFECT5 : Don't stop thinking when too far away ...@@ -12648,7 +12683,7 @@ ML_EFFECT5 : Don't stop thinking when too far away
case MT_GLAREGOYLEDOWN: case MT_GLAREGOYLEDOWN:
case MT_GLAREGOYLELONG: case MT_GLAREGOYLELONG:
if (mthing->angle >= 360) if (mthing->angle >= 360)
mobj->tics += 7*(mthing->angle / 360) + 1; // starting delay mobj->tics += 7*(mthing->angle/360) + 1; // starting delay
break; break;
case MT_DSZSTALAGMITE: case MT_DSZSTALAGMITE:
case MT_DSZ2STALAGMITE: case MT_DSZ2STALAGMITE:
...@@ -12659,39 +12694,39 @@ ML_EFFECT5 : Don't stop thinking when too far away ...@@ -12659,39 +12694,39 @@ ML_EFFECT5 : Don't stop thinking when too far away
} }
break; break;
case MT_THZTREE: case MT_THZTREE:
{ // Spawn the branches { // Spawn the branches
angle_t mobjangle = FixedAngle((mthing->angle % 113)<<FRACBITS); angle_t mobjangle = FixedAngle((mthing->angle % 113) << FRACBITS);
P_SpawnMobjFromMobj(mobj, 1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_22h; P_SpawnMobjFromMobj(mobj, 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, 0, FRACUNIT, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_157h;
P_SpawnMobjFromMobj(mobj, -1*FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270; P_SpawnMobjFromMobj(mobj, -FRACUNIT, 0, 0, MT_THZTREEBRANCH)->angle = mobjangle + ANGLE_270;
} }
break; break;
case MT_CEZPOLE1: case MT_CEZPOLE1:
case MT_CEZPOLE2: case MT_CEZPOLE2:
{ // Spawn the banner { // Spawn the banner
angle_t mobjangle = FixedAngle(mthing->angle<<FRACBITS); angle_t mobjangle = FixedAngle(mthing->angle << FRACBITS);
P_SpawnMobjFromMobj(mobj, P_SpawnMobjFromMobj(mobj,
P_ReturnThrustX(mobj, mobjangle, 4<<FRACBITS), P_ReturnThrustX(mobj, mobjangle, 4 << FRACBITS),
P_ReturnThrustY(mobj, mobjangle, 4<<FRACBITS), P_ReturnThrustY(mobj, mobjangle, 4 << FRACBITS),
0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2))->angle = mobjangle + ANGLE_90; 0, ((mobj->type == MT_CEZPOLE1) ? MT_CEZBANNER1 : MT_CEZBANNER2))->angle = mobjangle + ANGLE_90;
} }
break; break;
case MT_HHZTREE_TOP: case MT_HHZTREE_TOP:
{ // Spawn the branches { // Spawn the branches
angle_t mobjangle = FixedAngle(mthing->angle<<FRACBITS) & (ANGLE_90-1); angle_t mobjangle = FixedAngle(mthing->angle << FRACBITS) & (ANGLE_90 - 1);
mobj_t *leaf; mobj_t* leaf;
#define doleaf(x, y) \ #define doleaf(x, y) \
leaf = P_SpawnMobjFromMobj(mobj, x, y, 0, MT_HHZTREE_PART);\ leaf = P_SpawnMobjFromMobj(mobj, x, y, 0, MT_HHZTREE_PART);\
leaf->angle = mobjangle;\ leaf->angle = mobjangle;\
P_SetMobjState(leaf, leaf->info->seestate);\ P_SetMobjState(leaf, leaf->info->seestate);\
mobjangle += ANGLE_90 mobjangle += ANGLE_90
doleaf(1*FRACUNIT, 0); doleaf(FRACUNIT, 0);
doleaf(0, 1*FRACUNIT); doleaf(0, FRACUNIT);
doleaf(-1*FRACUNIT, 0); doleaf(-FRACUNIT, 0);
doleaf(0, -1*FRACUNIT); doleaf(0, -FRACUNIT);
#undef doleaf #undef doleaf
} }
break; break;
case MT_SMASHINGSPIKEBALL: case MT_SMASHINGSPIKEBALL:
if (mthing->angle > 0) if (mthing->angle > 0)
mobj->tics += mthing->angle; mobj->tics += mthing->angle;
...@@ -12722,94 +12757,27 @@ ML_EFFECT5 : Don't stop thinking when too far away ...@@ -12722,94 +12757,27 @@ ML_EFFECT5 : Don't stop thinking when too far away
angle_t fa = (angle >> ANGLETOFINESHIFT) & FINEMASK; angle_t fa = (angle >> ANGLETOFINESHIFT) & FINEMASK;
fixed_t xoffs = FINECOSINE(fa); fixed_t xoffs = FINECOSINE(fa);
fixed_t yoffs = FINESINE(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; leaf->angle = angle;
angle += ANGLE_45; angle += ANGLE_45;
} }
break; break;
} }
case MT_REDBOOSTER: 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: case MT_YELLOWBOOSTER:
{ if (!P_SetupBooster(mthing, mobj, mobj->type == MT_REDBOOSTER))
angle_t angle = FixedAngle(mthing->angle << FRACBITS); return false;
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:
break; break;
} case MT_AXIS:
// Inverted if uppermost bit is set
if (mobj->flags & MF_BOSS) if (mthing->angle & 16384)
{ mobj->flags2 |= MF2_AMBUSH;
if (mthing->options & MTF_OBJECTSPECIAL) // No egg trap for this boss
mobj->flags2 |= MF2_BOSSNOTRAP;
}
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 // Mare it belongs to
mobj->threshold = min(mthing->extrainfo, 7); mobj->threshold = min(mthing->extrainfo, 7);
...@@ -12817,38 +12785,29 @@ ML_EFFECT5 : Don't stop thinking when too far away ...@@ -12817,38 +12785,29 @@ ML_EFFECT5 : Don't stop thinking when too far away
mobj->health = mthing->options; mobj->health = mthing->options;
mobj->flags2 |= MF2_AXIS; mobj->flags2 |= MF2_AXIS;
break;
if (i == MT_AXIS) case MT_TOKEN:
{
// 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)
{
// We advanced tokenbits earlier due to the return check. // We advanced tokenbits earlier due to the return check.
// Subtract 1 here for the correct value. // Subtract 1 here for the correct value.
mobj->health = 1 << (tokenbits - 1); mobj->health = 1 << (tokenbits - 1);
} break;
else if (i == MT_CYBRAKDEMON && mthing->options & MTF_AMBUSH) case MT_CYBRAKDEMON:
{ if (mthing->options & MTF_AMBUSH)
mobj_t *elecmobj; {
elecmobj = P_SpawnMobj(x, y, z, MT_CYBRAKDEMON_ELECTRIC_BARRIER); mobj_t* elecmobj;
P_SetTarget(&elecmobj->target, mobj); elecmobj = P_SpawnMobj(mobj->x, mobj->y, mobj->z, MT_CYBRAKDEMON_ELECTRIC_BARRIER);
elecmobj->angle = FixedAngle(mthing->angle<<FRACBITS);; P_SetTarget(&elecmobj->target, mobj);
elecmobj->destscale = mobj->scale*2; elecmobj->angle = FixedAngle(mthing->angle << FRACBITS);
P_SetScale(elecmobj, elecmobj->destscale); elecmobj->destscale = mobj->scale*2;
} P_SetScale(elecmobj, elecmobj->destscale);
else if (i == MT_STARPOST) }
break;
case MT_STARPOST:
{ {
thinker_t *th; thinker_t* th;
mobj_t *mo2; mobj_t* mo2;
boolean foundanother = false; 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. // 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) 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 ...@@ -12856,7 +12815,7 @@ ML_EFFECT5 : Don't stop thinking when too far away
if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (th->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
continue; continue;
mo2 = (mobj_t *)th; mo2 = (mobj_t*)th;
if (mo2 == mobj) if (mo2 == mobj)
continue; continue;
...@@ -12870,14 +12829,14 @@ ML_EFFECT5 : Don't stop thinking when too far away ...@@ -12870,14 +12829,14 @@ ML_EFFECT5 : Don't stop thinking when too far away
if (!foundanother) if (!foundanother)
numstarposts++; numstarposts++;
break;
} }
else if (i == MT_SPIKE) case MT_SPIKE:
{
// Pop up spikes! // Pop up spikes!
if (mthing->options & MTF_OBJECTSPECIAL) if (mthing->options & MTF_OBJECTSPECIAL)
{ {
mobj->flags &= ~MF_SCENERY; 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) if (mthing->options & MTF_EXTRA)
P_SetMobjState(mobj, mobj->info->meleestate); P_SetMobjState(mobj, mobj->info->meleestate);
} }
...@@ -12889,14 +12848,13 @@ ML_EFFECT5 : Don't stop thinking when too far away ...@@ -12889,14 +12848,13 @@ ML_EFFECT5 : Don't stop thinking when too far away
mobj->flags |= MF_SOLID; mobj->flags |= MF_SOLID;
P_SetThingPosition(mobj); P_SetThingPosition(mobj);
} }
} break;
else if (i == MT_WALLSPIKE) case MT_WALLSPIKE:
{
// Pop up spikes! // Pop up spikes!
if (mthing->options & MTF_OBJECTSPECIAL) if (mthing->options & MTF_OBJECTSPECIAL)
{ {
mobj->flags &= ~MF_SCENERY; 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) if (mthing->options & MTF_EXTRA)
P_SetMobjState(mobj, mobj->info->meleestate); P_SetMobjState(mobj, mobj->info->meleestate);
} }
...@@ -12904,64 +12862,51 @@ ML_EFFECT5 : Don't stop thinking when too far away ...@@ -12904,64 +12862,51 @@ ML_EFFECT5 : Don't stop thinking when too far away
if (!(mthing->options & MTF_AMBUSH) && !metalrecording) if (!(mthing->options & MTF_AMBUSH) && !metalrecording)
{ {
P_UnsetThingPosition(mobj); P_UnsetThingPosition(mobj);
mobj->flags &= ~(MF_NOBLOCKMAP|MF_NOCLIPHEIGHT); mobj->flags &= ~(MF_NOBLOCKMAP | MF_NOCLIPHEIGHT);
mobj->flags |= MF_SOLID; mobj->flags |= MF_SOLID;
P_SetThingPosition(mobj); P_SetThingPosition(mobj);
} }
// spawn base // 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; const fixed_t baseradius = mobj->radius - mobj->scale;
mobj_t *base = P_SpawnMobj( mobj_t* base = P_SpawnMobj(
mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius), mobj->x - P_ReturnThrustX(mobj, mobjangle, baseradius),
mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius), mobj->y - P_ReturnThrustY(mobj, mobjangle, baseradius),
mobj->z, MT_WALLSPIKEBASE); mobj->z, MT_WALLSPIKEBASE);
base->angle = mobjangle + ANGLE_90; base->angle = mobjangle + ANGLE_90;
base->destscale = mobj->destscale; base->destscale = mobj->destscale;
P_SetScale(base, mobj->scale); P_SetScale(base, mobj->scale);
P_SetTarget(&base->target, mobj); P_SetTarget(&base->target, mobj);
P_SetTarget(&mobj->tracer, base); P_SetTarget(&mobj->tracer, base);
} }
} break;
case MT_RING_BOX:
//count 10 ring boxes into the number of rings equation too. //count 10 ring boxes into the number of rings equation too.
if (i == MT_RING_BOX && nummaprings >= 0) if (nummaprings >= 0)
nummaprings += 10; nummaprings += 10;
break;
if (i == MT_BIGTUMBLEWEED || i == MT_LITTLETUMBLEWEED) case MT_BIGTUMBLEWEED:
{ case MT_LITTLETUMBLEWEED:
if (mthing->options & MTF_AMBUSH) if (mthing->options & MTF_AMBUSH)
{ {
mobj->momz += FixedMul(16*FRACUNIT, mobj->scale); fixed_t offset = FixedMul(16*FRACUNIT, mobj->scale);
mobj->momx += P_RandomChance(FRACUNIT/2) ? offset : -offset;
if (P_RandomChance(FRACUNIT/2)) mobj->momy += P_RandomChance(FRACUNIT/2) ? offset : -offset;
mobj->momx += FixedMul(16*FRACUNIT, mobj->scale); mobj->momz += offset;
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);
} }
} break;
case MT_REDFLAG:
// CTF flag pointers
if (i == MT_REDFLAG)
{
redflag = mobj; redflag = mobj;
rflagpoint = mobj->spawnpoint; rflagpoint = mobj->spawnpoint;
} break;
if (i == MT_BLUEFLAG) case MT_BLUEFLAG:
{
blueflag = mobj; blueflag = mobj;
bflagpoint = mobj->spawnpoint; bflagpoint = mobj->spawnpoint;
} break;
case MT_PUSH:
// special push/pull stuff case MT_PULL:
if (i == MT_PUSH || i == MT_PULL)
{
mobj->health = 0; // Default behaviour: pushing uses XY, fading uses XYZ mobj->health = 0; // Default behaviour: pushing uses XY, fading uses XYZ
if (mthing->options & MTF_AMBUSH) if (mthing->options & MTF_AMBUSH)
...@@ -12970,23 +12915,129 @@ ML_EFFECT5 : Don't stop thinking when too far away ...@@ -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 mobj->health |= 2; // If object special is set, fade using XY
if (G_IsSpecialStage(gamemap)) if (G_IsSpecialStage(gamemap))
{ P_SetMobjState(mobj, (mobj->type == MT_PUSH) ? S_GRAVWELLGREEN : S_GRAVWELLRED);
if (i == MT_PUSH) break;
P_SetMobjState(mobj, S_GRAVWELLGREEN); default:
if (i == MT_PULL) break;
P_SetMobjState(mobj, S_GRAVWELLRED); }
}
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) if (doangle)
mobj->angle = FixedAngle(mthing->angle<<FRACBITS); mobj->angle = FixedAngle(mthing->angle<<FRACBITS);
mthing->mobj = mobj;
// ignore MTF_ flags and return early // ignore MTF_ flags and return early
if (i == MT_NIGHTSBUMPER) if (i == MT_NIGHTSBUMPER)
{
mthing->mobj = mobj;
return; return;
}
if ((mthing->options & MTF_AMBUSH) if ((mthing->options & MTF_AMBUSH)
&& (mthing->options & MTF_OBJECTSPECIAL) && (mthing->options & MTF_OBJECTSPECIAL)
...@@ -12995,67 +13046,10 @@ ML_EFFECT5 : Don't stop thinking when too far away ...@@ -12995,67 +13046,10 @@ ML_EFFECT5 : Don't stop thinking when too far away
else else
{ {
if (mthing->options & MTF_AMBUSH) if (mthing->options & MTF_AMBUSH)
{ P_SetAmbush(mobj);
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;
}
if (mthing->options & MTF_OBJECTSPECIAL) if (mthing->options & MTF_OBJECTSPECIAL)
{ P_SetObjectSpecial(mobj);
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;
}
}
} }
// Generic reverse gravity for individual objects flag. // Generic reverse gravity for individual objects flag.
...@@ -13078,564 +13072,373 @@ ML_EFFECT5 : Don't stop thinking when too far away ...@@ -13078,564 +13072,373 @@ ML_EFFECT5 : Don't stop thinking when too far away
// Final set of not being able to draw nightsitems. // Final set of not being able to draw nightsitems.
if (mobj->flags & MF_NIGHTSITEM) if (mobj->flags & MF_NIGHTSITEM)
mobj->flags2 |= MF2_DONTDRAW; 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; mobj_t *mobj = NULL;
INT32 r, i; mobj_t *nextmobj = NULL;
fixed_t x, y, z, finalx, finaly, finalz; mobj_t *hoopcenter;
sector_t *sec; TMatrix *pitchmatrix, *yawmatrix;
fixed_t radius = hoopsize*sizefactor;
INT32 i;
angle_t fa;
TVector v, *res; 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! z +=
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 +=
#ifdef ESLOPE #ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif #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); P_UnsetThingPosition(hoopcenter);
hoopcenter->x = x; hoopcenter->x = x;
hoopcenter->y = y; hoopcenter->y = y;
P_SetThingPosition(hoopcenter); P_SetThingPosition(hoopcenter);
// Scale 0-255 to 0-359 =( // Scale 0-255 to 0-359 =(
closestangle = FixedAngle(FixedMul((mthing->angle>>8)*FRACUNIT, hoopcenter->movedir = ((mthing->angle & 255)*360)/256; // Pitch
360*(FRACUNIT/256))); 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, // For the hoop when it flies away
360*(FRACUNIT/256))); hoopcenter->extravalue1 = hoopsize;
hoopcenter->movecount = FixedInt(AngleFixed(closestangle)); hoopcenter->extravalue2 = radius/12;
// For the hoop when it flies away // Create the hoop!
hoopcenter->extravalue1 = 32; for (i = 0; i < hoopsize; i++)
hoopcenter->extravalue2 = 8 * FRACUNIT; {
fa = i*(FINEANGLES/hoopsize);
spewangle = (INT16)hoopcenter->movedir; v[0] = FixedMul(FINECOSINE(fa), radius);
v[1] = 0;
// Create the hoop! v[2] = FixedMul(FINESINE(fa), radius);
for (i = 0; i < 32; i++) v[3] = FRACUNIT;
{
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);
if (maptol & TOL_XMAS) res = VectorMatrixMultiply(v, *pitchmatrix);
P_SetMobjState(mobj, mobj->info->seestate + (i & 1)); M_Memcpy(&v, res, sizeof(v));
res = VectorMatrixMultiply(v, *yawmatrix);
M_Memcpy(&v, res, sizeof(v));
mobj->z -= mobj->height/2; mobj = P_SpawnMobj(x + v[0], y + v[1], z + v[2], MT_HOOP);
P_SetTarget(&mobj->target, hoopcenter); // Link the sprite to the center. mobj->z -= mobj->height/2;
mobj->fuse = 0;
// Link all the sprites in the hoop together if (maptol & TOL_XMAS)
if (nextmobj) P_SetMobjState(mobj, mobj->info->seestate + (i & 1));
{
P_SetTarget(&mobj->hprev, nextmobj);
P_SetTarget(&mobj->hprev->hnext, mobj);
}
else
P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL));
nextmobj = mobj; P_SetTarget(&mobj->target, hoopcenter); // Link the sprite to the center.
} mobj->fuse = 0;
// Create the collision detectors! // Link all the sprites in the hoop together
for (i = 0; i < 16; i++) 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, nextmobj);
P_SetTarget(&mobj->hprev->hnext, mobj); P_SetTarget(&mobj->hprev->hnext, mobj);
nextmobj = mobj;
} }
// Create the collision detectors! else
for (i = 0; i < 16; i++) P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL));
{
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);
nextmobj = mobj; nextmobj = mobj;
}
return;
} }
// 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; // Create the collision detectors!
// Create them until the size is less than 8
// Super happy fun time // But always create at least ONE set of collision detectors
// For each flag add 4 fracunits to the size do
// Default (0 flags) is 8 fracunits {
hoopsize = 8 + (4 * (mthing->options & 0xF)); if (hoopsize >= 32)
hoopplacement = hoopsize * (4*FRACUNIT); hoopsize -= 16;
else
hoopsize /= 2;
// For the hoop when it flies away radius = hoopsize*sizefactor;
hoopcenter->extravalue1 = hoopsize;
hoopcenter->extravalue2 = FixedDiv(hoopplacement, 12*FRACUNIT);
// Create the hoop!
for (i = 0; i < hoopsize; i++) for (i = 0; i < hoopsize; i++)
{ {
fa = i*(FINEANGLES/hoopsize); fa = i*(FINEANGLES/hoopsize);
v[0] = FixedMul(FINECOSINE(fa), hoopplacement); v[0] = FixedMul(FINECOSINE(fa), radius);
v[1] = 0; v[1] = 0;
v[2] = FixedMul(FINESINE(fa), hoopplacement); v[2] = FixedMul(FINESINE(fa), radius);
v[3] = FRACUNIT; v[3] = FRACUNIT;
res = VectorMatrixMultiply(v, *RotateXMatrix(FixedAngle(spewangle*FRACUNIT))); res = VectorMatrixMultiply(v, *pitchmatrix);
M_Memcpy(&v, res, sizeof (v)); M_Memcpy(&v, res, sizeof(v));
res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); res = VectorMatrixMultiply(v, *yawmatrix);
M_Memcpy(&v, res, sizeof (v)); 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));
mobj = P_SpawnMobj(x + v[0], y + v[1], z + v[2], MT_HOOPCOLLIDE);
mobj->z -= mobj->height/2; 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 // Link all the collision sprites together.
if (nextmobj) P_SetTarget(&mobj->hnext, NULL);
{ P_SetTarget(&mobj->hprev, nextmobj);
P_SetTarget(&mobj->hprev, nextmobj); P_SetTarget(&mobj->hprev->hnext, mobj);
P_SetTarget(&mobj->hprev->hnext, mobj);
}
else
P_SetTarget(&mobj->hprev, P_SetTarget(&mobj->hnext, NULL));
nextmobj = mobj; nextmobj = mobj;
} }
} while (hoopsize >= 8);
}
// Create the collision detectors! static void P_SpawnRingItem(mapthing_t *mthing, fixed_t x, fixed_t y, boolean bonustime, boolean nightsreplace)
// Create them until the size is less than 8 {
// But always create at least ONE set of collision detectors mobjtype_t ringthing = MT_RING;
do mobj_t *mobj = NULL;
{ fixed_t z;
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
// ***
// Vertical Rings - Stack of 5 (handles both red and yellow) // Which ringthing to use
else if (mthing->type == 600 || mthing->type == 601) 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) if (ultimatemode)
return; // No rings in Ultimate! return; // No rings in Ultimate!
if (nightsreplace) if (nightsreplace)
ringthing = MT_NIGHTSSTAR; 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 = P_GetMobjSpawnHeight(ringthing, mthing, x, y);
{ mobj = P_SpawnMobj(x, y, z, ringthing);
z = ( mobj->spawnpoint = mthing;
#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;
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->angle = FixedAngle(mthing->angle << FRACBITS);
{ mthing->mobj = mobj;
mobj->eflags |= MFE_VERTICALFLIP; if (mthing->options & MTF_AMBUSH)
mobj->flags2 |= MF2_OBJECTFLIP; mobj->flags2 |= MF2_AMBUSH;
}
mobj->angle = FixedAngle(mthing->angle*FRACUNIT); if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP))
if (mthing->options & MTF_AMBUSH) P_SetMobjState(mobj, mobj->info->raisestate);
mobj->flags2 |= MF2_AMBUSH; else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
P_SetMobjState(mobj, mobj->info->seestate);
}
if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) static void P_SpawnVerticalSpringRings(mapthing_t *mthing, fixed_t x, fixed_t y, sector_t* sec, boolean nightsreplace)
P_SetMobjState(mobj, mobj->info->seestate); {
} mobjtype_t ringthing = MT_RING;
} mobj_t* mobj = NULL;
// Diagonal rings (handles both types) fixed_t z;
else if (mthing->type == 602 || mthing->type == 603) // Diagonal rings (5) INT32 r;
{
INT32 iterations = 5;
if (mthing->type == 603)
iterations = 10;
if (ultimatemode) INT32 dist = 64*FRACUNIT;
return; // No rings in Ultimate! if (mthing->type == 601)
dist = 128*FRACUNIT;
if (nightsreplace) if (ultimatemode)
ringthing = MT_NIGHTSSTAR; return; // No rings in Ultimate!
closestangle = FixedAngle(mthing->angle*FRACUNIT); if (nightsreplace)
fa = (closestangle >> ANGLETOFINESHIFT); ringthing = MT_NIGHTSSTAR;
if (mthing->options & MTF_OBJECTFLIP) if (mthing->options & MTF_OBJECTFLIP)
{ {
z = ( 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 #ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : sec->c_slope ? P_GetZAt(sec->c_slope, x, y) :
#endif #endif
sec->floorheight); sec->ceilingheight) - mobjinfo[ringthing].height;
if (mthing->options >> ZSHIFT) if (mthing->z)
z += ((mthing->options >> ZSHIFT) << FRACBITS); z -= (mthing->z << 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);
}
} }
// Rings of items (all six of them) else
else if (mthing->type >= 604 && mthing->type <= 609)
{ {
INT32 numitems = 8; z = (
INT32 size = 96*FRACUNIT;
if (mthing->type & 1)
{
numitems = 16;
size = 192*FRACUNIT;
}
z =
#ifdef ESLOPE #ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif #endif
sec->floorheight; sec->floorheight);
if (mthing->options >> ZSHIFT) if (mthing->z)
z += ((mthing->options >> ZSHIFT) << FRACBITS); 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: mobj->eflags |= MFE_VERTICALFLIP;
case 605: mobj->flags2 |= MF2_OBJECTFLIP;
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;
} }
// Create the hoop! mobj->angle = FixedAngle(mthing->angle << FRACBITS);
for (i = 0; i < numitems; i++) if (mthing->options & MTF_AMBUSH)
{ mobj->flags2 |= MF2_AMBUSH;
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;
}
fa = i*FINEANGLES/numitems; if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR))
v[0] = FixedMul(FINECOSINE(fa),size); P_SetMobjState(mobj, mobj->info->seestate);
v[1] = 0; }
v[2] = FixedMul(FINESINE(fa),size); }
v[3] = FRACUNIT;
res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle)); static void P_SpawnDiagonalSpringRings(mapthing_t* mthing, fixed_t x, fixed_t y, sector_t* sec, boolean nightsreplace)
M_Memcpy(&v, res, sizeof (v)); {
mobjtype_t ringthing = MT_RING;
mobj_t *mobj = NULL;
fixed_t z;
INT32 r;
angle_t closestangle, fa;
finalx = x + v[0]; INT32 iterations = 5;
finaly = y + v[1]; if (mthing->type == 603)
finalz = z + v[2]; iterations = 10;
mobj = P_SpawnMobj(finalx, finaly, finalz, ringthing); if (ultimatemode)
mobj->z -= mobj->height/2; return; // No rings in Ultimate!
if (mthing->options & MTF_OBJECTFLIP) if (nightsreplace)
{ ringthing = MT_NIGHTSSTAR;
mobj->eflags |= MFE_VERTICALFLIP;
mobj->flags2 |= MF2_OBJECTFLIP;
}
mobj->angle = closestangle; closestangle = FixedAngle(mthing->angle << FRACBITS);
if (mthing->options & MTF_AMBUSH) fa = (closestangle >> ANGLETOFINESHIFT);
mobj->flags2 |= MF2_AMBUSH;
if (bonustime && (ringthing == MT_BLUESPHERE || ringthing == MT_NIGHTSCHIP)) if (mthing->options & MTF_OBJECTFLIP)
P_SetMobjState(mobj, mobj->info->raisestate); {
else if ((maptol & TOL_XMAS) && (ringthing == MT_NIGHTSSTAR)) z = (
P_SetMobjState(mobj, mobj->info->seestate); #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 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 for (r = 1; r <= iterations; r++)
if (mthing->type == mobjinfo[MT_BLUESPHERE].doomednum) {
ringthing = (nightsreplace) ? MT_NIGHTSCHIP : MT_BLUESPHERE; x += FixedMul(64*FRACUNIT, FINECOSINE(fa));
else if (mthing->type == mobjinfo[MT_BOMBSPHERE].doomednum) y += FixedMul(64*FRACUNIT, FINESINE(fa));
ringthing = MT_BOMBSPHERE;
if (mthing->options & MTF_OBJECTFLIP)
z -= 64*FRACUNIT;
else else
{ z += 64*FRACUNIT;
if (ultimatemode)
return; // No rings in Ultimate!
if (nightsreplace) mobj = P_SpawnMobj(x, y, z, ringthing);
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;
}
// Set proper height
if (mthing->options & MTF_OBJECTFLIP) if (mthing->options & MTF_OBJECTFLIP)
{ {
z = ( mobj->eflags |= MFE_VERTICALFLIP;
#ifdef ESLOPE mobj->flags2 |= MF2_OBJECTFLIP;
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
{ mobj->angle = closestangle;
z = 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 #ifdef ESLOPE
sec->f_slope ? P_GetZAt(sec->f_slope, x, y) : sec->f_slope ? P_GetZAt(sec->f_slope, x, y) :
#endif #endif
sec->floorheight; sec->floorheight;
if (mthing->options >> ZSHIFT) if (mthing->z)
z += ((mthing->options >> ZSHIFT) << FRACBITS); 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) if (i & 1)
z -= 24*FRACUNIT; {
if (ultimatemode)
continue; // No rings in Ultimate!
ringthing = (nightsreplace) ? MT_NIGHTSSTAR : MT_RING;
}
else 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); res = VectorMatrixMultiply(v, *RotateZMatrix(closestangle));
mobj->spawnpoint = mthing; 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) if (mthing->options & MTF_OBJECTFLIP)
{ {
...@@ -13643,8 +13446,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) ...@@ -13643,8 +13446,7 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime)
mobj->flags2 |= MF2_OBJECTFLIP; mobj->flags2 |= MF2_OBJECTFLIP;
} }
mobj->angle = FixedAngle(mthing->angle*FRACUNIT); mobj->angle = closestangle;
mthing->mobj = mobj;
if (mthing->options & MTF_AMBUSH) if (mthing->options & MTF_AMBUSH)
mobj->flags2 |= MF2_AMBUSH; mobj->flags2 |= MF2_AMBUSH;
...@@ -13655,6 +13457,47 @@ void P_SpawnHoopsAndRings(mapthing_t *mthing, boolean bonustime) ...@@ -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 // P_CheckMissileSpawn
// Moves the missile forward a bit and possibly explodes it right there. // Moves the missile forward a bit and possibly explodes it right there.
......
...@@ -781,9 +781,10 @@ static void P_NetArchiveWorld(void) ...@@ -781,9 +781,10 @@ static void P_NetArchiveWorld(void)
UINT8 *put; UINT8 *put;
// reload the map just to see difference // reload the map just to see difference
mapsector_t *ms; virtres_t* virt = vres_GetMap(lastloadedmaplumpnum);
mapsidedef_t *msd; mapsector_t *ms = (mapsector_t*) vres_Find(virt, "SECTORS")->data;
maplinedef_t *mld; 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; const sector_t *ss = sectors;
UINT8 diff, diff2, diff3; UINT8 diff, diff2, diff3;
...@@ -793,26 +794,6 @@ static void P_NetArchiveWorld(void) ...@@ -793,26 +794,6 @@ static void P_NetArchiveWorld(void)
WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD); WRITEUINT32(save_p, ARCHIVEBLOCK_WORLD);
put = save_p; 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++) for (i = 0; i < numsectors; i++, ss++, ms++)
{ {
diff = diff2 = diff3 = 0; diff = diff2 = diff3 = 0;
...@@ -1037,6 +1018,7 @@ static void P_NetArchiveWorld(void) ...@@ -1037,6 +1018,7 @@ static void P_NetArchiveWorld(void)
WRITEUINT16(put, 0xffff); WRITEUINT16(put, 0xffff);
R_ClearTextureNumCache(false); R_ClearTextureNumCache(false);
vres_Free(virt);
save_p = put; save_p = put;
} }
......
...@@ -367,27 +367,12 @@ UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade) ...@@ -367,27 +367,12 @@ UINT32 P_GetScoreForGrade(INT16 map, UINT8 mare, UINT8 grade)
return mapheaderinfo[map-1]->grades[mare].grade[grade-1]; return mapheaderinfo[map-1]->grades[mare].grade[grade-1];
} }
/** Loads the vertexes for a level. // Loads the vertexes for a level.
* static inline void P_LoadRawVertexes(UINT8 *data)
* \param lump VERTEXES lump number.
* \sa ML_VERTEXES
*/
static inline void P_LoadRawVertexes(UINT8 *data, size_t i)
{ {
mapvertex_t *ml; mapvertex_t *ml = (mapvertex_t *)data;
vertex_t *li; vertex_t *li = vertexes;
size_t i;
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;
// Copy and convert vertex coordinates, internal representation as fixed. // Copy and convert vertex coordinates, internal representation as fixed.
for (i = 0; i < numvertexes; i++, li++, ml++) for (i = 0; i < numvertexes; i++, li++, ml++)
...@@ -397,13 +382,6 @@ static inline void P_LoadRawVertexes(UINT8 *data, size_t i) ...@@ -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. /** Computes the length of a seg in fracunits.
* *
* \param seg Seg to compute length for. * \param seg Seg to compute length for.
...@@ -435,25 +413,15 @@ static inline float P_SegLengthFloat(seg_t *seg) ...@@ -435,25 +413,15 @@ static inline float P_SegLengthFloat(seg_t *seg)
} }
#endif #endif
/** Loads the SEGS resource from a level. // Loads the SEGS resource from a level.
* static void P_LoadRawSegs(UINT8 *data)
* \param lump Lump number of the SEGS resource.
* \sa ::ML_SEGS
*/
static void P_LoadRawSegs(UINT8 *data, size_t i)
{ {
INT32 linedef, side; INT32 linedef, side;
mapseg_t *ml; mapseg_t *ml = (mapseg_t*)data;
seg_t *li; seg_t *li = segs;
line_t *ldef; 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++) for (i = 0; i < numsegs; i++, li++, ml++)
{ {
li->v1 = &vertexes[SHORT(ml->v1)]; li->v1 = &vertexes[SHORT(ml->v1)];
...@@ -478,7 +446,7 @@ static void P_LoadRawSegs(UINT8 *data, size_t i) ...@@ -478,7 +446,7 @@ static void P_LoadRawSegs(UINT8 *data, size_t i)
li->side = side = SHORT(ml->side); li->side = side = SHORT(ml->side);
li->sidedef = &sides[ldef->sidenum[side]]; li->sidedef = &sides[ldef->sidenum[side]];
li->frontsector = sides[ldef->sidenum[side]].sector; 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; li->backsector = sides[ldef->sidenum[side^1]].sector;
else else
li->backsector = 0; li->backsector = 0;
...@@ -488,30 +456,12 @@ static void P_LoadRawSegs(UINT8 *data, size_t i) ...@@ -488,30 +456,12 @@ static void P_LoadRawSegs(UINT8 *data, size_t i)
} }
} }
static void P_LoadSegs(lumpnum_t lumpnum) // Loads the SSECTORS resource from a level.
{ static inline void P_LoadRawSubsectors(void *data)
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)
{ {
mapsubsector_t *ms; mapsubsector_t *ms = (mapsubsector_t*)data;
subsector_t *ss; subsector_t *ss = subsectors;
size_t i;
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;
for (i = 0; i < numsubsectors; i++, ss++, ms++) for (i = 0; i < numsubsectors; i++, ss++, ms++)
{ {
...@@ -525,13 +475,6 @@ static inline void P_LoadRawSubsectors(void *data, size_t i) ...@@ -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 // levelflats
// //
...@@ -698,20 +641,12 @@ INT32 P_CheckLevelFlat(const char *flatname) ...@@ -698,20 +641,12 @@ INT32 P_CheckLevelFlat(const char *flatname)
} }
// Sets up the ingame sectors structures. // Sets up the ingame sectors structures.
// Lumpnum is the lumpnum of a SECTORS lump. static void P_LoadRawSectors(UINT8 *data)
static void P_LoadRawSectors(UINT8 *data, size_t i)
{ {
mapsector_t *ms; mapsector_t *ms = (mapsector_t *)data;
sector_t *ss; sector_t *ss = sectors;
levelflat_t *foundflats; levelflat_t *foundflats;
size_t i;
// 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);
// Allocate a big chunk of memory as big as our MAXLEVELFLATS limit. // 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 //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) ...@@ -722,8 +657,6 @@ static void P_LoadRawSectors(UINT8 *data, size_t i)
numlevelflats = 0; numlevelflats = 0;
// For each counted sector, copy the sector raw data from our cache pointer ms, to the global table pointer ss. // 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++) for (i = 0; i < numsectors; i++, ss++, ms++)
{ {
ss->floorheight = SHORT(ms->floorheight)<<FRACBITS; ss->floorheight = SHORT(ms->floorheight)<<FRACBITS;
...@@ -805,29 +738,15 @@ static void P_LoadRawSectors(UINT8 *data, size_t i) ...@@ -805,29 +738,15 @@ static void P_LoadRawSectors(UINT8 *data, size_t i)
P_SetupLevelFlatAnims(); 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 // P_LoadNodes
// //
static void P_LoadRawNodes(UINT8 *data, size_t i) static void P_LoadRawNodes(UINT8 *data)
{ {
UINT8 j, k; UINT8 j, k;
mapnode_t *mn; mapnode_t *mn = (mapnode_t*)data;
node_t *no; node_t *no = nodes;
size_t i;
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;
for (i = 0; i < numnodes; i++, no++, mn++) for (i = 0; i < numnodes; i++, no++, mn++)
{ {
...@@ -844,13 +763,6 @@ static void P_LoadRawNodes(UINT8 *data, size_t i) ...@@ -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 // P_ReloadRings
// Used by NiGHTS, clears all ring/wing/etc items and respawns them // Used by NiGHTS, clears all ring/wing/etc items and respawns them
...@@ -906,10 +818,6 @@ void P_ReloadRings(void) ...@@ -906,10 +818,6 @@ void P_ReloadRings(void)
{ {
mt->mobj = NULL; 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); P_SpawnHoopsAndRings(mt, true);
} }
} }
...@@ -1006,20 +914,16 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum) ...@@ -1006,20 +914,16 @@ void P_ScanThings(INT16 mapnum, INT16 wadnum, INT16 lumpnum)
} }
#endif #endif
static void P_PrepareRawThings(UINT8 *data, size_t i) static void P_PrepareRawThings(UINT8 *data)
{ {
mapthing_t *mt; mapthing_t *mt;
size_t i;
nummapthings = i / (5 * sizeof (INT16)); for (i = 0, mt = mapthings; i < nummapthings; i++, mt++)
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++)
{ {
mt->x = READINT16(data); mt->x = READINT16(data);
mt->y = READINT16(data); mt->y = READINT16(data);
mt->angle = READINT16(data); mt->angle = READINT16(data);
mt->type = READUINT16(data); mt->type = READUINT16(data);
mt->options = READUINT16(data); mt->options = READUINT16(data);
...@@ -1027,6 +931,66 @@ static void P_PrepareRawThings(UINT8 *data, size_t i) ...@@ -1027,6 +931,66 @@ static void P_PrepareRawThings(UINT8 *data, size_t i)
mt->type &= 4095; 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) switch (mt->type)
{ {
case 1700: // MT_AXIS case 1700: // MT_AXIS
...@@ -1039,35 +1003,11 @@ static void P_PrepareRawThings(UINT8 *data, size_t i) ...@@ -1039,35 +1003,11 @@ static void P_PrepareRawThings(UINT8 *data, size_t i)
break; 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; 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 if (mt->type == 1700 // MT_AXIS
|| mt->type == 1701 // MT_AXISTRANSFER || mt->type == 1701 // MT_AXISTRANSFER
|| mt->type == 1702) // MT_AXISTRANSFERLINE || mt->type == 1702) // MT_AXISTRANSFERLINE
...@@ -1082,49 +1022,7 @@ static void P_LoadThings(boolean loademblems) ...@@ -1082,49 +1022,7 @@ static void P_LoadThings(boolean loademblems)
// random emeralds for hunt // random emeralds for hunt
if (numhuntemeralds) if (numhuntemeralds)
{ P_SpawnEmeraldHunt();
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);
}
if (metalrecording) // Metal Sonic gets no rings to distract him. if (metalrecording) // Metal Sonic gets no rings to distract him.
return; return;
...@@ -1140,11 +1038,6 @@ static void P_LoadThings(boolean loademblems) ...@@ -1140,11 +1038,6 @@ static void P_LoadThings(boolean loademblems)
|| mt->type == 1705 || mt->type == 1713) // hoops || mt->type == 1705 || mt->type == 1713) // hoops
{ {
mt->mobj = NULL; 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); P_SpawnHoopsAndRings(mt, false);
} }
} }
...@@ -1193,33 +1086,46 @@ void P_WriteThings(lumpnum_t lumpnum) ...@@ -1193,33 +1086,46 @@ void P_WriteThings(lumpnum_t lumpnum)
CONS_Printf(M_GetText("newthings%d.lmp saved.\n"), gamemap); 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; maplinedef_t *mld = (maplinedef_t *)data;
line_t *ld; line_t *ld = lines;
vertex_t *v1, *v2; size_t i;
numlines = i / sizeof (maplinedef_t);
if (numlines <= 0)
I_Error("Level has no linedefs");
lines = Z_Calloc(numlines * sizeof (*lines), PU_LEVEL, NULL);
mld = (maplinedef_t *)data;
ld = lines;
for (i = 0; i < numlines; i++, mld++, ld++) for (i = 0; i < numlines; i++, mld++, ld++)
{ {
ld->flags = SHORT(mld->flags); ld->flags = SHORT(mld->flags);
ld->special = SHORT(mld->special); ld->special = SHORT(mld->special);
ld->tag = SHORT(mld->tag); ld->tag = SHORT(mld->tag);
v1 = ld->v1 = &vertexes[SHORT(mld->v1)]; ld->v1 = &vertexes[SHORT(mld->v1)];
v2 = ld->v2 = &vertexes[SHORT(mld->v2)]; ld->v2 = &vertexes[SHORT(mld->v2)];
ld->dx = v2->x - v1->x;
ld->dy = v2->y - v1->y; 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 #ifdef WALLSPLATS
ld->splats = NULL; ld->splats = NULL;
#endif #endif
#ifdef POLYOBJECTS
ld->polyobj = NULL;
#endif
ld->dx = v2->x - v1->x;
ld->dy = v2->y - v1->y;
if (!ld->dx) if (!ld->dx)
ld->slopetype = ST_VERTICAL; ld->slopetype = ST_VERTICAL;
else if (!ld->dy) else if (!ld->dy)
...@@ -1251,62 +1157,46 @@ static void P_LoadRawLineDefs(UINT8 *data, size_t i) ...@@ -1251,62 +1157,46 @@ static void P_LoadRawLineDefs(UINT8 *data, size_t i)
ld->bbox[BOXTOP] = v1->y; 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 2006/09/30 - fix sidedef errors right away.
// cph 2002/07/20 - these errors are fatal if not fixed, so apply them // cph 2002/07/20 - these errors are fatal if not fixed, so apply them
UINT8 j; UINT8 j;
for (j=0; j < 2; j++) for (j=0; j < 2; j++)
{
if (ld->sidenum[j] != 0xffff && ld->sidenum[j] >= (UINT16)numsides) if (ld->sidenum[j] != 0xffff && ld->sidenum[j] >= (UINT16)numsides)
{ {
ld->sidenum[j] = 0xffff; ld->sidenum[j] = 0xffff;
CONS_Debug(DBG_SETUP, "P_LoadRawLineDefs: linedef %s has out-of-range sidedef number\n", sizeu1(numlines-i-1)); 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->frontsector = ld->backsector = NULL;
ld->validcount = 0; ld->validcount = 0;
ld->firsttag = ld->nexttag = -1; ld->firsttag = ld->nexttag = -1;
ld->callcount = 0; 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) if (ld->sidenum[0] == 0xffff)
{ {
ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side ld->sidenum[0] = 0; // Substitute dummy sidedef for missing right side
// cph - print a warning about the bug // 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)) if ((ld->sidenum[1] == 0xffff) && (ld->flags & ML_TWOSIDED))
{ {
ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side ld->flags &= ~ML_TWOSIDED; // Clear 2s flag for missing left side
// cph - print a warning about the bug // 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) if (ld->sidenum[0] != 0xffff && ld->special)
sides[ld->sidenum[0]].special = ld->special; sides[ld->sidenum[0]].special = ld->special;
if (ld->sidenum[1] != 0xffff && ld->special) if (ld->sidenum[1] != 0xffff && ld->special)
sides[ld->sidenum[1]].special = 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) static void P_LoadLineDefs2(void)
{ {
size_t i = numlines; size_t i = numlines;
...@@ -1409,22 +1299,6 @@ static void P_LoadLineDefs2(void) ...@@ -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) static void P_LoadRawSideDefs2(void *data)
{ {
UINT16 i; UINT16 i;
...@@ -1585,15 +1459,6 @@ static void P_LoadRawSideDefs2(void *data) ...@@ -1585,15 +1459,6 @@ static void P_LoadRawSideDefs2(void *data)
R_ClearTextureNumCache(true); 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) 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]; fixed_t bbox[4];
...@@ -1873,84 +1738,11 @@ static void P_ReadBlockMapLump(INT16 *wadblockmaplump, size_t count) ...@@ -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 // This needs to be a separate function
// because making both the WAD and PK3 loading code use // because making both the WAD and PK3 loading code use
// the same functions is trickier than it looks for blockmap // the same functions is trickier than it looks for blockmap
// -- Monster Iestyn 09/01/18 // -- 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 #if 0
(void)data; (void)data;
...@@ -1958,12 +1750,6 @@ static boolean P_LoadRawBlockMap(UINT8 *data, size_t count, const char *lumpname ...@@ -1958,12 +1750,6 @@ static boolean P_LoadRawBlockMap(UINT8 *data, size_t count, const char *lumpname
(void)lumpname; (void)lumpname;
return false; return false;
#else #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) if (!count || count >= 0x20000)
return false; return false;
...@@ -2089,56 +1875,139 @@ static void P_GroupLines(void) ...@@ -2089,56 +1875,139 @@ static void P_GroupLines(void)
} }
} }
// // PK3 version
// P_LoadReject // -- Monster Iestyn 09/01/18
// static void P_LoadRawReject(UINT8 *data, size_t count)
// Detect if the REJECT lump is valid,
// if not, rejectmatrix will be NULL
static void P_LoadReject(lumpnum_t lumpnum)
{ {
size_t count; if (!count) // zero length, someone probably used ZDBSP
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)
{ {
rejectmatrix = NULL; rejectmatrix = NULL;
CONS_Debug(DBG_SETUP, "P_LoadReject: No valid REJECT lump found\n"); CONS_Debug(DBG_SETUP, "P_LoadRawReject: REJECT lump has size 0, will not be loaded\n");
return;
} }
else
count = W_LumpLength(lumpnum);
if (!count) // zero length, someone probably used ZDBSP
{ {
rejectmatrix = NULL; rejectmatrix = Z_Malloc(count, PU_LEVEL, NULL); // allocate memory for the reject matrix
CONS_Debug(DBG_SETUP, "P_LoadReject: REJECT lump has size 0, will not be loaded\n"); 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 else
rejectmatrix = W_CacheLumpNum(lumpnum, PU_LEVEL); rejectmatrix = NULL;
if (!(virtblockmap && P_LoadRawBlockMap(virtblockmap->data, virtblockmap->size)))
P_CreateBlockMap();
} }
// PK3 version static void P_LoadMapData(const virtres_t* virt)
// -- Monster Iestyn 09/01/18
static void P_LoadRawReject(UINT8 *data, size_t count, const char *lumpname)
{ {
// Check if the lump is named "REJECT" virtlump_t* virtvertexes = NULL, * virtsectors = NULL, * virtsidedefs = NULL, * virtlinedefs = NULL, * virtthings = NULL;
if (!lumpname || memcmp(lumpname, "REJECT\0\0", 8) != 0) #ifdef UDMF
virtlump_t* textmap = vres_Find(virt, "TEXTMAP");
// Count map data.
if (textmap)
{ {
rejectmatrix = NULL; nummapthings = 0;
CONS_Debug(DBG_SETUP, "P_LoadRawReject: No valid REJECT lump found\n"); numlines = 0;
return; 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 else
#endif
{ {
rejectmatrix = Z_Malloc(count, PU_LEVEL, NULL); // allocate memory for the reject matrix // Strict map data
M_Memcpy(rejectmatrix, data, count); // copy the data into it 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) ...@@ -2317,6 +2186,8 @@ void P_LoadThingsOnly(void)
// Search through all the thinkers. // Search through all the thinkers.
thinker_t *think; thinker_t *think;
INT32 i, viewid = -1, centerid = -1; // for skyboxes 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 // check if these are any of the normal viewpoint/centerpoint mobjs in the level or not
if (skyboxmo[0] || skyboxmo[1]) if (skyboxmo[0] || skyboxmo[1])
...@@ -2328,7 +2199,6 @@ void P_LoadThingsOnly(void) ...@@ -2328,7 +2199,6 @@ void P_LoadThingsOnly(void)
centerid = i; // save id just in case centerid = i; // save id just in case
} }
for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next) for (think = thlist[THINK_MOBJ].next; think != &thlist[THINK_MOBJ]; think = think->next)
{ {
if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed) if (think->function.acp1 == (actionf_p1)P_RemoveThinkerDelayed)
...@@ -2338,18 +2208,11 @@ void P_LoadThingsOnly(void) ...@@ -2338,18 +2208,11 @@ void P_LoadThingsOnly(void)
P_LevelInitStuff(); P_LevelInitStuff();
if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3 P_PrepareRawThings(vth->data);
{ // 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_LoadThings(true); P_LoadThings(true);
vres_Free(virt);
// restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that // restore skybox viewpoint/centerpoint if necessary, set them to defaults if we can't do that
skyboxmo[0] = skyboxviewpnts[(viewid >= 0) ? viewid : 0]; skyboxmo[0] = skyboxviewpnts[(viewid >= 0) ? viewid : 0];
skyboxmo[1] = skyboxcenterpnts[(centerid >= 0) ? centerid : 0]; skyboxmo[1] = skyboxcenterpnts[(centerid >= 0) ? centerid : 0];
...@@ -2381,7 +2244,7 @@ static INT32 P_MakeBufferMD5(const char *buffer, size_t len, void *resblock) ...@@ -2381,7 +2244,7 @@ static INT32 P_MakeBufferMD5(const char *buffer, size_t len, void *resblock)
#endif #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 linemd5[16];
unsigned char sectormd5[16]; unsigned char sectormd5[16];
...@@ -2392,20 +2255,15 @@ static void P_MakeMapMD5(lumpnum_t maplumpnum, void *dest) ...@@ -2392,20 +2255,15 @@ static void P_MakeMapMD5(lumpnum_t maplumpnum, void *dest)
// Create a hash for the current map // Create a hash for the current map
// get the actual lumps! // get the actual lumps!
UINT8 *datalines = W_CacheLumpNum(maplumpnum + ML_LINEDEFS, PU_CACHE); virtlump_t* virtlines = vres_Find(virt, "LINEDEFS");
UINT8 *datasectors = W_CacheLumpNum(maplumpnum + ML_SECTORS, PU_CACHE); virtlump_t* virtsectors = vres_Find(virt, "SECTORS");
UINT8 *datathings = W_CacheLumpNum(maplumpnum + ML_THINGS, PU_CACHE); virtlump_t* virtmthings = vres_Find(virt, "THINGS");
UINT8 *datasides = W_CacheLumpNum(maplumpnum + ML_SIDEDEFS, PU_CACHE); virtlump_t* virtsides = vres_Find(virt, "SIDEDEFS");
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);
Z_Free(datalines); P_MakeBufferMD5((char*)virtlines->data, virtlines->size, linemd5);
Z_Free(datasectors); P_MakeBufferMD5((char*)virtsectors->data, virtsectors->size, sectormd5);
Z_Free(datathings); P_MakeBufferMD5((char*)virtmthings->data, virtmthings->size, thingmd5);
Z_Free(datasides); P_MakeBufferMD5((char*)virtsides->data, virtsides->size, sidedefmd5);
for (i = 0; i < 16; i++) for (i = 0; i < 16; i++)
resmd5[i] = (linemd5[i] + sectormd5[i] + thingmd5[i] + sidedefmd5[i]) & 0xFF; resmd5[i] = (linemd5[i] + sectormd5[i] + thingmd5[i] + sidedefmd5[i]) & 0xFF;
...@@ -2641,7 +2499,6 @@ boolean P_SetupLevel(boolean skipprecip) ...@@ -2641,7 +2499,6 @@ boolean P_SetupLevel(boolean skipprecip)
INT32 i, loadprecip = 1, ranspecialwipe = 0; INT32 i, loadprecip = 1, ranspecialwipe = 0;
INT32 loademblems = 1; INT32 loademblems = 1;
INT32 fromnetsave = 0; INT32 fromnetsave = 0;
boolean loadedbm = false;
sector_t *ss; sector_t *ss;
boolean chase; boolean chase;
levelloading = true; levelloading = true;
...@@ -2890,110 +2747,39 @@ boolean P_SetupLevel(boolean skipprecip) ...@@ -2890,110 +2747,39 @@ boolean P_SetupLevel(boolean skipprecip)
// SRB2 determines the sky texture to be used depending on the map header. // SRB2 determines the sky texture to be used depending on the map header.
P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true); P_SetupLevelSky(mapheaderinfo[gamemap-1]->skynum, true);
P_MakeMapMD5(lastloadedmaplumpnum, &mapmd5); numdmstarts = numredctfstarts = numbluectfstarts = 0;
// 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);
}
if (numlumps > ML_BLOCKMAP) // enough room for a BLOCKMAP lump at least // reset the player starts
{ for (i = 0; i < MAXPLAYERS; i++)
loadedbm = P_LoadRawBlockMap( playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
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);
}
// Important: take care of the ordering of the next functions. for (i = 0; i < MAX_DM_STARTS; i++)
if (!loadedbm) deathmatchstarts[i] = NULL;
P_CreateBlockMap(); // Graue 02-29-2004
P_LoadLineDefs2();
P_GroupLines();
numdmstarts = numredctfstarts = numbluectfstarts = 0;
// reset the player starts for (i = 0; i < 2; i++)
for (i = 0; i < MAXPLAYERS; i++) skyboxmo[i] = NULL;
playerstarts[i] = bluectfstarts[i] = redctfstarts[i] = NULL;
for (i = 0; i < MAX_DM_STARTS; i++) for (i = 0; i < 16; i++)
deathmatchstarts[i] = NULL; skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL;
for (i = 0; i < 2; i++) P_MapStart();
skyboxmo[i] = NULL;
for (i = 0; i < 16; i++) if (lastloadedmaplumpnum)
skyboxviewpnts[i] = skyboxcenterpnts[i] = NULL; {
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_LoadLineDefs2();
P_GroupLines(); P_GroupLines();
numdmstarts = numredctfstarts = numbluectfstarts = 0;
// reset the player starts P_PrepareRawThings(vres_Find(virt, "THINGS")->data);
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_MapStart(); P_MakeMapMD5(virt, &mapmd5);
P_PrepareThings(lastloadedmaplumpnum + ML_THINGS); vres_Free(virt);
} }
// init gravity, tag lists, // init gravity, tag lists,
......
...@@ -6441,7 +6441,7 @@ void P_SpawnSpecials(INT32 fromnetsave) ...@@ -6441,7 +6441,7 @@ void P_SpawnSpecials(INT32 fromnetsave)
INT32 j; INT32 j;
thinkerlist_t *secthinkers; thinkerlist_t *secthinkers;
thinker_t *th; thinker_t *th;
virtres_t* virt = NULL;
// This used to be used, and *should* be used in the future, // This used to be used, and *should* be used in the future,
// but currently isn't. // but currently isn't.
(void)fromnetsave; (void)fromnetsave;
...@@ -7193,17 +7193,10 @@ void P_SpawnSpecials(INT32 fromnetsave) ...@@ -7193,17 +7193,10 @@ void P_SpawnSpecials(INT32 fromnetsave)
UINT8 *data; UINT8 *data;
UINT16 b; UINT16 b;
if (W_IsLumpWad(lastloadedmaplumpnum)) // welp it's a map wad in a pk3 if (!virt)
{ // HACK: Open wad file rather quickly so we can get the data from the sidedefs lump virt = vres_GetMap(lastloadedmaplumpnum);
UINT8 *wadData = W_CacheLumpNum(lastloadedmaplumpnum, PU_STATIC);
filelump_t *fileinfo = (filelump_t *)(wadData + ((wadinfo_t *)wadData)->infotableofs); data = (UINT8*) vres_Find(virt, "SIDEDEFS")->data;
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);
for (b = 0; b < (INT16)numsides; b++) for (b = 0; b < (INT16)numsides; b++)
{ {
...@@ -7223,7 +7216,6 @@ void P_SpawnSpecials(INT32 fromnetsave) ...@@ -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); 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 else
I_Error("Make-Your-Own FOF (tag %d) found without a 2nd linedef side!", lines[i].tag); 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) ...@@ -7449,6 +7441,9 @@ void P_SpawnSpecials(INT32 fromnetsave)
} }
} }
if (virt)
vres_Free(virt);
// Allocate each list // Allocate each list
for (i = 0; i < numsectors; i++) for (i = 0; i < numsectors; i++)
if(secthinkers[i].thinkers) if(secthinkers[i].thinkers)
......
...@@ -1600,7 +1600,7 @@ void P_RestoreMusic(player_t *player) ...@@ -1600,7 +1600,7 @@ void P_RestoreMusic(player_t *player)
P_PlayJingle(player, JT_SUPER); P_PlayJingle(player, JT_SUPER);
// Invulnerability // 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); strlcpy(S_sfx[sfx_None].caption, "Invincibility", 14);
S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]); S_StartCaption(sfx_None, -1, player->powers[pw_invulnerability]);
...@@ -4635,7 +4635,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd) ...@@ -4635,7 +4635,7 @@ static void P_DoSpinAbility(player_t *player, ticcmd_t *cmd)
S_StartSound(player->mo, sfx_spin); S_StartSound(player->mo, sfx_spin);
break; 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) #define chargecalculation (6*(player->dashspeed - player->mindash))/(player->maxdash - player->mindash)
fixed_t soundcalculation = chargecalculation; fixed_t soundcalculation = chargecalculation;
...@@ -5128,11 +5128,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) ...@@ -5128,11 +5128,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
boolean elem = ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL); boolean elem = ((player->powers[pw_shield] & SH_NOSTACK) == SH_ELEMENTAL);
player->pflags |= PF_THOKKED|PF_SHIELDABILITY; player->pflags |= PF_THOKKED|PF_SHIELDABILITY;
if (elem) if (elem)
{
player->pflags |= PF_NOJUMPDAMAGE;
P_SetPlayerMobjState(player->mo, S_PLAY_FALL);
S_StartSound(player->mo, sfx_s3k43); S_StartSound(player->mo, sfx_s3k43);
}
else else
{ {
player->pflags &= ~PF_NOJUMPDAMAGE; player->pflags &= ~PF_NOJUMPDAMAGE;
...@@ -5273,7 +5269,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd) ...@@ -5273,7 +5269,7 @@ static void P_DoJumpStuff(player_t *player, ticcmd_t *cmd)
player->secondjump = 0; player->secondjump = 0;
player->pflags &= ~PF_THOKKED; 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)) /*else if (P_SuperReady(player))
{ {
......
...@@ -2320,14 +2320,20 @@ static void ST_drawTeamHUD(void) ...@@ -2320,14 +2320,20 @@ static void ST_drawTeamHUD(void)
p = bflagico; p = bflagico;
else else
p = bmatcico; 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); V_DrawSmallScaledPatch(BASEVIDWIDTH/2 - SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p);
if (gametype == GT_CTF) if (gametype == GT_CTF)
p = rflagico; p = rflagico;
else else
p = rmatcico; 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); V_DrawSmallScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(p->width)/4, 4, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, p);
if (gametype != GT_CTF) if (gametype != GT_CTF)
...@@ -2339,28 +2345,53 @@ static void ST_drawTeamHUD(void) ...@@ -2339,28 +2345,53 @@ static void ST_drawTeamHUD(void)
// Show which flags aren't at base. // Show which flags aren't at base.
for (i = 0; i < MAXPLAYERS; i++) 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); 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); V_DrawScaledPatch(BASEVIDWIDTH/2 + SEP - SHORT(nonicon2->width)/2, 0, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, nonicon2);
whichflag |= players[i].gotflag; whichflag |= players[i].gotflag;
if ((whichflag & (GF_REDFLAG|GF_BLUEFLAG)) == (GF_REDFLAG|GF_BLUEFLAG)) if ((whichflag & (GF_REDFLAG|GF_BLUEFLAG)) == (GF_REDFLAG|GF_BLUEFLAG))
break; // both flags were found, let's stop early break; // both flags were found, let's stop early
} }
// Display a countdown timer showing how much time left until the flag returns to base. // 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))); 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))); V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 8, V_YELLOWMAP|V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", (redflag->fuse / TICRATE)));
} }
} }
num: 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)); 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)); V_DrawCenteredString(BASEVIDWIDTH/2 + SEP, 16, V_HUDTRANS|V_PERPLAYER|V_SNAPTOTOP, va("%u", redscore));
#undef SEP #undef SEP
......
...@@ -1888,3 +1888,101 @@ int W_VerifyNMUSlumps(const char *filename) ...@@ -1888,3 +1888,101 @@ int W_VerifyNMUSlumps(const char *filename)
}; };
return W_VerifyFile(filename, NMUSlist, false); 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 ...@@ -72,6 +72,25 @@ typedef struct
compmethod compression; // lump compression method compmethod compression; // lump compression method
} lumpinfo_t; } 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 // DYNAMIC WAD LOADING
// ========================================================================= // =========================================================================
......