From 83975f3ab0bd6992fd0d6a0cdc0c3c257d7ae099 Mon Sep 17 00:00:00 2001 From: danij Date: Tue, 26 Mar 2013 15:07:44 +0000 Subject: [PATCH] libheretic|Fixed: Errant Firemace spawning/repositioning Also fixed a multiplayer specific bug where clients would spawn a duplicate Firemace locally. --- doomsday/plugins/common/include/p_start.h | 22 +++++- doomsday/plugins/common/src/p_mapsetup.c | 88 ++++++++++++++++++--- doomsday/plugins/common/src/p_start.c | 5 +- doomsday/plugins/heretic/include/acfnlink.h | 5 ++ doomsday/plugins/heretic/include/p_local.h | 6 +- doomsday/plugins/heretic/src/p_inter.c | 16 ++-- doomsday/plugins/heretic/src/p_mobj.c | 43 +++++++--- 7 files changed, 147 insertions(+), 38 deletions(-) diff --git a/doomsday/plugins/common/include/p_start.h b/doomsday/plugins/common/include/p_start.h index 9a686c9221..a206d4c95a 100644 --- a/doomsday/plugins/common/include/p_start.h +++ b/doomsday/plugins/common/include/p_start.h @@ -129,10 +129,10 @@ typedef struct { } playerstart_t; extern uint numMapSpots; -extern mapspot_t* mapSpots; +extern mapspot_t *mapSpots; #if __JHERETIC__ -extern mapspotid_t* maceSpots; +extern mapspotid_t *maceSpots; extern uint maceSpotCount; extern mapspotid_t* bossSpots; extern uint bossSpotCount; @@ -183,7 +183,25 @@ void P_TurnGizmosAwayFromDoors(void); #endif #if __JHERETIC__ +/** + * Add a new map spot to the list of mace spawn spots. + * + * @param id Unique identifier of the map spot to add. + */ void P_AddMaceSpot(mapspotid_t id); + +/** + * Choose a random map spot from the list of mace spawn spots which passes + * validation according to the current game rules configuration. + * + * @note Randomization depends on the seeded playsim RNG. Ensure to call + * this at the correct time otherwise the RNG will "drift", resulting in + * behavior which differs from that of the original game logic. + * + * @return The chosen map spot; otherwise @c 0. + */ +mapspot_t const *P_ChooseRandomMaceSpot(void); + void P_AddBossSpot(mapspotid_t id); #endif diff --git a/doomsday/plugins/common/src/p_mapsetup.c b/doomsday/plugins/common/src/p_mapsetup.c index 7953a7d26d..7885663f78 100644 --- a/doomsday/plugins/common/src/p_mapsetup.c +++ b/doomsday/plugins/common/src/p_mapsetup.c @@ -250,11 +250,11 @@ int applySurfaceColor(void* obj, void* context) } #endif -static boolean checkMapSpotSpawnFlags(const mapspot_t* spot) +static boolean checkMapSpotSpawnFlags(mapspot_t const *spot) { #if __JHEXEN__ /// @todo Move to classinfo_t - static unsigned int classFlags[] = { + static uint classFlags[] = { MSF_FIGHTER, MSF_CLERIC, MSF_MAGE @@ -334,7 +334,7 @@ static boolean P_IsClientAllowedToSpawn(int doomEdNum) /** * Should we auto-spawn one or more mobjs from the specified map spot? */ -static boolean checkMapSpotAutoSpawn(const mapspot_t* spot) +static boolean checkMapSpotAutoSpawn(mapspot_t const *spot) { #if __JHERETIC__ // Ambient sound sequence activator? @@ -560,13 +560,69 @@ static void loadMapSpots(void) } } +#if __JHERETIC__ +mapspot_t const *P_ChooseRandomMaceSpot(void) +{ + uint i, numQualifyingSpots; + uint chosenQualifyingSpotIdx, qualifyingSpotIdx; + + if(!maceSpots || !maceSpotCount) return 0; + + /* + * Pass 1: Determine how many spots qualify given the current game rules. + */ + numQualifyingSpots = 0; + for(i = 0; i < maceSpotCount; ++i) + { + mapspotid_t mapSpotId = maceSpots[i]; + DENG_ASSERT(mapSpots != 0 && mapSpotId < numMapSpots); + { + // Does this spot qualify given the current game configuration? + mapspot_t const *mapSpot = &mapSpots[mapSpotId]; + if(checkMapSpotSpawnFlags(mapSpot)) + numQualifyingSpots += 1; + } + } + if(!numQualifyingSpots) return 0; + + /* + * Pass 2: Choose and locate the chosen spot. + */ + chosenQualifyingSpotIdx = P_Random() % numQualifyingSpots; + qualifyingSpotIdx = 0; + for(i = 0; i < maceSpotCount; ++i) + { + mapspotid_t mapSpotId = maceSpots[i]; + mapspot_t const *mapSpot = &mapSpots[mapSpotId]; + + if(!checkMapSpotSpawnFlags(mapSpot)) + continue; + + if(qualifyingSpotIdx != chosenQualifyingSpotIdx) + { + qualifyingSpotIdx++; + continue; + } + +#if _DEBUG + Con_Message("P_ChooseRandomMaceSpot: Chosen map spot id:%u.", mapSpotId); +#endif + return mapSpot; + } + + // Unreachable. + DENG_ASSERT(false); + return 0; +} +#endif // __JHERETIC__ + static void spawnMapObjects(void) { uint i; for(i = 0; i < numMapSpots; ++i) { - const mapspot_t* spot = &mapSpots[i]; + mapspot_t const *spot = &mapSpots[i]; mobjtype_t type; // Not all map spots spawn mobjs on map load. @@ -579,7 +635,7 @@ static void spawnMapObjects(void) type = P_DoomEdNumToMobjType(spot->doomEdNum); if(type != MT_NONE) { - mobj_t* mo; + mobj_t *mo; // Check for things that clients don't spawn on their own. if(IS_CLIENT) @@ -635,15 +691,23 @@ static void spawnMapObjects(void) } #if __JHERETIC__ - if(maceSpotCount) + // Spawn a Firemace? + if(!IS_CLIENT && maceSpotCount) { - // Sometimes doesn't show up if not in deathmatch. + // Sometimes the Firemace doesn't show up if not in deathmatch. if(!(!deathmatch && P_Random() < 64)) { - const mapspot_t* spot = &mapSpots[maceSpots[P_Random() % maceSpotCount]]; + mapspot_t const *spot = P_ChooseRandomMaceSpot(); + if(spot) + { +# if _DEBUG + Con_Message("spawnMapObjects: Spawning Firemace at (%.2f, %.2f, %.2f).", + spot->origin[VX], spot->origin[VY], spot->origin[VZ]); +# endif - P_SpawnMobjXYZ(MT_WMACE, spot->origin[VX], spot->origin[VY], 0, - spot->angle, MSF_Z_FLOOR); + P_SpawnMobjXYZ(MT_WMACE, spot->origin[VX], spot->origin[VY], 0, + spot->angle, MSF_Z_FLOOR); + } } } #endif @@ -829,9 +893,9 @@ static void P_ResetWorldState(void) #if __JHERETIC__ maceSpotCount = 0; - maceSpots = NULL; + maceSpots = 0; bossSpotCount = 0; - bossSpots = NULL; + bossSpots = 0; #endif P_PurgeDeferredSpawns(); diff --git a/doomsday/plugins/common/src/p_start.c b/doomsday/plugins/common/src/p_start.c index 4dfd7c7171..c81005d50e 100644 --- a/doomsday/plugins/common/src/p_start.c +++ b/doomsday/plugins/common/src/p_start.c @@ -79,7 +79,7 @@ mapspot_t* mapSpots; #if __JHERETIC__ uint maceSpotCount; -mapspotid_t* maceSpots; +mapspotid_t *maceSpots; uint bossSpotCount; mapspotid_t* bossSpots; #endif @@ -973,6 +973,9 @@ boolean P_CheckSpot(coord_t x, coord_t y) #if __JHERETIC__ void P_AddMaceSpot(mapspotid_t id) { +#ifdef _DEBUG + Con_Message("P_AddMaceSpot: Added mace spot %u", id); +#endif maceSpots = Z_Realloc(maceSpots, sizeof(mapspotid_t) * ++maceSpotCount, PU_MAP); maceSpots[maceSpotCount-1] = id; } diff --git a/doomsday/plugins/heretic/include/acfnlink.h b/doomsday/plugins/heretic/include/acfnlink.h index a8d356c1f6..7055bd320c 100644 --- a/doomsday/plugins/heretic/include/acfnlink.h +++ b/doomsday/plugins/heretic/include/acfnlink.h @@ -131,7 +131,12 @@ void C_DECL A_Raise(); void C_DECL A_ReFire(); void C_DECL A_RemovePod(); void C_DECL A_RestoreArtifact(); + +/** + * Make a special 'thing' visible again. + */ void C_DECL A_RestoreSpecialThing1(); + void C_DECL A_RestoreSpecialThing2(); void C_DECL A_Scream(); void C_DECL A_ShutdownPhoenixPL2(); diff --git a/doomsday/plugins/heretic/include/p_local.h b/doomsday/plugins/heretic/include/p_local.h index e5c567073d..d79bc0b971 100644 --- a/doomsday/plugins/heretic/include/p_local.h +++ b/doomsday/plugins/heretic/include/p_local.h @@ -93,7 +93,11 @@ #define USE_MACE_AMMO_1 1 #define USE_MACE_AMMO_2 5 -void P_RepositionMace(mobj_t* mo); +/** + * Chooses the next spot to place the mace. + */ +void P_RepositionMace(mobj_t *mo); + void P_SetPsprite(player_t* player, int position, statenum_t stnum); void P_SetupPsprites(player_t* curplayer); diff --git a/doomsday/plugins/heretic/src/p_inter.c b/doomsday/plugins/heretic/src/p_inter.c index b9d3654e21..5d70506fa5 100644 --- a/doomsday/plugins/heretic/src/p_inter.c +++ b/doomsday/plugins/heretic/src/p_inter.c @@ -378,18 +378,16 @@ void P_HideSpecialThing(mobj_t* thing) P_MobjChangeState(thing, S_HIDESPECIAL1); } -/** - * Make a special thing visible again. - */ -void C_DECL A_RestoreSpecialThing1(mobj_t* thing) +void C_DECL A_RestoreSpecialThing1(mobj_t *mo) { - if(thing->type == MT_WMACE) - { // Do random mace placement. - P_RepositionMace(thing); + if(mo->type == MT_WMACE) + { + // Do random mace placement. + P_RepositionMace(mo); } - thing->flags2 &= ~MF2_DONTDRAW; - S_StartSound(SFX_RESPAWN, thing); + mo->flags2 &= ~MF2_DONTDRAW; + S_StartSound(SFX_RESPAWN, mo); } void C_DECL A_RestoreSpecialThing2(mobj_t* thing) diff --git a/doomsday/plugins/heretic/src/p_mobj.c b/doomsday/plugins/heretic/src/p_mobj.c index 41d729c84b..c9f5a64ade 100644 --- a/doomsday/plugins/heretic/src/p_mobj.c +++ b/doomsday/plugins/heretic/src/p_mobj.c @@ -1141,25 +1141,42 @@ mobj_t* P_SpawnMobj(mobjtype_t type, coord_t const pos[3], angle_t angle, int sp return P_SpawnMobjXYZ(type, pos[VX], pos[VY], pos[VZ], angle, spawnFlags); } -/** - * Chooses the next spot to place the mace. - */ -void P_RepositionMace(mobj_t* mo) +void P_RepositionMace(mobj_t *mo) { - mapspotid_t spot; - BspLeaf* bspLeaf; + mapspot_t const *mapSpot; + BspLeaf *bspLeaf; + + DENG_ASSERT(mo && mo->type == MT_WMACE); +#if _DEBUG + Con_Message("P_RepositionMace: Repositioning mobj [%p], thinkerId:%i.", mo, mo->thinker.id); +#endif + + mapSpot = P_ChooseRandomMaceSpot(); + if(!mapSpot) + { +#if _DEBUG + Con_Message("P_RepositionMace: Failed to choose a map spot, aborting..."); +#endif + return; + } P_MobjUnsetOrigin(mo); - spot = maceSpots[P_Random() % maceSpotCount]; - mo->origin[VX] = mapSpots[spot].origin[VX]; - mo->origin[VY] = mapSpots[spot].origin[VY]; - bspLeaf = P_BspLeafAtPoint(mo->origin); + { + mo->origin[VX] = mapSpot->origin[VX]; + mo->origin[VY] = mapSpot->origin[VY]; + bspLeaf = P_BspLeafAtPoint(mo->origin); - mo->floorZ = P_GetDoublep(bspLeaf, DMU_CEILING_HEIGHT); - mo->origin[VZ] = mo->floorZ; + mo->floorZ = P_GetDoublep(bspLeaf, DMU_CEILING_HEIGHT); + mo->origin[VZ] = mo->floorZ; - mo->ceilingZ = P_GetDoublep(bspLeaf, DMU_CEILING_HEIGHT); + mo->ceilingZ = P_GetDoublep(bspLeaf, DMU_CEILING_HEIGHT); + } P_MobjSetOrigin(mo); + +#if _DEBUG + Con_Message("P_RepositionMace: Mobj [%p], thinkerId:%i - now at (%.2f, %.2f, %.2f).", + mo, mo->thinker.id, mo->origin[VX], mo->origin[VY], mo->origin[VZ]); +#endif } void P_SpawnPuff(coord_t x, coord_t y, coord_t z, angle_t angle)