Add MFE_TEAMFLAG

This commit is contained in:
Lactozilla 2023-08-06 19:03:13 -03:00
parent b0ebb24eb6
commit 0021fd1680
8 changed files with 192 additions and 125 deletions

View file

@ -3690,6 +3690,7 @@ const char *const MOBJTYPE_LIST[] = { // array length left dynamic for sanity t
"MT_TOKEN", // Special Stage token for special stage "MT_TOKEN", // Special Stage token for special stage
"MT_REDFLAG", // Red CTF Flag "MT_REDFLAG", // Red CTF Flag
"MT_BLUEFLAG", // Blue CTF Flag "MT_BLUEFLAG", // Blue CTF Flag
"MT_TEAMFLAG", // Team flag
"MT_EMBLEM", "MT_EMBLEM",
"MT_EMERALD1", "MT_EMERALD1",
"MT_EMERALD2", "MT_EMERALD2",
@ -4407,6 +4408,7 @@ const char *const MOBJEFLAG_LIST[] = {
"TRACERANGLE", // Compute and trigger on mobj angle relative to tracer "TRACERANGLE", // Compute and trigger on mobj angle relative to tracer
"FORCESUPER", // Forces an object to use super sprites with SPR_PLAY. "FORCESUPER", // Forces an object to use super sprites with SPR_PLAY.
"FORCENOSUPER", // Forces an object to NOT use super sprites with SPR_PLAY. "FORCENOSUPER", // Forces an object to NOT use super sprites with SPR_PLAY.
"TEAMFLAG", // Object is a team flag
NULL NULL
}; };

View file

