Skip to content

Commit

Permalink
libdoom: Use map URIs to determine A_BossDeath special triggers
Browse files Browse the repository at this point in the history
  • Loading branch information
danij-deng committed Jul 24, 2014
1 parent 3da142c commit 1c359db
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 174 deletions.
212 changes: 81 additions & 131 deletions doomsday/plugins/doom/src/p_enemy.c
Expand Up @@ -1546,161 +1546,111 @@ void C_DECL A_Explode(mobj_t *mo)
P_RadiusAttack(mo, mo->target, 128, 127);
}

typedef enum {
ST_SPAWN_FLOOR,
ST_SPAWN_DOOR,
ST_LEAVEMAP
} SpecialType;

/// @todo Should be defined in MapInfo.
typedef struct {
int gameModeBits;
char const *mapPath;
dd_bool compatAnyBoss; ///< @c true= type requirement optional by compat option.
mobjtype_t bossType;
//dd_bool massacreOnDeath;
SpecialType special;
int tag;
int type;
} BossTrigger;

/**
* Trigger special effects on certain maps if all "bosses" are dead.
*
* @note DOOM ver 1.9 behavoir change:
* @see http://doomwiki.org/wiki/Tag_666#Difference_in_behaviour_between_Doom1_and_Ultimate_Doom
*/
void C_DECL A_BossDeath(mobj_t *mo)
{
int i;
countmobjworker_params_t parm;

if(gameModeBits & GM_ANY_DOOM2)
{
if(G_CurrentMapNumber() != 6)
return;
if(mo->type != MT_FATSO && mo->type != MT_BABY)
return;
}
/*
* DOOM ver 1.9 behavioral change:
* Many classic PWADS such as "Doomsday of UAC" (UAC_DEAD.wad) rely on the
* old behavior. Episode 4 is exempt by PrBoom's precedent.
*/
else if(cfg.anyBossDeath && gameEpisode < 3)
static BossTrigger const bossTriggers[] =
{
if(G_CurrentMapNumber() != 7)
return;
{ GM_ANY_DOOM2, "MAP07", false, MT_FATSO, ST_SPAWN_FLOOR, 666, (int)FT_LOWERTOLOWEST },
{ GM_ANY_DOOM2, "MAP07", false, MT_BABY, ST_SPAWN_FLOOR, 667, (int)FT_RAISETOTEXTURE },
{ GM_ANY_DOOM, "E1M8", true, MT_BRUISER, ST_SPAWN_FLOOR, 666, (int)FT_LOWERTOLOWEST },
{ GM_ANY_DOOM, "E2M8", true, MT_CYBORG, ST_LEAVEMAP, 0, 0 },
{ GM_ANY_DOOM, "E3M8", true, MT_SPIDER, ST_LEAVEMAP, 0, 0 },
{ GM_ANY_DOOM, "E4M6", false, MT_CYBORG, ST_SPAWN_DOOR, 666, (int)DT_BLAZEOPEN },
{ GM_ANY_DOOM, "E4M8", false, MT_SPIDER, ST_SPAWN_FLOOR, 666, (int)FT_LOWERTOLOWEST }
};
static int const numBossTriggers = sizeof(bossTriggers) / sizeof(bossTriggers[0]);

if(gameEpisode != 0 && mo->type == MT_BRUISER)
return;
}
else
{
switch(gameEpisode)
{
case 0:
if(G_CurrentMapNumber() != 7)
return;

if(mo->type != MT_BRUISER)
return;
break;

case 1:
if(G_CurrentMapNumber() != 7)
return;

if(mo->type != MT_CYBORG)
return;
break;

case 2:
if(G_CurrentMapNumber() != 7)
return;

if(mo->type != MT_SPIDER)
return;

break;

case 3:
switch(G_CurrentMapNumber())
{
case 5:
if(mo->type != MT_CYBORG)
return;
break;

case 7:
if(mo->type != MT_SPIDER)
return;
break;

default:
return;
}
break;
Str const *currentMapPath = Uri_Path(G_CurrentMapUri());

default:
if(G_CurrentMapNumber() != 7)
return;
break;
}
}

// Make sure there is a player alive for victory...
// Make sure there is a player alive.
int i;
for(i = 0; i < MAXPLAYERS; ++i)
{
if(players[i].plr->inGame && players[i].health > 0)
break;
}
if(i == MAXPLAYERS) return;

