diff --git a/src/actor.h b/src/actor.h index 53145b7c1..2c5e66990 100644 --- a/src/actor.h +++ b/src/actor.h @@ -858,6 +858,7 @@ public: int lastbump; // Last time the actor was bumped, used to control BUMPSPECIAL int Score; // manipulated by score items, ACS or DECORATE. The engine doesn't use this itself for anything. FString * Tag; // Strife's tag name. + int DesignatedTeam; // Allow for friendly fire cacluations to be done on non-players. AActor *BlockingMobj; // Actor that blocked the last move line_t *BlockingLine; // Line that blocked the last move diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp index 378aaae9d..bc755892e 100644 --- a/src/p_enemy.cpp +++ b/src/p_enemy.cpp @@ -44,6 +44,7 @@ #include "thingdef/thingdef.h" #include "d_dehacked.h" #include "g_level.h" +#include "teaminfo.h" #include "gi.h" @@ -1417,9 +1418,7 @@ AActor *LookForEnemiesInBlock (AActor *lookee, int index, void *extparam) other = NULL; if (link->flags & MF_FRIENDLY) { - if (deathmatch && - lookee->FriendPlayer != 0 && link->FriendPlayer != 0 && - lookee->FriendPlayer != link->FriendPlayer) + if (!lookee->IsFriend(link)) { // This is somebody else's friend, so go after it other = link; @@ -1581,7 +1580,7 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) } #endif // [SP] If you don't see any enemies in deathmatch, look for players (but only when friend to a specific player.) - if (actor->FriendPlayer == 0) return result; + if (actor->FriendPlayer == 0 && (!teamplay || actor->DesignatedTeam == TEAM_NONE)) return result; if (result || !deathmatch) return true; @@ -1664,10 +1663,8 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params) // We're going to ignore our master, but go after his enemies. if ( actor->flags & MF_FRIENDLY ) { - if ( actor->FriendPlayer == 0 ) - continue; // I have no friends, I will ignore players. - if ( actor->FriendPlayer == player->mo->FriendPlayer ) - continue; // This is my master. + if ( actor->IsFriend(player->mo) ) + continue; } if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) || diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp index 4a082cff0..b39a4017f 100644 --- a/src/p_interaction.cpp +++ b/src/p_interaction.cpp @@ -1087,6 +1087,21 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage } } + // [RH] Avoid friendly fire if enabled + if (!(flags & DMG_FORCED) && source != NULL && + ((player && player != source->player) || !player) && + target->IsTeammate (source)) + { + if (player) + FriendlyFire = true; + if (damage < TELEFRAG_DAMAGE) + { // Still allow telefragging :-( + damage = (int)((float)damage * level.teamdamage); + if (damage <= 0) + return; + } + } + // // player specific // @@ -1115,17 +1130,6 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage return; } - // [RH] Avoid friendly fire if enabled - if (source != NULL && player != source->player && target->IsTeammate (source)) - { - FriendlyFire = true; - if (damage < TELEFRAG_DAMAGE) - { // Still allow telefragging :-( - damage = (int)((float)damage * level.teamdamage); - if (damage <= 0) - return; - } - } if (!(flags & DMG_NO_ARMOR) && player->mo->Inventory != NULL) { int newdam = damage; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 31302cbc8..d769f4143 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -300,6 +300,7 @@ void AActor::Serialize (FArchive &arc) << pushfactor << Species << Score + << DesignatedTeam << lastpush << lastbump << PainThreshold << DamageFactor @@ -775,6 +776,7 @@ void AActor::CopyFriendliness (AActor *other, bool changeTarget) flags3 = (flags3 & ~(MF3_NOSIGHTCHECK | MF3_HUNTPLAYERS)) | (other->flags3 & (MF3_NOSIGHTCHECK | MF3_HUNTPLAYERS)); flags4 = (flags4 & ~MF4_NOHATEPLAYERS) | (other->flags4 & MF4_NOHATEPLAYERS); FriendPlayer = other->FriendPlayer; + DesignatedTeam = other->DesignatedTeam; if (changeTarget && other->target != NULL && !(other->target->flags3 & MF3_NOTARGET)) { // LastHeard must be set as well so that A_Look can react to the new target if called @@ -5296,12 +5298,18 @@ AActor *P_SpawnPlayerMissile (AActor *source, fixed_t x, fixed_t y, fixed_t z, bool AActor::IsTeammate (AActor *other) { - if (!player || !other || !other->player) + if (!other) return false; - if (!deathmatch) + else if (!deathmatch && player && other->player) return true; - if (teamplay && other->player->userinfo.team != TEAM_NONE && - player->userinfo.team == other->player->userinfo.team) + int myTeam = DesignatedTeam; + int otherTeam = other->DesignatedTeam; + if (player) + myTeam = player->userinfo.team; + if (other->player) + otherTeam = other->player->userinfo.team; + if (teamplay && myTeam != TEAM_NONE && + myTeam == otherTeam) { return true; } @@ -5353,6 +5361,11 @@ bool AActor::IsFriend (AActor *other) { if (flags & other->flags & MF_FRIENDLY) { + if (deathmatch && teamplay) + return IsTeammate(other) || + (FriendPlayer != 0 && other->FriendPlayer != 0 && + players[FriendPlayer-1].mo->IsTeammate(players[other->FriendPlayer-1].mo)); + return !deathmatch || FriendPlayer == other->FriendPlayer || FriendPlayer == 0 || @@ -5378,6 +5391,11 @@ bool AActor::IsHostile (AActor *other) // Both monsters are friendly and belong to the same player if applicable. if (flags & other->flags & MF_FRIENDLY) { + if (deathmatch && teamplay) + return !IsTeammate(other) && + !(FriendPlayer != 0 && other->FriendPlayer != 0 && + players[FriendPlayer-1].mo->IsTeammate(players[other->FriendPlayer-1].mo)); + return deathmatch && FriendPlayer != other->FriendPlayer && FriendPlayer !=0 && diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index efff2b665..e7601ba74 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -67,6 +67,7 @@ #include "r_translate.h" #include "a_morph.h" #include "colormatcher.h" +#include "teaminfo.h" //========================================================================== @@ -1120,6 +1121,17 @@ DEFINE_PROPERTY(activation, N, Actor) defaults->activationtype = val; } +//========================================================================== +// +//========================================================================== +DEFINE_PROPERTY(designatedteam, I, Actor) +{ + PROP_INT_PARM(val, 0); + if(val < 0 || (val >= (signed) Teams.Size() && val != TEAM_NONE)) + I_Error("Invalid team designation.\n"); + defaults->DesignatedTeam = val; +} + //========================================================================== // // Special inventory properties diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index b0bb3a3d8..5e71ac555 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -21,6 +21,7 @@ ACTOR Actor native //: Thinker PushFactor 0.25 WeaveIndexXY 0 WeaveIndexZ 16 + DesignatedTeam 255 // Variables for the expression evaluator // NOTE: fixed_t and angle_t are only used here to ensure proper conversion