@ -7149,6 +7149,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] =
S_NULL // raisestate S_NULL // raisestate
}, },
{ // MT_TEAMFLAG
323, // doomednum
S_NULL, // spawnstate
1000, // spawnhealth
S_NULL, // seestate
sfx_None, // seesound
8, // reactiontime
sfx_None, // attacksound
S_NULL, // painstate
0, // painchance
sfx_None, // painsound
S_NULL, // meleestate
S_NULL, // missilestate
S_NULL, // deathstate
S_NULL, // xdeathstate
sfx_lvpass, // deathsound
8, // speed
24*FRACUNIT, // radius
64*FRACUNIT, // height
0, // display offset
0, // mass
0, // damage
sfx_None, // activesound
MF_SPECIAL, // flags
S_NULL // raisestate
},
{ // MT_EMBLEM { // MT_EMBLEM
322, // doomednum 322, // doomednum
S_EMBLEM1, // spawnstate S_EMBLEM1, // spawnstate

View file

@ -4521,6 +4521,7 @@ typedef enum mobj_type
MT_TOKEN, // Special Stage token for special stage MT_TOKEN, // Special Stage token for special stage
MT_REDFLAG, // Red CTF Flag MT_REDFLAG, // Red CTF Flag
MT_BLUEFLAG, // Blue CTF Flag MT_BLUEFLAG, // Blue CTF Flag
MT_TEAMFLAG, // Team flag
MT_EMBLEM, MT_EMBLEM,
MT_EMERALD1, MT_EMERALD1,
MT_EMERALD2, MT_EMERALD2,

View file

@ -552,6 +552,60 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
P_DamageMobj(toucher, special, special, 1, DMG_FIRE); P_DamageMobj(toucher, special, special, 1, DMG_FIRE);
return; return;
} }
// CTF Flags
else if (special->eflags & MFE_TEAMFLAG)
{
if (player->bot && player->bot != BOT_MPAI)
return;
if (player->powers[pw_flashing] || player->tossdelay)
return;
if (!special->spawnpoint)
return;
if (special->fuse == 1)
return;
if (special->extravalue1 > TEAM_NONE && special->extravalue1 < numteams)
{
UINT8 flagteam = special->extravalue1;
sectorspecialflags_t specialflag = flagteam == TEAM_RED ? SSF_REDTEAMBASE : SSF_BLUETEAMBASE;
const char *flagtext;
const char *flagcolor;
char plname[MAXPLAYERNAME+4];
flagtext = G_GetTeamFlagName(flagteam);
flagcolor = GetChatColorForSkincolor(G_GetTeamColor(flagteam));
snprintf(plname, sizeof(plname), "%s%s%s",
CTFTEAMCODE(player),
player_names[player - players],
CTFTEAMENDCODE(player));
if (player->ctfteam == flagteam) // Player is on the same team as the flag
{
// Ignore height, only check x/y for now
// avoids stupid problems with some flags constantly returning
if (special->x>>FRACBITS != special->spawnpoint->x
|| special->y>>FRACBITS != special->spawnpoint->y)
{
special->fuse = 1;
special->flags2 |= MF2_JUSTATTACKED;
if (!P_PlayerTouchingSectorSpecialFlag(player, specialflag))
CONS_Printf(M_GetText("%s returned the %s%s%c to base.\n"), plname, flagcolor, flagtext, 0x80);
}
return;
}
else if (player->ctfteam) // Player is on the other team (and not a spectator)
{
if (player->powers[pw_super])
return;
player->gotflag |= teams[flagteam].flag;
CONS_Printf(M_GetText("%s picked up the %s%s%c!\n"), plname, flagcolor, flagtext, 0x80);
P_SetTarget(&flagmobjs[flagteam], NULL);
}
}
else
return;
}
else else
{ {
// We now identify by object type, not sprite! Tails 04-11-2001 // We now identify by object type, not sprite! Tails 04-11-2001
@ -833,68 +887,6 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck)
} }
} }
// CTF Flags
case MT_REDFLAG:
case MT_BLUEFLAG:
if (player->bot && player->bot != BOT_MPAI)
return;
if (player->powers[pw_flashing] || player->tossdelay)
return;
if (!special->spawnpoint)
return;
if (special->fuse == 1)
return;
// if (special->momz > 0)
// return;
if (special->info->mass < numteams)
{
UINT8 flagteam = special->info->mass;
sectorspecialflags_t specialflag = flagteam == TEAM_RED ? SSF_REDTEAMBASE : SSF_BLUETEAMBASE;
const char *flagtext;
const char *flagcolor;
char plname[MAXPLAYERNAME+4];
flagtext = G_GetTeamFlagName(flagteam);
flagcolor = GetChatColorForSkincolor(G_GetTeamColor(flagteam));
snprintf(plname, sizeof(plname), "%s%s%s",
CTFTEAMCODE(player),
player_names[player - players],
CTFTEAMENDCODE(player));
if (player->ctfteam == flagteam) // Player is on the same team as the flag
{
// Ignore height, only check x/y for now
// avoids stupid problems with some flags constantly returning
if (special->x>>FRACBITS != special->spawnpoint->x
|| special->y>>FRACBITS != special->spawnpoint->y)
{
special->fuse = 1;
special->flags2 |= MF2_JUSTATTACKED;
if (!P_PlayerTouchingSectorSpecialFlag(player, specialflag))
{
CONS_Printf(M_GetText("%s returned the %s%s%c to base.\n"), plname, flagcolor, flagtext, 0x80);
// The fuse code plays this sound effect
//if (players[consoleplayer].ctfteam == player->ctfteam)
// S_StartSound(NULL, sfx_hoop1);
}
}
}
else if (player->ctfteam) // Player is on the other team (and not a spectator)
{
if (player->powers[pw_super])
return;
player->gotflag |= teams[flagteam].flag;
CONS_Printf(M_GetText("%s picked up the %s%s%c!\n"), plname, flagcolor, flagtext, 0x80);
P_SetTarget(&flagmobjs[flagteam], NULL);
// code for dealing with abilities is handled elsewhere now
break;
}
}
return;
// ********************************** // // ********************************** //
// NiGHTS gameplay items and powerups // // NiGHTS gameplay items and powerups //
// ********************************** // // ********************************** //
@ -4389,13 +4381,16 @@ void P_PlayerFlagBurst(player_t *player, boolean toss)
if (!player->gotflag) if (!player->gotflag)
return; return;
for (UINT8 team = TEAM_RED; team < numteams; team++) for (UINT8 i = 1; i < numteams; i++)
{ {
UINT8 team = G_GetTeam(i);
UINT32 flagflag = 1 << (team - 1); UINT32 flagflag = 1 << (team - 1);
if (!(player->gotflag & flagflag)) if (!(player->gotflag & flagflag))
continue; continue;
mobj_t *flag = P_SpawnMobj(player->mo->x, player->mo->y, player->mo->z, teams[team].flag_mobj_type); mobj_t *flag = P_SpawnTeamFlag(team, player->mo->x, player->mo->y, player->mo->z);
if (flag == NULL)
continue;
if (player->mo->eflags & MFE_VERTICALFLIP) if (player->mo->eflags & MFE_VERTICALFLIP)
{ {

View file

@ -338,6 +338,7 @@ FUNCMATH boolean P_WeaponOrPanel(mobjtype_t type);
mobj_t *P_GetTeamFlag(UINT8 team); mobj_t *P_GetTeamFlag(UINT8 team);
mapthing_t *P_GetTeamFlagMapthing(UINT8 team); mapthing_t *P_GetTeamFlagMapthing(UINT8 team);
mobj_t *P_SpawnTeamFlag(UINT8 team, fixed_t x, fixed_t y, fixed_t z);
void P_CalcChasePostImg(player_t *player, camera_t *thiscam); void P_CalcChasePostImg(player_t *player, camera_t *thiscam);
boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled); boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled);

View file

@ -44,6 +44,10 @@ actioncache_t actioncachehead;
static mobj_t *overlaycap = NULL; static mobj_t *overlaycap = NULL;
#define MAXHUNTEMERALDS 64
mapthing_t *huntemeralds[MAXHUNTEMERALDS];
INT32 numhuntemeralds;
void P_InitCachedActions(void) void P_InitCachedActions(void)
{ {
actioncachehead.prev = actioncachehead.next = &actioncachehead; actioncachehead.prev = actioncachehead.next = &actioncachehead;
@ -2428,15 +2432,6 @@ boolean P_ZMovement(mobj_t *mo)
return false; return false;
} }
break; break;
case MT_REDFLAG:
case MT_BLUEFLAG:
// Remove from death pits. DON'T FUCKING DESPAWN IT DAMMIT
if (P_CheckDeathPitCollide(mo))
{
mo->fuse = 1;
return false;
}
break;
case MT_RING: // Ignore still rings case MT_RING: // Ignore still rings
case MT_COIN: case MT_COIN:
@ -2497,6 +2492,12 @@ boolean P_ZMovement(mobj_t *mo)
} }
break; break;
default: default:
// Respawn flags whenever they hit a death pit
if (mo->eflags & MFE_TEAMFLAG && P_CheckDeathPitCollide(mo))
{
mo->fuse = 1;
return false;
}
break; break;
} }
@ -2793,7 +2794,7 @@ boolean P_ZMovement(mobj_t *mo)
mo->momz = -mo->momz; mo->momz = -mo->momz;
else else
// Flags bounce // Flags bounce
if (mo->type == MT_REDFLAG || mo->type == MT_BLUEFLAG) if (mo->eflags & MFE_TEAMFLAG)
{ {
if (maptol & TOL_NIGHTS) if (maptol & TOL_NIGHTS)
mo->momz = -FixedDiv(mo->momz, 10*FRACUNIT); mo->momz = -FixedDiv(mo->momz, 10*FRACUNIT);
@ -9762,11 +9763,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
if (!P_TurretThink(mobj)) if (!P_TurretThink(mobj))
return false; return false;
break; break;
case MT_BLUEFLAG:
case MT_REDFLAG:
if (P_MobjTouchingSectorSpecialFlag(mobj, SSF_RETURNFLAG))
mobj->fuse = 1; // Return to base.
break;
case MT_SPINDUST: // Spindash dust case MT_SPINDUST: // Spindash dust
mobj->momx = FixedMul(mobj->momx, (3*FRACUNIT)/4); // originally 50000 mobj->momx = FixedMul(mobj->momx, (3*FRACUNIT)/4); // originally 50000
mobj->momy = FixedMul(mobj->momy, (3*FRACUNIT)/4); // same mobj->momy = FixedMul(mobj->momy, (3*FRACUNIT)/4); // same
@ -9894,6 +9890,13 @@ static boolean P_MobjRegularThink(mobj_t *mobj)
} }
/* FALLTHRU */ /* FALLTHRU */
default: default:
// Return team flags to base whenever they touch sectors that return team flags
if (mobj->eflags & MFE_TEAMFLAG)
{
if (P_MobjTouchingSectorSpecialFlag(mobj, SSF_RETURNFLAG))
mobj->fuse = 1; // Return to base.
}
// check mobj against possible water content, before movement code // check mobj against possible water content, before movement code
P_MobjCheckWater(mobj); P_MobjCheckWater(mobj);
@ -10058,6 +10061,12 @@ static boolean P_FuseThink(mobj_t *mobj)
P_MonitorFuseThink(mobj); P_MonitorFuseThink(mobj);
return false; return false;
} }
else if (mobj->eflags & MFE_TEAMFLAG)
{
P_FlagFuseThink(mobj);
P_RemoveMobj(mobj);
return false;
}
else switch (mobj->type) else switch (mobj->type)
{ {
// gargoyle and snowman handled in P_PushableThinker, not here // gargoyle and snowman handled in P_PushableThinker, not here
@ -10068,11 +10077,6 @@ static boolean P_FuseThink(mobj_t *mobj)
case MT_LHRT: case MT_LHRT:
P_KillMobj(mobj, NULL, NULL, 0); P_KillMobj(mobj, NULL, NULL, 0);
break; break;
case MT_BLUEFLAG:
case MT_REDFLAG:
P_FlagFuseThink(mobj);
P_RemoveMobj(mobj);
return false;
case MT_FANG: case MT_FANG:
if (mobj->flags2 & MF2_SLIDEPUSH) if (mobj->flags2 & MF2_SLIDEPUSH)
{ {
@ -10549,8 +10553,6 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing)
case MT_REDTEAMRING: case MT_REDTEAMRING:
case MT_BLUETEAMRING: case MT_BLUETEAMRING:
case MT_REDFLAG:
case MT_BLUEFLAG:
case MT_EMBLEM: case MT_EMBLEM:
@ -10589,8 +10591,9 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing)
return FRACUNIT; return FRACUNIT;
default: default:
if (thing->eflags & MFE_TEAMFLAG)
if (thing->flags & (MF_ENEMY|MF_BOSS)) return 2*FRACUNIT/3;
else if (thing->flags & (MF_ENEMY|MF_BOSS))
return FRACUNIT; return FRACUNIT;
else else
return 0; return 0;
@ -11829,10 +11832,6 @@ void P_MovePlayerToStarpost(INT32 playernum)
leveltime = p->starposttime; leveltime = p->starposttime;
} }
#define MAXHUNTEMERALDS 64
mapthing_t *huntemeralds[MAXHUNTEMERALDS];
INT32 numhuntemeralds;
fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const boolean flip, const fixed_t scale) fixed_t P_GetMobjSpawnHeight(const mobjtype_t mobjtype, const fixed_t x, const fixed_t y, const fixed_t dz, const fixed_t offset, const boolean flip, const fixed_t scale)
{ {
const subsector_t *ss = R_PointInSubsector(x, y); const subsector_t *ss = R_PointInSubsector(x, y);
@ -11962,7 +11961,8 @@ static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing)
return true; return true;
} }
else if (metalrecording && mthing->type == mobjinfo[MT_METALSONIC_RACE].doomednum) else if (metalrecording && mthing->type == mobjinfo[MT_METALSONIC_RACE].doomednum)
{ // If recording, you ARE Metal Sonic. Do not spawn it, do not save normal spawnpoints. {
// If recording, you ARE Metal Sonic. Do not spawn it, do not save normal spawnpoints.
playerstarts[0] = mthing; playerstarts[0] = mthing;
return true; return true;
} }
@ -12061,13 +12061,13 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i)
if (!(gametyperules & GTR_TEAMFLAGS)) // CTF specific things if (!(gametyperules & GTR_TEAMFLAGS)) // CTF specific things
{ {
if (i == MT_BLUEFLAG || i == MT_REDFLAG) if (i == MT_BLUEFLAG || i == MT_REDFLAG || i == MT_TEAMFLAG)
return false; // No flags in non-CTF modes! return false; // No flags in non-CTF modes!
} }
else if (i == MT_BLUEFLAG || i == MT_REDFLAG) else if (i == MT_BLUEFLAG || i == MT_REDFLAG || i == MT_TEAMFLAG)
{ {
UINT8 team = mobjinfo[i].mass; UINT8 team = i == MT_TEAMFLAG ? mthing->args[0] : mobjinfo[i].mass;
if (team >= numteams) if (team == TEAM_NONE || team >= numteams)
return false; return false;
else if (flagmobjs[team] && !P_MobjWasRemoved(flagmobjs[team])) else if (flagmobjs[team] && !P_MobjWasRemoved(flagmobjs[team]))
{ {
@ -12154,6 +12154,14 @@ static mobjtype_t P_GetMobjtypeSubstitute(mapthing_t *mthing, mobjtype_t i)
return MT_NIGHTSCHIP; return MT_NIGHTSCHIP;
} }
if (i == MT_TEAMFLAG)
{
INT32 team = mthing->args[0];
if (team == TEAM_NONE || team >= numteams)
return MT_NULL;
return teams[team].flag_mobj_type;
}
if (!(gametyperules & GTR_TEAMS)) if (!(gametyperules & GTR_TEAMS))
{ {
if (i == MT_BLUETEAMRING || i == MT_REDTEAMRING) if (i == MT_BLUETEAMRING || i == MT_REDTEAMRING)
@ -13171,12 +13179,11 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
} }
break; break;
case MT_REDFLAG: case MT_REDFLAG:
P_SetTarget(&flagmobjs[TEAM_RED], mobj);
flagpoints[TEAM_RED] = mobj->spawnpoint;
break;
case MT_BLUEFLAG: case MT_BLUEFLAG:
P_SetTarget(&flagmobjs[TEAM_BLUE], mobj); mobj->extravalue1 = G_GetTeam(mobj->info->mass);
flagpoints[TEAM_BLUE] = mobj->spawnpoint; /* FALLTHRU */
case MT_TEAMFLAG:
mobj->eflags |= MFE_TEAMFLAG;
break; break;
case MT_NIGHTSSTAR: case MT_NIGHTSSTAR:
if (maptol & TOL_XMAS) if (maptol & TOL_XMAS)
@ -13295,6 +13302,19 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean
mobj->threshold = mobj->info->seesound; mobj->threshold = mobj->info->seesound;
mobj->health = mobj->info->spawnhealth; mobj->health = mobj->info->spawnhealth;
} }
// Team flag
if (mobj->eflags & MFE_TEAMFLAG)
{
if (mobj->extravalue1 == 0)
mobj->extravalue1 = mthing->args[0];
INT32 team = mobj->extravalue1;
if (team > TEAM_NONE && team < numteams)
{
P_SetTarget(&flagmobjs[team], mobj);
flagpoints[team] = mobj->spawnpoint;
}
}
return true; return true;
} }
@ -14102,6 +14122,38 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai
return slope ? th : NULL; return slope ? th : NULL;
} }
mobj_t *P_SpawnTeamFlag(UINT8 team, fixed_t x, fixed_t y, fixed_t z)
{
if (team == TEAM_NONE || team >= numteams || teams[team].flag_mobj_type == 0)
return NULL;
mobj_t *flag = P_SpawnMobj(x, y, z, teams[team].flag_mobj_type);
if (flag)
{
flag->eflags |= MFE_TEAMFLAG;
flag->extravalue1 = team;
}
return flag;
}
mobj_t *P_GetTeamFlag(UINT8 team)
{
if (team >= teamsingame || P_MobjWasRemoved(flagmobjs[team]))
return NULL;
return flagmobjs[team];
}
mapthing_t *P_GetTeamFlagMapthing(UINT8 team)
{
if (team >= teamsingame)
return NULL;
return flagpoints[team];
}
// //
// P_FlashPal // P_FlashPal
// Flashes a player's palette. ARMAGEDDON BLASTS! // Flashes a player's palette. ARMAGEDDON BLASTS!
@ -14185,19 +14237,3 @@ mobj_t *P_SpawnMobjFromMobj(mobj_t *mobj, fixed_t xofs, fixed_t yofs, fixed_t zo
return newmobj; return newmobj;
} }
mobj_t *P_GetTeamFlag(UINT8 team)
{
if (team >= teamsingame || P_MobjWasRemoved(flagmobjs[team]))
return NULL;
return flagmobjs[team];
}
mapthing_t *P_GetTeamFlagMapthing(UINT8 team)
{
if (team >= teamsingame)
return NULL;
return flagpoints[team];
}