if(i == MAXPLAYERS)
return; // No one left alive, so do not end game.
for(i = 0; i < numBossTriggers; ++i)
{
BossTrigger const *trigger = &bossTriggers[i];

// Scan the remaining thinkers to see if all bosses are dead.
parm.excludeMobj = mo;
parm.type = mo->type;
parm.minHealth = 1;
if(!(trigger->gameModeBits & gameModeBits)) continue;

if(!noMobjRemains(&parm))
return; // Other boss not dead.
// Mobj type requirement change in DOOM ver 1.9
if(!(cfg.anyBossDeath && trigger->compatAnyBoss))
{
// Not a boss on this map?
if(mo->type != trigger->bossType) continue;
}

// Victory!
if(gameModeBits & GM_ANY_DOOM2)
{
if(G_CurrentMapNumber() == 6)
if(Str_CompareIgnoreCase(currentMapPath, trigger->mapPath)) continue;

// Scan the remaining thinkers to determine if this is indeed the last boss.
{
if(mo->type == MT_FATSO)
{
Line *dummyLine = P_AllocDummyLine();
P_ToXLine(dummyLine)->tag = 666;
EV_DoFloor(dummyLine, FT_LOWERTOLOWEST);
P_FreeDummyLine(dummyLine);
return;
}
countmobjworker_params_t parm;
parm.excludeMobj = mo;
parm.type = mo->type;
parm.minHealth = 1;

if(mo->type == MT_BABY)
{
Line *dummyLine = P_AllocDummyLine();
P_ToXLine(dummyLine)->tag = 667;
EV_DoFloor(dummyLine, FT_RAISETOTEXTURE);
P_FreeDummyLine(dummyLine);
return;
}
// Anything left alive?
if(!noMobjRemains(&parm)) continue;
}
}
else
{
if(gameEpisode == 0)

// Kill all remaining enemies?
/*if(trigger->massacreOnDeath)
{
P_Massacre();
}*/

// Trigger the special.
switch(trigger->special)
{
case ST_SPAWN_FLOOR: {
Line *dummyLine = P_AllocDummyLine();
P_ToXLine(dummyLine)->tag = 666;
EV_DoFloor(dummyLine, FT_LOWERTOLOWEST);
P_ToXLine(dummyLine)->tag = trigger->tag;
EV_DoFloor(dummyLine, (floortype_e)trigger->type);
P_FreeDummyLine(dummyLine);
return;
}
break; }

if(gameEpisode == 3)
{
if(G_CurrentMapNumber() == 5)
{
Line *dummyLine = P_AllocDummyLine();
P_ToXLine(dummyLine)->tag = 666;
EV_DoDoor(dummyLine, DT_BLAZEOPEN);
P_FreeDummyLine(dummyLine);
return;
}
case ST_SPAWN_DOOR: {
Line *dummyLine = P_AllocDummyLine();
P_ToXLine(dummyLine)->tag = trigger->tag;
EV_DoDoor(dummyLine, (doortype_e)trigger->type);
P_FreeDummyLine(dummyLine);
break; }

if(G_CurrentMapNumber() == 7)
{
Line *dummyLine = P_AllocDummyLine();
P_ToXLine(dummyLine)->tag = 666;
EV_DoFloor(dummyLine, FT_LOWERTOLOWEST);
P_FreeDummyLine(dummyLine);
return;
}
case ST_LEAVEMAP:
G_SetGameActionMapCompletedAndSetNextMap();
break;

default: DENG_ASSERT(!"A_BossDeath: Unknown trigger special type");
}
}

G_SetGameActionMapCompletedAndSetNextMap();
}

void C_DECL A_Hoof(mobj_t *mo)
Expand Down
105 changes: 62 additions & 43 deletions doomsday/plugins/heretic/src/p_enemy.c
Expand Up @@ -2102,71 +2102,90 @@ static int countMobjOfType(thinker_t *th, void *context)
return false; // Continue iteration.
}

typedef enum {
ST_SPAWN_FLOOR,
//ST_SPAWN_DOOR,
ST_LEAVEMAP
} SpecialType;

