diff --git a/src/deh_tables.c b/src/deh_tables.c index 0ab5a6882..5f473654c 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -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_REDFLAG", // Red CTF Flag "MT_BLUEFLAG", // Blue CTF Flag + "MT_TEAMFLAG", // Team flag "MT_EMBLEM", "MT_EMERALD1", "MT_EMERALD2", @@ -4407,6 +4408,7 @@ const char *const MOBJEFLAG_LIST[] = { "TRACERANGLE", // Compute and trigger on mobj angle relative to tracer "FORCESUPER", // Forces an object to 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 }; diff --git a/src/info.c b/src/info.c index 47e4b6b93..bc5214f59 100644 --- a/src/info.c +++ b/src/info.c @@ -7149,6 +7149,33 @@ mobjinfo_t mobjinfo[NUMMOBJTYPES] = 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 322, // doomednum S_EMBLEM1, // spawnstate diff --git a/src/info.h b/src/info.h index 5c7a9f3fd..f7c7f80d4 100644 --- a/src/info.h +++ b/src/info.h @@ -4521,6 +4521,7 @@ typedef enum mobj_type MT_TOKEN, // Special Stage token for special stage MT_REDFLAG, // Red CTF Flag MT_BLUEFLAG, // Blue CTF Flag + MT_TEAMFLAG, // Team flag MT_EMBLEM, MT_EMERALD1, MT_EMERALD2, diff --git a/src/p_inter.c b/src/p_inter.c index ecd3e5aa0..8a0403454 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -552,6 +552,60 @@ void P_TouchSpecialThing(mobj_t *special, mobj_t *toucher, boolean heightcheck) P_DamageMobj(toucher, special, special, 1, DMG_FIRE); 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 { // 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 // // ********************************** // @@ -4389,13 +4381,16 @@ void P_PlayerFlagBurst(player_t *player, boolean toss) if (!player->gotflag) 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); if (!(player->gotflag & flagflag)) 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) { diff --git a/src/p_local.h b/src/p_local.h index fb8626b64..3e1c162ce 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -338,6 +338,7 @@ FUNCMATH boolean P_WeaponOrPanel(mobjtype_t type); mobj_t *P_GetTeamFlag(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); boolean P_CameraThinker(player_t *player, camera_t *thiscam, boolean resetcalled); diff --git a/src/p_mobj.c b/src/p_mobj.c index ff8dd7c63..2e6e68561 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -44,6 +44,10 @@ actioncache_t actioncachehead; static mobj_t *overlaycap = NULL; +#define MAXHUNTEMERALDS 64 +mapthing_t *huntemeralds[MAXHUNTEMERALDS]; +INT32 numhuntemeralds; + void P_InitCachedActions(void) { actioncachehead.prev = actioncachehead.next = &actioncachehead; @@ -2428,15 +2432,6 @@ boolean P_ZMovement(mobj_t *mo) return false; } 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_COIN: @@ -2497,6 +2492,12 @@ boolean P_ZMovement(mobj_t *mo) } break; default: + // Respawn flags whenever they hit a death pit + if (mo->eflags & MFE_TEAMFLAG && P_CheckDeathPitCollide(mo)) + { + mo->fuse = 1; + return false; + } break; } @@ -2793,7 +2794,7 @@ boolean P_ZMovement(mobj_t *mo) mo->momz = -mo->momz; else // Flags bounce - if (mo->type == MT_REDFLAG || mo->type == MT_BLUEFLAG) + if (mo->eflags & MFE_TEAMFLAG) { if (maptol & TOL_NIGHTS) mo->momz = -FixedDiv(mo->momz, 10*FRACUNIT); @@ -9762,11 +9763,6 @@ static boolean P_MobjRegularThink(mobj_t *mobj) if (!P_TurretThink(mobj)) return false; 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 mobj->momx = FixedMul(mobj->momx, (3*FRACUNIT)/4); // originally 50000 mobj->momy = FixedMul(mobj->momy, (3*FRACUNIT)/4); // same @@ -9894,6 +9890,13 @@ static boolean P_MobjRegularThink(mobj_t *mobj) } /* FALLTHRU */ 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 P_MobjCheckWater(mobj); @@ -10058,6 +10061,12 @@ static boolean P_FuseThink(mobj_t *mobj) P_MonitorFuseThink(mobj); return false; } + else if (mobj->eflags & MFE_TEAMFLAG) + { + P_FlagFuseThink(mobj); + P_RemoveMobj(mobj); + return false; + } else switch (mobj->type) { // gargoyle and snowman handled in P_PushableThinker, not here @@ -10068,11 +10077,6 @@ static boolean P_FuseThink(mobj_t *mobj) case MT_LHRT: P_KillMobj(mobj, NULL, NULL, 0); break; - case MT_BLUEFLAG: - case MT_REDFLAG: - P_FlagFuseThink(mobj); - P_RemoveMobj(mobj); - return false; case MT_FANG: if (mobj->flags2 & MF2_SLIDEPUSH) { @@ -10549,8 +10553,6 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing) case MT_REDTEAMRING: case MT_BLUETEAMRING: - case MT_REDFLAG: - case MT_BLUEFLAG: case MT_EMBLEM: @@ -10589,8 +10591,9 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing) return FRACUNIT; default: - - if (thing->flags & (MF_ENEMY|MF_BOSS)) + if (thing->eflags & MFE_TEAMFLAG) + return 2*FRACUNIT/3; + else if (thing->flags & (MF_ENEMY|MF_BOSS)) return FRACUNIT; else return 0; @@ -11829,10 +11832,6 @@ void P_MovePlayerToStarpost(INT32 playernum) 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) { const subsector_t *ss = R_PointInSubsector(x, y); @@ -11962,7 +11961,8 @@ static boolean P_SpawnNonMobjMapThing(mapthing_t *mthing) return true; } 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; return true; } @@ -12061,13 +12061,13 @@ static boolean P_AllowMobjSpawn(mapthing_t* mthing, mobjtype_t i) 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! } - else if (i == MT_BLUEFLAG || i == MT_REDFLAG) + else if (i == MT_BLUEFLAG || i == MT_REDFLAG || i == MT_TEAMFLAG) { - UINT8 team = mobjinfo[i].mass; - if (team >= numteams) + UINT8 team = i == MT_TEAMFLAG ? mthing->args[0] : mobjinfo[i].mass; + if (team == TEAM_NONE || team >= numteams) return false; 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; } + 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 (i == MT_BLUETEAMRING || i == MT_REDTEAMRING) @@ -13171,12 +13179,11 @@ static boolean P_SetupSpawnedMapThing(mapthing_t *mthing, mobj_t *mobj, boolean } break; case MT_REDFLAG: - P_SetTarget(&flagmobjs[TEAM_RED], mobj); - flagpoints[TEAM_RED] = mobj->spawnpoint; - break; case MT_BLUEFLAG: - P_SetTarget(&flagmobjs[TEAM_BLUE], mobj); - flagpoints[TEAM_BLUE] = mobj->spawnpoint; + mobj->extravalue1 = G_GetTeam(mobj->info->mass); + /* FALLTHRU */ + case MT_TEAMFLAG: + mobj->eflags |= MFE_TEAMFLAG; break; case MT_NIGHTSSTAR: 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->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; } @@ -14102,6 +14122,38 @@ mobj_t *P_SPMAngle(mobj_t *source, mobjtype_t type, angle_t angle, UINT8 allowai 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 // 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; } - -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]; -} diff --git a/src/p_mobj.h b/src/p_mobj.h index 9c598f59e..6f81c5258 100644 --- a/src/p_mobj.h +++ b/src/p_mobj.h @@ -250,9 +250,11 @@ typedef enum // Forces an object to NOT use super sprites with SPR_PLAY. MFE_FORCENOSUPER = 1<<13, // 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; // diff --git a/src/p_spec.c b/src/p_spec.c index 7d7c75e4c..c1703f8fe 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4668,12 +4668,15 @@ static void P_ProcessTeamBase(player_t *player, UINT8 team) else if (players[consoleplayer].ctfteam != team) 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; - mo->flags &= ~MF_SPECIAL; - mo->fuse = TICRATE; - mo->spawnpoint = flagpoints[otherteam]; - mo->flags2 |= MF2_JUSTATTACKED; teamscores[team]++; P_AddPlayerScore(player, 250); }