View file

@ -250,9 +250,11 @@ typedef enum
// Forces an object to NOT use super sprites with SPR_PLAY. // Forces an object to NOT use super sprites with SPR_PLAY.
MFE_FORCENOSUPER = 1<<13, MFE_FORCENOSUPER = 1<<13,
// Makes an object use super sprites where they wouldn't have otherwise and vice-versa // Makes an object use super sprites where they wouldn't have otherwise and vice-versa
MFE_REVERSESUPER = MFE_FORCESUPER|MFE_FORCENOSUPER MFE_REVERSESUPER = MFE_FORCESUPER|MFE_FORCENOSUPER,
// Object is a team flag
MFE_TEAMFLAG = 1<<14,
// free: to and including 1<<15 // free: 1<<15
} mobjeflag_t; } mobjeflag_t;
// //

View file

@ -4668,12 +4668,15 @@ static void P_ProcessTeamBase(player_t *player, UINT8 team)
else if (players[consoleplayer].ctfteam != team) else if (players[consoleplayer].ctfteam != team)
S_StartSound(NULL, sfx_lose); S_StartSound(NULL, sfx_lose);
mo = P_SpawnMobj(player->mo->x,player->mo->y,player->mo->z, teams[otherteam].flag_mobj_type); mo = P_SpawnTeamFlag(otherteam, player->mo->x, player->mo->y, player->mo->z);
if (mo)
{
mo->flags &= ~MF_SPECIAL;
mo->fuse = TICRATE;
mo->spawnpoint = flagpoints[otherteam];
mo->flags2 |= MF2_JUSTATTACKED;
}
player->gotflag &= ~teamflag; player->gotflag &= ~teamflag;
mo->flags &= ~MF_SPECIAL;
mo->fuse = TICRATE;
mo->spawnpoint = flagpoints[otherteam];
mo->flags2 |= MF2_JUSTATTACKED;
teamscores[team]++; teamscores[team]++;
P_AddPlayerScore(player, 250); P_AddPlayerScore(player, 250);
} }