/// @todo Should be defined in MapInfo.
typedef struct {
//int gameModeBits;
char const *mapPath;
//dd_bool compatAnyBoss; ///< @c true= type requirement optional by compat option.
mobjtype_t bossType;
dd_bool massacreOnDeath;
} BossMap;
SpecialType special;
int tag;
int type;
} BossTrigger;

/**
* Trigger special effects on certain maps if all "bosses" are dead.
*/
void C_DECL A_BossDeath(mobj_t *actor)
{
static BossMap const bossMaps[] =
static BossTrigger const bossTriggers[] =
{
{ "E1M8", MT_HEAD, false },
{ "E2M8", MT_MINOTAUR, true },
{ "E3M8", MT_SORCERER2, true },
{ "E4M8", MT_HEAD, true },
{ "E5M8", MT_MINOTAUR, true },
{ "", MT_NONE, false }
{ "E1M8", MT_HEAD, false, ST_SPAWN_FLOOR, 666, FT_LOWER },
{ "E2M8", MT_MINOTAUR, true, ST_SPAWN_FLOOR, 666, FT_LOWER },
{ "E3M8", MT_SORCERER2, true, ST_SPAWN_FLOOR, 666, FT_LOWER },
{ "E4M8", MT_HEAD, true, ST_SPAWN_FLOOR, 666, FT_LOWER },
{ "E5M8", MT_MINOTAUR, true, ST_SPAWN_FLOOR, 666, FT_LOWER },
};
static int const numBossMaps = sizeof(bossMaps) / sizeof(bossMaps[0]);
static int const numBossTriggers = sizeof(bossTriggers) / sizeof(bossTriggers[0]);

Str const *currentMapPath = Uri_Path(G_CurrentMapUri());
BossMap const *bossMap = 0;
int i;
for(i = 0; i < numBossMaps; ++i)
Str const *currentMapPath = Uri_Path(G_CurrentMapUri());
for(i = 0; i < numBossTriggers; ++i)
{
if(!Str_CompareIgnoreCase(currentMapPath, bossMaps[i].mapPath))
{
bossMap = &bossMaps[i];
break;
}
}
BossTrigger const *trigger = &bossTriggers[i];

// Not a boss map?
if(!bossMap) return;
// Not a boss on this map?
if(actor->type != trigger->bossType) continue;

// Not a boss on this map?
if(actor->type != bossMap->bossType)
return;
if(Str_CompareIgnoreCase(currentMapPath, trigger->mapPath)) continue;

// Scan the remaining thinkers to determine if this is indeed the last boss.
{
countmobjoftypeparams_t parm;
parm.type = actor->type;
parm.count = 0;
Thinker_Iterate(P_MobjThinker, countMobjOfType, &parm);
// Scan the remaining thinkers to determine if this is indeed the last boss.
{
countmobjoftypeparams_t parm;
parm.type = actor->type;
parm.count = 0;
Thinker_Iterate(P_MobjThinker, countMobjOfType, &parm);

// Anything left alive?
if(parm.count) return;
}
// Anything left alive?
if(parm.count) continue;
}

// Kill all remaining enemies?
if(bossMap->massacreOnDeath)
{
P_Massacre();
}
// Kill all remaining enemies?
if(trigger->massacreOnDeath)
{
P_Massacre();
}

// Trigger the '666' line special.
{
Line *dummyLine = P_AllocDummyLine();
P_ToXLine(dummyLine)->tag = 666;
EV_DoFloor(dummyLine, FT_LOWER);
P_FreeDummyLine(dummyLine);
// Trigger the special.
switch(trigger->special)
{
case ST_SPAWN_FLOOR: {
Line *dummyLine = P_AllocDummyLine();
P_ToXLine(dummyLine)->tag = trigger->tag;
EV_DoFloor(dummyLine, (floortype_e)trigger->type);
P_FreeDummyLine(dummyLine);
break; }

/*case ST_SPAWN_DOOR: {
Line *dummyLine = P_AllocDummyLine();
P_ToXLine(dummyLine)->tag = trigger->tag;
EV_DoDoor(dummyLine, (doortype_e)trigger->type);
P_FreeDummyLine(dummyLine);
break; }*/

case ST_LEAVEMAP:
G_SetGameActionMapCompletedAndSetNextMap();
break;

default: DENG_ASSERT(!"A_BossDeath: Unknown trigger special type");
}
}
}

Expand Down

0 comments on commit 1c359db

Please sign in to comment.