diff --git a/src/deh_tables.c b/src/deh_tables.c index 77cae0e70f019b61b874039a0ca7d0ea086e0235..588bbea9beab385695b191c74e0b22630af72584 100644 --- a/src/deh_tables.c +++ b/src/deh_tables.c @@ -3697,6 +3697,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", @@ -4415,6 +4416,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 15ff40c675e8d3c05486c50c3aa2cdc110dd080d..bab6945d6ec15900cac9764572280ba95b83dff8 100644 --- a/src/info.c +++ b/src/info.c @@ -7157,6 +7157,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 a2d87dbdc10644edaaf34187d45495d70ba49f85..f5ab1595e87ffc104c87fb45976a9f32d13065cc 100644 --- a/src/info.h +++ b/src/info.h @@ -4529,6 +4529,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 f0531c3b39f3c1c18cebce443e39e614c7b6cd85..0d5c4af74e84b2e9a06545c087ef4989e037ea6a 100644 --- a/src/p_inter.c +++ b/src/p_inter.c @@ -553,6 +553,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 @@ -834,68 +888,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 // // ********************************** // @@ -4392,13 +4384,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 b0d3acf685d0e3e0390dfba118a82e0a00a78bca..5ee5dfd5d2ef288b9ecff04672ab439577f8218e 100644 --- a/src/p_local.h +++ b/src/p_local.h @@ -345,6 +345,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 077c6b68be83c77caaa8fa9f32166de52813ed8c..4755583c13cb44217fff351d164fb5ff3648e6bf 100644 --- a/src/p_mobj.c +++ b/src/p_mobj.c @@ -45,6 +45,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; @@ -2430,15 +2434,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: @@ -2499,6 +2494,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; } @@ -2795,7 +2796,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); @@ -9763,11 +9764,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 @@ -9895,6 +9891,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); @@ -10059,6 +10062,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 @@ -10069,11 +10078,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) { @@ -10551,8 +10555,6 @@ static fixed_t P_DefaultMobjShadowScale (mobj_t *thing) case MT_REDTEAMRING: case MT_BLUETEAMRING: - case MT_REDFLAG: - case MT_BLUEFLAG: case MT_BOUNCERING: case MT_AUTOMATICRING: @@ -10614,8 +10616,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; @@ -11845,10 +11848,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 boolean absolutez) { const subsector_t *ss = R_PointInSubsector(x, y); @@ -11979,7 +11978,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; } @@ -12078,13 +12078,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])) { @@ -12171,6 +12171,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) @@ -13188,12 +13196,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) @@ -13312,6 +13319,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; } @@ -14119,6 +14139,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! @@ -14202,19 +14254,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 a980691beb8b296b4fd16415141e4f9e5f484af8..11d03fdaed2b291da37b92045787def12b2e60d2 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 736498a55615922bf390f787ae9d7a28cc1c789d..a4ed36f8b32f3f8f676101220759b54259a87c11 100644 --- a/src/p_spec.c +++ b/src/p_spec.c @@ -4667,12 +4667,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); }