diff --git a/docs/rh-log.txt b/docs/rh-log.txt
index 9c064977..bd48ce1c 100644
--- a/docs/rh-log.txt
+++ b/docs/rh-log.txt
@@ -1,3 +1,27 @@
+September 16, 2009 (Changes by Graf Zahl)
+- Fixed: The deprecated flag handler for the old bounce flags needs to clear
+ BOUNCE_MBF and BOUNCE_UseSeeSound, too, when clearing one of these flags.
+- Fixed: When adding the AVOIDMELEE code the code was accidentally changed so that
+ friendly monsters could no longer acquire targets by themselves.
+- Renamed WIF_BOT_MELEE to WIF_MELEEWEAPON because it's no longer a bot only flag.
+- Added MBF's monster_backing feature as an actor flag: AVOIDMELEE.
+- Gez's misc. bugs patch:
+* Moves the dog sound out of the Doom-specific sounds in SNDINFO to address this,
+* Renames the dog actor to MBFHelperDog to prevent name conflicts,
+* Adds APROP_Score to CheckActorProperty,
+* Completes the randomspawner update (the reason I moved the recursion counter out of
+ special1 was that I found some projectiles had this set to them, for example in
+ A_LichAttack, but I forgot to add transfer for them),
+* Provides centered sprites for beta plasma balls if this is deemed deserving correction.
+- Added some pieces of MBF's friendly AI.
+- Cleaned up A_LookEx code and merged most of it with the base functions.
+ The major difference was a common piece of code that was repeated 5 times
+ throughout the code so I moved it into a subfunction.
+- Changed P_BlockmapSearch to pass a user parameter to its callback so that
+ A_LookEx does not need to store its info inside the actor itself.
+- fixed: The linetarget CCMD duplicated all of the info CCMD.
+- fixed: PrintActorInfo crashed due to some incomplete implementation.
+
September 15, 2009 (Changes by Graf Zahl)
- added PinkSilver's A_Respawn enhancement patch.
- added RandomSpawner update from Gez's experimental build.
diff --git a/gzdoom.vcproj b/gzdoom.vcproj
index afc81845..c8484fc5 100644
--- a/gzdoom.vcproj
+++ b/gzdoom.vcproj
@@ -797,10 +797,6 @@
RelativePath=".\src\p_enemy.cpp"
>
-
-
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ca264bdd..c1e1d2d6 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -607,7 +607,6 @@ add_executable( zdoom WIN32
p_doors.cpp
p_effect.cpp
p_enemy.cpp
- p_enemy_a_lookex.cpp
p_floor.cpp
p_interaction.cpp
p_lights.cpp
diff --git a/src/actor.h b/src/actor.h
index 82d1d97e..22e86dc6 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -217,7 +217,7 @@ enum
MF3_NOBLOCKMONST = 0x00100000, // Can cross ML_BLOCKMONSTERS lines
MF3_CRASHED = 0x00200000, // Actor entered its crash state
MF3_FULLVOLDEATH = 0x00400000, // DeathSound is played full volume (for missiles)
- /* = 0x00800000, */
+ MF3_AVOIDMELEE = 0x00800000, // Avoids melee attacks (same as MBF's monster_backing but must be explicitly set)
/* = 0x01000000, */
MF3_FOILINVUL = 0x02000000, // Actor can hurt MF2_INVULNERABLE things
MF3_NOTELEOTHER = 0x04000000, // Monster is unaffected by teleport other artifact
@@ -761,6 +761,7 @@ public:
BYTE movedir; // 0-7
SBYTE visdir;
SWORD movecount; // when 0, select a new dir
+ SWORD strafecount; // for MF3_AVOIDMELEE
TObjPtr target; // thing being chased/attacked (or NULL)
// also the originator for missiles
TObjPtr lastenemy; // Last known enemy -- killough 2/15/98
@@ -811,14 +812,6 @@ public:
AActor *BlockingMobj; // Actor that blocked the last move
line_t *BlockingLine; // Line that blocked the last move
- // [KS] These temporary-use properties are needed to allow A_LookEx to pass its parameters to
- // LookFor*InBlock in P_BlockmapSearch so that friendly enemies and monsters that look for
- // other monsters can find their targets properly. If there's a cleaner way of doing this,
- // feel free to remove these and use that method instead.
- fixed_t LookExMinDist; // Minimum sight distance
- fixed_t LookExMaxDist; // Maximum sight distance
- angle_t LookExFOV; // Field of Vision
-
// a linked list of sectors where this object appears
struct msecnode_t *touching_sectorlist; // phares 3/14/98
diff --git a/src/b_bot.cpp b/src/b_bot.cpp
index b03c067f..3911264c 100644
--- a/src/b_bot.cpp
+++ b/src/b_bot.cpp
@@ -136,7 +136,6 @@ void InitBotStuff()
{ "SkullRod", 27000000, 0, "HornRodFX1" },
{ "SkullRodPowered", 27000000, 0, "HornRodFX2" },
{ "PhoenixRod", 18350080, WIF_BOT_REACTION_SKILL_THING|WIF_BOT_EXPLOSIVE, "PhoenixFX1" },
- { "PhoenixRodPowered", 0, WIF_BOT_MELEE, "PhoenixFX2" },
{ "Mace", 27000000, WIF_BOT_REACTION_SKILL_THING, "MaceFX2" },
{ "MacePowered", 27000000, WIF_BOT_REACTION_SKILL_THING|WIF_BOT_EXPLOSIVE, "MaceFX4" },
{ "FWeapHammer", 22000000, 0, "HammerMissile" },
diff --git a/src/b_func.cpp b/src/b_func.cpp
index 5da2e8e2..adaa755c 100644
--- a/src/b_func.cpp
+++ b/src/b_func.cpp
@@ -175,7 +175,7 @@ void FCajunMaster::Dofire (AActor *actor, ticcmd_t *cmd)
(actor->y + actor->vely) - (enemy->y + enemy->vely));
//FIRE EACH TYPE OF WEAPON DIFFERENT: Here should all the different weapons go.
- if (actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_MELEE)
+ if (actor->player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON)
{
if ((actor->player->ReadyWeapon->ProjectileType != NULL))
{
diff --git a/src/b_move.cpp b/src/b_move.cpp
index 896ce934..332160f1 100644
--- a/src/b_move.cpp
+++ b/src/b_move.cpp
@@ -342,7 +342,7 @@ void FCajunMaster::TurnToAng (AActor *actor)
if(actor->player->enemy)
if(!actor->player->dest) //happens when running after item in combat situations, or normal, prevents weak turns
- if(actor->player->ReadyWeapon->ProjectileType == NULL && !(actor->player->ReadyWeapon->WeaponFlags & WIF_BOT_MELEE))
+ if(actor->player->ReadyWeapon->ProjectileType == NULL && !(actor->player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON))
if(Check_LOS(actor, actor->player->enemy, SHOOTFOV+5*ANGLE_1))
maxturn = 3;
}
diff --git a/src/c_cmds.cpp b/src/c_cmds.cpp
index 3cddb6d5..ed27e2d2 100644
--- a/src/c_cmds.cpp
+++ b/src/c_cmds.cpp
@@ -778,7 +778,6 @@ CCMD(linetarget)
linetarget->GetClass()->TypeName.GetChars(),
linetarget->health,
linetarget->SpawnHealth());
- PrintMiscActorInfo(linetarget);
}
else Printf("No target found\n");
}
diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp
index f6397819..1ac3ff28 100644
--- a/src/d_dehacked.cpp
+++ b/src/d_dehacked.cpp
@@ -149,10 +149,10 @@ static TArray WeaponNames;
// List of states that are hacked to use a codepointer
struct MBFParamState
{
- FState * state;
+ FState *state;
int pointer;
};
-static TArray MBFParamStates;
+static TArray MBFParamStates;
// Data on how to correctly modify the codepointers
struct CodePointerAlias
{
@@ -1610,9 +1610,9 @@ static void SetPointer(FState *state, PSymbol *sym, int frame = 0)
{
if (!symname.CompareNoCase(MBFCodePointers[i].name))
{
- MBFParamState * newstate = new MBFParamState;
- newstate->state = state;
- newstate->pointer = i;
+ MBFParamState newstate;
+ newstate.state = state;
+ newstate.pointer = i;
MBFParamStates.Push(newstate);
break; // No need to cycle through the rest of the list.
}
@@ -2494,7 +2494,7 @@ static void UnloadDehSupp ()
// Handle MBF params here, before the required arrays are cleared
for (unsigned int i=0; i < MBFParamStates.Size(); i++)
{
- SetDehParams(MBFParamStates[i]->state, MBFParamStates[i]->pointer);
+ SetDehParams(MBFParamStates[i].state, MBFParamStates[i].pointer);
}
MBFParamStates.Clear();
MBFParamStates.ShrinkToFit();
diff --git a/src/g_doom/a_bossbrain.cpp b/src/g_doom/a_bossbrain.cpp
index 2fc203e1..7764f2ec 100644
--- a/src/g_doom/a_bossbrain.cpp
+++ b/src/g_doom/a_bossbrain.cpp
@@ -238,7 +238,7 @@ static void SpawnFly(AActor *self, const PClass *spawntype, FSoundID sound)
{
newmobj->CopyFriendliness (eye, false);
}
- if (newmobj->SeeState != NULL && P_LookForPlayers (newmobj, true))
+ if (newmobj->SeeState != NULL && P_LookForPlayers (newmobj, true, NULL))
newmobj->SetState (newmobj->SeeState);
if (!(newmobj->ObjectFlags & OF_EuthanizeMe))
diff --git a/src/g_doom/a_scriptedmarine.cpp b/src/g_doom/a_scriptedmarine.cpp
index fbae607c..9f6f5405 100644
--- a/src/g_doom/a_scriptedmarine.cpp
+++ b/src/g_doom/a_scriptedmarine.cpp
@@ -168,7 +168,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_M_Refire)
{
if (self->MissileState && pr_m_refire() < 160)
{ // Look for a new target most of the time
- if (P_LookForPlayers (self, true) && P_CheckMissileRange (self))
+ if (P_LookForPlayers (self, true, NULL) && P_CheckMissileRange (self))
{ // Found somebody new and in range, so don't stop shooting
return;
}
diff --git a/src/g_hexen/a_dragon.cpp b/src/g_hexen/a_dragon.cpp
index 8ef10e24..0c5ea81b 100644
--- a/src/g_hexen/a_dragon.cpp
+++ b/src/g_hexen/a_dragon.cpp
@@ -213,7 +213,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_DragonFlight)
}
else
{
- P_LookForPlayers (self, true);
+ P_LookForPlayers (self, true, NULL);
}
}
diff --git a/src/g_hexen/a_firedemon.cpp b/src/g_hexen/a_firedemon.cpp
index 884a12f2..d0366fdf 100644
--- a/src/g_hexen/a_firedemon.cpp
+++ b/src/g_hexen/a_firedemon.cpp
@@ -145,7 +145,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_FiredChase)
if(!self->target || !(self->target->flags&MF_SHOOTABLE))
{ // Invalid target
- P_LookForPlayers (self,true);
+ P_LookForPlayers (self,true, NULL);
return;
}
diff --git a/src/g_hexen/a_magestaff.cpp b/src/g_hexen/a_magestaff.cpp
index 85b51d33..76610f69 100644
--- a/src/g_hexen/a_magestaff.cpp
+++ b/src/g_hexen/a_magestaff.cpp
@@ -19,7 +19,7 @@ void A_DropBloodscourgePieces (AActor *);
void A_MStaffAttack (AActor *actor);
void A_MStaffPalette (AActor *actor);
-static AActor *FrontBlockCheck (AActor *mo, int index);
+static AActor *FrontBlockCheck (AActor *mo, int index, void *);
static divline_t BlockCheckLine;
//==========================================================================
@@ -254,7 +254,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_MStaffTrack)
//
//============================================================================
-static AActor *FrontBlockCheck (AActor *mo, int index)
+static AActor *FrontBlockCheck (AActor *mo, int index, void *)
{
FBlockNode *link;
diff --git a/src/g_shared/a_pickups.cpp b/src/g_shared/a_pickups.cpp
index 045e5bf9..e9d9e200 100644
--- a/src/g_shared/a_pickups.cpp
+++ b/src/g_shared/a_pickups.cpp
@@ -1741,10 +1741,7 @@ IMPLEMENT_CLASS(AScoreItem)
//
// AScoreItem :: TryPickup
//
-// This function does nothing much. Theoretically, the player could have a
-// score property which would be incremented by the score items' own score
-// property (probably using the Amount property for that), but that is not
-// needed for the moment.
+// Adds the value (Amount) of the item to the toucher's Score property.
//
//===========================================================================
diff --git a/src/g_shared/a_pickups.h b/src/g_shared/a_pickups.h
index 6ccc8cd5..b402fcf5 100644
--- a/src/g_shared/a_pickups.h
+++ b/src/g_shared/a_pickups.h
@@ -322,6 +322,7 @@ enum
WIF_NO_AUTO_SWITCH = 0x00001000, // never switch to this weapon when it's picked up
WIF_STAFF2_KICKBACK = 0x00002000, // the powered-up Heretic staff has special kickback
WIF_NOAUTOAIM = 0x00004000, // this weapon never uses autoaim (useful for ballistic projectiles)
+ WIF_MELEEWEAPON = 0x00008000, // melee weapon. Used by bots and monster AI.
WIF_CHEATNOTWEAPON = 0x08000000, // Give cheat considers this not a weapon (used by Sigil)
@@ -329,7 +330,6 @@ enum
WIF_BOT_REACTION_SKILL_THING = 1<<31, // I don't understand this
WIF_BOT_EXPLOSIVE = 1<<30, // weapon fires an explosive
- WIF_BOT_MELEE = 1<<29, // melee weapon
WIF_BOT_BFG = 1<<28, // this is a BFG
};
@@ -477,7 +477,7 @@ public:
// A score item is picked up without being added to the inventory.
-// Contrarily to FakeInventory, it does nothing.
+// It differs from FakeInventory by doing nothing more than increasing the player's score.
class AScoreItem : public AInventory
{
DECLARE_CLASS (AScoreItem, AInventory)
diff --git a/src/g_shared/a_randomspawner.cpp b/src/g_shared/a_randomspawner.cpp
index b4b9176a..a5ffa925 100644
--- a/src/g_shared/a_randomspawner.cpp
+++ b/src/g_shared/a_randomspawner.cpp
@@ -111,6 +111,8 @@ class ARandomSpawner : public AActor
newmobj->args[2] = args[2];
newmobj->args[3] = args[3];
newmobj->args[4] = args[4];
+ newmobj->special1 = special1;
+ newmobj->special2 = special2;
newmobj->SpawnFlags = SpawnFlags;
newmobj->HandleSpawnFlags();
newmobj->tid = tid;
diff --git a/src/p_acs.cpp b/src/p_acs.cpp
index e45f9275..3f24ad0e 100644
--- a/src/p_acs.cpp
+++ b/src/p_acs.cpp
@@ -2684,6 +2684,7 @@ int DLevelScript::CheckActorProperty (int tid, int property, int value)
case APROP_Gravity:
case APROP_SpawnHealth:
case APROP_JumpZ:
+ case APROP_Score:
return (GetActorProperty(tid, property) == value);
// Boolean values need to compare to a binary version of value
diff --git a/src/p_enemy.cpp b/src/p_enemy.cpp
index a321955a..d2a1e1c6 100644
--- a/src/p_enemy.cpp
+++ b/src/p_enemy.cpp
@@ -62,8 +62,10 @@ static FRandom pr_look2 ("LookyLooky");
static FRandom pr_look3 ("IGotHooky");
static FRandom pr_slook ("SlooK");
static FRandom pr_dropoff ("Dropoff");
+static FRandom pr_defect ("Defect");
static FRandom pr_skiptarget("SkipTarget");
+static FRandom pr_enemystrafe("EnemyStrafe");
// movement interpolation is fine for objects that are moved by their own
// velocity. But for monsters it is problematic.
@@ -219,20 +221,20 @@ void P_NoiseAlert (AActor *target, AActor *emmiter, bool splash)
bool AActor::CheckMeleeRange ()
{
- AActor *pl;
+ AActor *pl = target;
+
fixed_t dist;
- if (!target)
+ if (!pl)
return false;
- pl = target;
dist = P_AproxDistance (pl->x - x, pl->y - y);
if (dist >= meleerange + pl->radius)
return false;
// [RH] If moving toward goal, then we've reached it.
- if (target == goal)
+ if (pl == goal)
return true;
// [RH] Don't melee things too far above or below actor.
@@ -243,6 +245,10 @@ bool AActor::CheckMeleeRange ()
if (pl->z + pl->height < z)
return false;
}
+
+ // killough 7/18/98: friendly monsters don't attack other friends
+ if (IsFriend(pl))
+ return false;
if (!P_CheckSight (this, pl, 0))
return false;
@@ -279,6 +285,12 @@ bool P_CheckMeleeRange2 (AActor *actor)
{ // Attacker is higher
return false;
}
+ else if (actor->IsFriend(mo))
+ {
+ // killough 7/18/98: friendly monsters don't attack other friends
+ return false;
+ }
+
if (!P_CheckSight(actor, mo))
{
return false;
@@ -303,12 +315,34 @@ bool P_CheckMissileRange (AActor *actor)
{
// the target just hit the enemy, so fight back!
actor->flags &= ~MF_JUSTHIT;
- return true;
+
+ // killough 7/18/98: no friendly fire at corpses
+ // killough 11/98: prevent too much infighting among friends
+ // Cleaned up and made readable
+ if (!(actor->flags & MF_FRIENDLY)) return true;
+ if (actor->target->health <= 0) return false;
+ if (!actor->IsFriend(actor->target)) return true;
+ if (actor->target->player != NULL)
+ {
+ return (pr_defect() >128);
+ }
+ else
+ {
+ return !(actor->target->flags & MF_JUSTHIT) && pr_defect() >128;
+ }
}
if (actor->reactiontime)
return false; // do not attack yet
-
+
+ // killough 7/18/98: friendly monsters don't attack other friendly
+ // monsters or players (except when attacked, and then only once)
+ if (actor->IsFriend(actor->target))
+ return false;
+
+ if (actor->flags & MF_FRIENDLY && P_HitFriend(actor))
+ return false;
+
// OPTIMIZE: get this from a global checksight
// [RH] What?
dist = P_AproxDistance (actor->x-actor->target->x,
@@ -357,7 +391,7 @@ bool P_HitFriend(AActor * self)
if (self->flags&MF_FRIENDLY && self->target != NULL)
{
angle_t angle = R_PointToAngle2 (self->x, self->y, self->target->x, self->target->y);
- fixed_t dist = P_AproxDistance (self->x-self->target->x, self->y-self->target->y);
+ fixed_t dist = P_AproxDistance (self->x - self->target->x, self->y - self->target->y);
P_AimLineAttack (self, angle, dist, &linetarget, 0, true);
if (linetarget != NULL && linetarget != self->target)
{
@@ -739,6 +773,8 @@ void P_NewChaseDir(AActor * actor)
fixed_t deltax;
fixed_t deltay;
+ actor->strafecount = 0;
+
if ((actor->flags5&MF5_CHASEGOAL || actor->goal == actor->target) && actor->goal!=NULL)
{
deltax = actor->goal->x - actor->x;
@@ -831,7 +867,56 @@ void P_NewChaseDir(AActor * actor)
return;
}
}
+
+#if 0
+ // Move away from friends when too close, except
+ // in certain situations (e.g. a crowded lift)
+
+ // MBF code for friends. Cannot be done in ZDoom but left here as a reminder for later implementation.
+
+ if (actor->flags & target->flags & MF_FRIEND &&
+ distfriend << FRACBITS > dist &&
+ !P_IsOnLift(target) && !P_IsUnderDamage(actor))
+ deltax = -deltax, deltay = -deltay;
+ else
+#endif
+
+ // MBF's monster_backing option. Made an actor flag instead. Also cleaned the code up to make it readable.
+ // Todo: implement the movement logic
+ AActor *target = actor->target;
+ if (target->health > 0 && !actor->IsFriend(target))
+ { // Live enemy target
+
+ if (actor->flags3 & MF3_AVOIDMELEE)
+ {
+ bool ismeleeattacker = false;
+ fixed_t dist = P_AproxDistance(actor->x-target->x, actor->y-target->y);
+ if (target->player == NULL)
+ {
+ ismeleeattacker = (target->MissileState == NULL && dist < (target->meleerange + target->radius)*2);
+ }
+ else if (target->player->ReadyWeapon != NULL)
+ {
+ // melee range of player weapon is a parameter of the action function and cannot be checked here.
+ // Add a new weapon property?
+ ismeleeattacker = (target->player->ReadyWeapon->WeaponFlags & WIF_MELEEWEAPON && dist < MELEERANGE*3);
+ }
+ if (ismeleeattacker)
+ {
+ actor->strafecount = pr_enemystrafe() & 15;
+ deltax = -deltax, deltay = -deltay;
+ }
+ }
+ }
+
P_DoNewChaseDir(actor, deltax, deltay);
+
+ // If strafing, set movecount to strafecount so that old Doom
+ // logic still works the same, except in the strafing part
+
+ if (actor->strafecount)
+ actor->movecount = actor->strafecount;
+
}
@@ -996,6 +1081,58 @@ void P_RandomChaseDir (AActor *actor)
actor->movedir = DI_NODIR; // cannot move
}
+//---------------------------------------------------------------------------
+//
+// P_IsVisible
+//
+// killough 9/9/98: whether a target is visible to a monster
+// Extended to handle all A_LookEx related checking, too.
+//
+//---------------------------------------------------------------------------
+
+bool P_IsVisible(AActor *lookee, AActor *other, INTBOOL allaround, FLookExParams *params)
+{
+ fixed_t maxdist;
+ fixed_t mindist;
+ angle_t fov;
+
+ if (params != NULL)
+ {
+ maxdist = params->maxdist;
+ mindist = params->mindist;
+ fov = params->fov;
+ }
+ else
+ {
+ mindist = maxdist = 0;
+ fov = allaround? 0 : ANGLE_180;
+ }
+
+ fixed_t dist = P_AproxDistance (other->x - lookee->x, other->y - lookee->y);
+
+ if (maxdist && dist > maxdist)
+ return false; // [KS] too far
+
+ if (mindist && dist < mindist)
+ return false; // [KS] too close
+
+ if (fov && fov < ANGLE_MAX)
+ {
+ angle_t an = R_PointToAngle2 (lookee->x, lookee->y, other->x, other->y) - lookee->angle;
+
+ if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2)))
+ {
+ // if real close, react anyway
+ // [KS] but respect minimum distance rules
+ if (mindist || dist > MELEERANGE)
+ return false; // outside of fov
+ }
+ }
+
+ // P_CheckSight is by far the most expensive operation in here so let's do it last.
+ return P_CheckSight(lookee, other, 2);
+}
+
//---------------------------------------------------------------------------
//
// FUNC P_LookForMonsters
@@ -1061,8 +1198,9 @@ bool P_LookForMonsters (AActor *actor)
//
//============================================================================
-AActor *LookForTIDinBlock (AActor *lookee, int index)
+AActor *LookForTIDInBlock (AActor *lookee, int index, void *extparams)
{
+ FLookExParams *params = (FLookExParams *)extparams;
FBlockNode *block;
AActor *link;
AActor *other;
@@ -1104,25 +1242,8 @@ AActor *LookForTIDinBlock (AActor *lookee, int index)
if (!(lookee->flags3 & MF3_NOSIGHTCHECK))
{
- if (!P_CheckSight (lookee, other, 2))
+ if (!P_IsVisible(lookee, other, true, params))
continue; // out of sight
- /*
- if (!allaround)
- {
- angle_t an = R_PointToAngle2 (actor->x, actor->y,
- other->x, other->y)
- - actor->angle;
-
- if (an > ANG90 && an < ANG270)
- {
- fixed_t dist = P_AproxDistance (other->x - actor->x,
- other->y - actor->y);
- // if real close, react anyway
- if (dist > MELEERANGE)
- continue; // behind back
- }
- }
- */
}
return other;
@@ -1138,12 +1259,13 @@ AActor *LookForTIDinBlock (AActor *lookee, int index)
//
//============================================================================
-bool P_LookForTID (AActor *actor, INTBOOL allaround)
+bool P_LookForTID (AActor *actor, INTBOOL allaround, FLookExParams *params)
{
AActor *other;
bool reachedend = false;
+ bool chasegoal = params? (!(params->flags & LOF_DONTCHASEGOAL)) : true;
- other = P_BlockmapSearch (actor, 0, LookForTIDinBlock);
+ other = P_BlockmapSearch (actor, 0, LookForTIDInBlock, params);
if (other != NULL)
{
@@ -1198,24 +1320,8 @@ bool P_LookForTID (AActor *actor, INTBOOL allaround)
if (!(actor->flags3 & MF3_NOSIGHTCHECK))
{
- if (!P_CheckSight (actor, other, 2))
+ if (!P_IsVisible (actor, other, !!allaround, params))
continue; // out of sight
-
- if (!allaround)
- {
- angle_t an = R_PointToAngle2 (actor->x, actor->y,
- other->x, other->y)
- - actor->angle;
-
- if (an > ANG90 && an < ANG270)
- {
- fixed_t dist = P_AproxDistance (other->x - actor->x,
- other->y - actor->y);
- // if real close, react anyway
- if (dist > MELEERANGE)
- continue; // behind back
- }
- }
}
// [RH] Need to be sure the reactiontime is 0 if the monster is
@@ -1231,7 +1337,7 @@ bool P_LookForTID (AActor *actor, INTBOOL allaround)
if (actor->target == NULL)
{
// [RH] use goal as target
- if (actor->goal != NULL)
+ if (actor->goal != NULL && chasegoal)
{
actor->target = actor->goal;
return true;
@@ -1256,18 +1362,19 @@ bool P_LookForTID (AActor *actor, INTBOOL allaround)
//============================================================================
//
-// LookForTIDinBlock
+// LookForEnemiesinBlock
//
// Finds a non-friendly monster in a mapblock. It can also use targets of
// friendlies in this mapblock to find non-friendlies in other mapblocks.
//
//============================================================================
-AActor *LookForEnemiesInBlock (AActor *lookee, int index)
+AActor *LookForEnemiesInBlock (AActor *lookee, int index, void *extparam)
{
FBlockNode *block;
AActor *link;
AActor *other;
+ FLookExParams *params = (FLookExParams *)extparam;
for (block = blocklinks[index]; block != NULL; block = block->NextActor)
{
@@ -1330,25 +1437,11 @@ AActor *LookForEnemiesInBlock (AActor *lookee, int index)
}
}
- if (other == NULL || !P_CheckSight (lookee, other, 2))
+ // [KS] Hey, shouldn't there be a check for MF3_NOSIGHTCHECK here?
+
+ if (other == NULL || !P_IsVisible (lookee, other, true, params))
continue; // out of sight
- /*
- if (!allaround)
- {
- angle_t an = R_PointToAngle2 (actor->x, actor->y,
- other->x, other->y)
- - actor->angle;
-
- if (an > ANG90 && an < ANG270)
- {
- fixed_t dist = P_AproxDistance (other->x - actor->x,
- other->y - actor->y);
- // if real close, react anyway
- if (dist > MELEERANGE)
- continue; // behind back
- }
- }
- */
+
return other;
}
@@ -1363,11 +1456,11 @@ AActor *LookForEnemiesInBlock (AActor *lookee, int index)
//
//============================================================================
-bool P_LookForEnemies (AActor *actor, INTBOOL allaround)
+bool P_LookForEnemies (AActor *actor, INTBOOL allaround, FLookExParams *params)
{
AActor *other;
- other = P_BlockmapSearch (actor, 10, LookForEnemiesInBlock);
+ other = P_BlockmapSearch (actor, 10, LookForEnemiesInBlock, params);
if (other != NULL)
{
@@ -1415,18 +1508,17 @@ bool P_LookForEnemies (AActor *actor, INTBOOL allaround)
================
*/
-bool P_LookForPlayers (AActor *actor, INTBOOL allaround)
+bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params)
{
int c;
int stop;
int pnum;
player_t* player;
- angle_t an;
- fixed_t dist;
+ bool chasegoal = params? (!(params->flags & LOF_DONTCHASEGOAL)) : true;
if (actor->TIDtoHate != 0)
{
- if (P_LookForTID (actor, allaround))
+ if (P_LookForTID (actor, allaround, params))
{
return true;
}
@@ -1437,10 +1529,43 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround)
}
else if (actor->flags & MF_FRIENDLY)
{
- if (!deathmatch) // [SP] If you don't see any enemies in deathmatch, look for players.
- return P_LookForEnemies (actor, allaround);
- else if ( P_LookForEnemies (actor, allaround) )
- return true;
+ bool result = P_LookForEnemies (actor, allaround, params);
+
+#ifdef MBF_FRIENDS
+ if (!result && (actor->flags & MF_FRIEND_MBF))
+ { // killough 9/9/98: friendly monsters go about players differently
+
+ // Go back to a player, no matter whether it's visible or not
+ for (int anyone=0; anyone<=1; anyone++)
+ {
+ for (int c=0; cIsFriend(players[c].mo) &&
+ (anyone || P_IsVisible(actor, players[c].mo, allaround)))
+ {
+ actor->target = players[c].mo;
+
+ // killough 12/98:
+ // get out of refiring loop, to avoid hitting player accidentally
+
+ if (actor->MissileState != NULL)
+ {
+ actor->SetStateNF(actor->SeeState);
+ actor->flags &= ~MF_JUSTHIT;
+ }
+
+ return true;
+ }
+ }
+ }
+ }
+#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 (result || !deathmatch) return true;
+
+
} // [SP] if false, and in deathmatch, intentional fall-through
if (!(gameinfo.gametype & (GAME_DoomStrifeChex)) &&
@@ -1478,7 +1603,8 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround)
if (actor->target == NULL)
{
// [RH] use goal as target
- if (actor->goal != NULL)
+ // [KS] ...unless we're ignoring goals and we don't already have one
+ if (actor->goal != NULL && chasegoal)
{
actor->target = actor->goal;
return true;
@@ -1512,7 +1638,7 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround)
if (player->health <= 0)
continue; // dead
- if (!P_CheckSight (actor, player->mo, 2))
+ if (!P_IsVisible (actor, player->mo, allaround, params))
continue; // out of sight
// [SP] Deathmatch fixes - if we have MF_FRIENDLY we're definitely in deathmatch
@@ -1525,23 +1651,6 @@ bool P_LookForPlayers (AActor *actor, INTBOOL allaround)
continue; // This is my master.
}
- if (!allaround)
- {
- an = R_PointToAngle2 (actor->x,
- actor->y,
- player->mo->x,
- player->mo->y)
- - actor->angle;
-
- if (an > ANG90 && an < ANG270)
- {
- dist = P_AproxDistance (player->mo->x - actor->x,
- player->mo->y - actor->y);
- // if real close, react anyway
- if (dist > MELEERANGE)
- continue; // behind back
- }
- }
if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) ||
player->mo->flags3 & MF3_GHOST)
{
@@ -1630,7 +1739,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look)
{
// If we find a valid target here, the wandering logic should *not*
// be activated! It would cause the seestate to be set twice.
- if (P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND))
+ if (P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND, NULL))
goto seeyou;
// Let the self wander around aimlessly looking for a fight
@@ -1657,7 +1766,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look)
}
}
- if (!P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND))
+ if (!P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND, NULL))
return;
// go into chase state
@@ -1687,6 +1796,193 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look)
}
+//==========================================================================
+//
+// A_LookEx (int flags, fixed minseedist, fixed maxseedist, fixed maxheardist, fixed fov, state wakestate)
+// [KS] Borrowed the A_Look code to make a parameterized version.
+//
+//==========================================================================
+
+DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx)
+{
+ ACTION_PARAM_START(6);
+ ACTION_PARAM_INT(flags, 0);
+ ACTION_PARAM_FIXED(minseedist, 1);
+ ACTION_PARAM_FIXED(maxseedist, 2);
+ ACTION_PARAM_FIXED(maxheardist, 3);
+ ACTION_PARAM_ANGLE(fov, 4);
+ ACTION_PARAM_STATE(seestate, 5);
+
+ AActor *targ = NULL; // Shuts up gcc
+ fixed_t dist;
+ FLookExParams params = {fov, minseedist, maxseedist, maxheardist, flags, seestate };
+
+ if (self->flags5 & MF5_INCONVERSATION)
+ return;
+
+ // [RH] Set goal now if appropriate
+ if (self->special == Thing_SetGoal && self->args[0] == 0)
+ {
+ NActorIterator iterator (NAME_PatrolPoint, self->args[1]);
+ self->special = 0;
+ self->goal = iterator.Next ();
+ self->reactiontime = self->args[2] * TICRATE + level.maptime;
+ if (self->args[3] == 0) self->flags5 &=~ MF5_CHASEGOAL;
+ else self->flags5 |= MF5_CHASEGOAL;
+ }
+
+ self->threshold = 0; // any shot will wake up
+
+ if (self->TIDtoHate != 0)
+ {
+ targ = self->target;
+ }
+ else
+ {
+ if (!(flags & LOF_NOSOUNDCHECK))
+ {
+ targ = self->LastHeard;
+ if (targ != NULL)
+ {
+ // [RH] If the soundtarget is dead, don't chase it
+ if (targ->health <= 0)
+ {
+ targ = NULL;
+ }
+ else
+ {
+ dist = P_AproxDistance (targ->x - self->x,
+ targ->y - self->y);
+
+ // [KS] If the target is too far away, don't respond to the sound.
+ if (maxheardist && dist > maxheardist)
+ {
+ targ = NULL;
+ self->LastHeard = NULL;
+ }
+ }
+ }
+ }
+
+ if (targ && targ->player && (targ->player->cheats & CF_NOTARGET))
+ {
+ return;
+ }
+ }
+
+ // [RH] Andy Baker's stealth monsters
+ if (self->flags & MF_STEALTH)
+ {
+ self->visdir = -1;
+ }
+
+ if (targ && (targ->flags & MF_SHOOTABLE))
+ {
+ if (self->IsFriend (targ)) // be a little more precise!
+ {
+ if (!(self->flags4 & MF4_STANDSTILL))
+ {
+ if (!(flags & LOF_NOSIGHTCHECK))
+ {
+ // If we find a valid target here, the wandering logic should *not*
+ // be activated! If would cause the seestate to be set twice.
+ if (P_LookForPlayers(self, true, ¶ms))
+ goto seeyou;
+ }
+
+ // Let the self wander around aimlessly looking for a fight
+ if (!(self->flags & MF_INCHASE))
+ {
+ if (seestate)
+ {
+ self->SetState (seestate);
+ }
+ else
+ {
+ if (self->SeeState != NULL)
+ {
+ self->SetState (self->SeeState);
+ }
+ else
+ {
+ CALL_ACTION(A_Wander, self);
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ self->target = targ; //We already have a target?
+
+ // [KS] The target can become ourselves in rare circumstances (like
+ // if we committed suicide), so if that's the case, just ignore it.
+ if (self->target == self) self->target = NULL;
+
+ if (self->target != NULL)
+ {
+ if (self->flags & MF_AMBUSH)
+ {
+ dist = P_AproxDistance (self->target->x - self->x,
+ self->target->y - self->y);
+ if (P_CheckSight (self, self->target, 2) &&
+ (!minseedist || dist > minseedist) &&
+ (!maxseedist || dist < maxseedist))
+ {
+ goto seeyou;
+ }
+ }
+ else
+ goto seeyou;
+ }
+ }
+ }
+
+ if (!(flags & LOF_NOSIGHTCHECK))
+ {
+ if (!P_LookForPlayers(self, true, ¶ms))
+ return;
+ }
+ else
+ {
+ return;
+ }
+
+ // go into chase state
+ seeyou:
+ // [RH] Don't start chasing after a goal if it isn't time yet.
+ if (self->target == self->goal)
+ {
+ if (self->reactiontime > level.maptime)
+ self->target = NULL;
+ }
+ else if (self->SeeSound && !(flags & LOF_NOSEESOUND))
+ {
+ if (flags & LOF_FULLVOLSEESOUND)
+ { // full volume
+ S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NONE);
+ }
+ else
+ {
+ S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM);
+ }
+ }
+
+ if (self->target && !(self->flags & MF_INCHASE))
+ {
+ if (seestate)
+ {
+ self->SetState (seestate);
+ }
+ else
+ {
+ self->SetState (self->SeeState);
+ }
+ }
+}
+
+// [KS] *** End additions by me ***
+
//==========================================================================
//
// A_Wander
@@ -1770,7 +2066,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_Look2)
}
else
{
- if (!P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND))
+ if (!P_LookForPlayers (self, self->flags4 & MF4_LOOKALLAROUND, NULL))
goto nosee;
self->SetState (self->SeeState);
self->flags4 |= MF4_INCOMBAT;
@@ -1856,7 +2152,11 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
}
// turn towards movement direction if not there yet
- if (actor->movedir < 8)
+ if (actor->strafecount)
+ {
+ A_FaceTarget(actor);
+ }
+ else if (actor->movedir < 8)
{
actor->angle &= (angle_t)(7<<29);
delta = actor->angle - (actor->movedir << 29);
@@ -1916,7 +2216,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
// hurt our old one temporarily.
actor->threshold = 0;
}
- if (P_LookForPlayers (actor, true) && actor->target != actor->goal)
+ if (P_LookForPlayers (actor, true, NULL) && actor->target != actor->goal)
{ // got a new target
actor->flags &= ~MF_INCHASE;
return;
@@ -2088,7 +2388,7 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
lookForBetter = true;
}
AActor * oldtarget = actor->target;
- gotNew = P_LookForPlayers (actor, true);
+ gotNew = P_LookForPlayers (actor, true, NULL);
if (lookForBetter)
{
actor->flags3 |= MF3_NOSIGHTCHECK;
@@ -2104,6 +2404,9 @@ void A_DoChase (AActor *actor, bool fastchase, FState *meleestate, FState *missi
// chase towards player
//
+ if (actor->strafecount)
+ actor->strafecount--;
+
// class bosses don't do this when strafing
if ((!fastchase || !actor->FastChaseStrafeCount) && !dontmove)
{
diff --git a/src/p_enemy.h b/src/p_enemy.h
index f111f9d0..ae259806 100644
--- a/src/p_enemy.h
+++ b/src/p_enemy.h
@@ -25,6 +25,25 @@ enum dirtype_t
extern fixed_t xspeed[8], yspeed[8];
+enum LO_Flags
+{
+ LOF_NOSIGHTCHECK = 1,
+ LOF_NOSOUNDCHECK = 2,
+ LOF_DONTCHASEGOAL = 4,
+ LOF_NOSEESOUND = 8,
+ LOF_FULLVOLSEESOUND = 16,
+};
+
+struct FLookExParams
+{
+ angle_t fov;
+ fixed_t mindist;
+ fixed_t maxdist;
+ fixed_t maxheardist;
+ int flags;
+ FState *seestate;
+};
+
void P_RecursiveSound (sector_t *sec, AActor *soundtarget, bool splash, int soundblocks);
bool P_HitFriend (AActor *self);
void P_NoiseAlert (AActor *target, AActor *emmiter, bool splash=false);
@@ -32,9 +51,9 @@ bool P_CheckMeleeRange2 (AActor *actor);
bool P_Move (AActor *actor);
bool P_TryWalk (AActor *actor);
void P_NewChaseDir (AActor *actor);
-bool P_LookForPlayers (AActor *actor, INTBOOL allaround);
AInventory *P_DropItem (AActor *source, const PClass *type, int special, int chance);
void P_TossItem (AActor *item);
+bool P_LookForPlayers (AActor *actor, INTBOOL allaround, FLookExParams *params);
DECLARE_ACTION(A_Look)
DECLARE_ACTION(A_Wander)
diff --git a/src/p_enemy_a_lookex.cpp b/src/p_enemy_a_lookex.cpp
deleted file mode 100644
index 4c68fcbf..00000000
--- a/src/p_enemy_a_lookex.cpp
+++ /dev/null
@@ -1,904 +0,0 @@
-#include
-
-#include "templates.h"
-#include "m_random.h"
-#include "i_system.h"
-#include "doomdef.h"
-#include "p_local.h"
-#include "p_lnspec.h"
-#include "s_sound.h"
-#include "g_game.h"
-#include "doomstat.h"
-#include "r_state.h"
-#include "c_cvars.h"
-#include "p_enemy.h"
-#include "a_sharedglobal.h"
-#include "a_action.h"
-#include "thingdef/thingdef.h"
-#include "g_level.h"
-
-#include "gi.h"
-
-bool P_LookForMonsters (AActor *actor);
-
-static FRandom pr_look2 ("LookyLookyEx");
-static FRandom pr_look3 ("IGotHookyEx");
-static FRandom pr_lookforplayers ("LookForPlayersEx");
-static FRandom pr_skiptarget("SkipTargetEx");
-
-
-// [KS] *** Start additions by me - p_enemy.cpp ***
-
-// LookForTIDinBlockEx
-// LookForEnemiesInBlockEx
-// P_NewLookTID (copied from P_LookForTID)
-// P_NewLookPlayers (copied from P_LookForPlayers)
-// Takes FOV and sight distances into account when acquiring a target.
-// TODO: Not sure if using actor properties to pass parameters around indirectly is such a good idea. If there's a cleaner method, do it that way instead.
-// ~Kate S. Last updated on 12/23/2007
-
-AActor *LookForTIDinBlockEx (AActor *lookee, int index)
-{
- FBlockNode *block;
- AActor *link;
- AActor *other;
- fixed_t dist;
- angle_t an;
-
- for (block = blocklinks[index]; block != NULL; block = block->NextActor)
- {
- link = block->Me;
-
- if (!(link->flags & MF_SHOOTABLE))
- continue; // not shootable (observer or dead)
-
- if (link == lookee)
- continue;
-
- if (link->health <= 0)
- continue; // dead
-
- if (link->flags2 & MF2_DORMANT)
- continue; // don't target dormant things
-
- if (link->tid == lookee->TIDtoHate)
- {
- other = link;
- }
- else if (link->target != NULL && link->target->tid == lookee->TIDtoHate)
- {
- other = link->target;
- if (!(other->flags & MF_SHOOTABLE) ||
- other->health <= 0 ||
- (other->flags2 & MF2_DORMANT))
- {
- continue;
- }
- }
- else
- {
- continue;
- }
-
- if (!(lookee->flags3 & MF3_NOSIGHTCHECK))
- {
- if (!P_CheckSight (lookee, other, 2))
- continue; // out of sight
-
- dist = P_AproxDistance (other->x - lookee->x,
- other->y - lookee->y);
-
- if (lookee->LookExMaxDist && dist > lookee->LookExMaxDist)
- continue; // [KS] too far
-
- if (lookee->LookExMinDist && dist < lookee->LookExMinDist)
- continue; // [KS] too close
-
- if (lookee->LookExFOV && lookee->LookExFOV < ANGLE_MAX)
- {
- an = R_PointToAngle2 (lookee->x,
- lookee->y,
- other->x,
- other->y)
- - lookee->angle;
-
- if (an > (lookee->LookExFOV / 2) && an < (ANGLE_MAX - (lookee->LookExFOV / 2)))
- {
- // if real close, react anyway
- // [KS] but respect minimum distance rules
- if (lookee->LookExMinDist || dist > MELEERANGE)
- continue; // outside of fov
- }
- }
- else
- {
- if(!(lookee->flags4 & MF4_LOOKALLAROUND) || (lookee->LookExFOV >= ANGLE_MAX)) // Just in case angle_t doesn't clamp stuff, because I can't be too sure.
- {
- an = R_PointToAngle2 (lookee->x,
- lookee->y,
- other->x,
- other->y)
- - lookee->angle;
-
- if (an > ANG90 && an < ANG270)
- {
- // if real close, react anyway
- // [KS] but respect minimum distance rules
- if (lookee->LookExMinDist || dist > MELEERANGE)
- continue; // behind back
- }
- }
- }
- }
-
- return other;
- }
- return NULL;
-}
-
-AActor *LookForEnemiesInBlockEx (AActor *lookee, int index)
-{
- FBlockNode *block;
- AActor *link;
- AActor *other;
- fixed_t dist;
- angle_t an;
-
- for (block = blocklinks[index]; block != NULL; block = block->NextActor)
- {
- link = block->Me;
-
- if (!(link->flags & MF_SHOOTABLE))
- continue; // not shootable (observer or dead)
-
- if (link == lookee)
- continue;
-
- if (link->health <= 0)
- continue; // dead
-
- if (link->flags2 & MF2_DORMANT)
- continue; // don't target dormant things
-
- if (!(link->flags3 & MF3_ISMONSTER))
- continue; // don't target it if it isn't a monster (could be a barrel)
-
- other = NULL;
- if (link->flags & MF_FRIENDLY)
- {
- if (deathmatch &&
- lookee->FriendPlayer != 0 && link->FriendPlayer != 0 &&
- lookee->FriendPlayer != link->FriendPlayer)
- {
- // This is somebody else's friend, so go after it
- other = link;
- }
- else if (link->target != NULL && !(link->target->flags & MF_FRIENDLY))
- {
- other = link->target;
- if (!(other->flags & MF_SHOOTABLE) ||
- other->health <= 0 ||
- (other->flags2 & MF2_DORMANT))
- {
- other = NULL;;
- }
- }
- }
- else
- {
- other = link;
- }
-
- // [MBF] If the monster is already engaged in a one-on-one attack
- // with a healthy friend, don't attack around 60% the time.
-
- // [GrafZahl] This prevents friendlies from attacking all the same
- // target.
-
- if (other)
- {
- AActor *targ = other->target;
- if (targ && targ->target == other && pr_skiptarget() > 100 && lookee->IsFriend (targ) &&
- targ->health*2 >= targ->SpawnHealth())
- {
- continue;
- }
- }
-
- // [KS] Hey, shouldn't there be a check for MF3_NOSIGHTCHECK here?
-
- if (other == NULL || !P_CheckSight (lookee, other, 2))
- continue; // out of sight
-
- dist = P_AproxDistance (other->x - lookee->x,
- other->y - lookee->y);
-
- if (lookee->LookExMaxDist && dist > lookee->LookExMaxDist)
- continue; // [KS] too far
-
- if (lookee->LookExMinDist && dist < lookee->LookExMinDist)
- continue; // [KS] too close
-
- if (lookee->LookExFOV && lookee->LookExFOV < ANGLE_MAX)
- {
- an = R_PointToAngle2 (lookee->x,
- lookee->y,
- other->x,
- other->y)
- - lookee->angle;
-
- if (an > (lookee->LookExFOV / 2) && an < (ANGLE_MAX - (lookee->LookExFOV / 2)))
- {
- // if real close, react anyway
- // [KS] but respect minimum distance rules
- if (lookee->LookExMinDist || dist > MELEERANGE)
- continue; // outside of fov
- }
- }
- else
- {
- if(!(lookee->flags4 & MF4_LOOKALLAROUND) || (lookee->LookExFOV >= ANGLE_MAX)) // Just in case angle_t doesn't clamp stuff, because I can't be too sure.
- {
- an = R_PointToAngle2 (lookee->x,
- lookee->y,
- other->x,
- other->y)
- - lookee->angle;
-
- if (an > ANG90 && an < ANG270)
- {
- // if real close, react anyway
- // [KS] but respect minimum distance rules
- if (lookee->LookExMinDist || dist > MELEERANGE)
- continue; // behind back
- }
- }
- }
-
- return other;
- }
- return NULL;
-}
-
-bool P_NewLookTID (AActor *actor, angle_t fov, fixed_t mindist, fixed_t maxdist, bool chasegoal)
-{
- AActor *other;
-
- actor->LookExMinDist = mindist;
- actor->LookExMaxDist = maxdist;
- actor->LookExFOV = fov;
- other = P_BlockmapSearch (actor, 0, LookForTIDinBlockEx);
-
- bool reachedend = false;
- fixed_t dist;
- angle_t an;
-
- if (other != NULL)
- {
- if (!(actor->flags3 & MF3_NOSIGHTCHECK))
- {
- dist = P_AproxDistance (other->x - actor->x,
- other->y - actor->y);
-
- if (maxdist && dist > maxdist)
- {
- other = NULL; // [KS] too far
- goto endcheck;
- }
-
- if (mindist && dist < mindist)
- {
- other = NULL; // [KS] too close
- goto endcheck;
- }
-
- if (fov && fov < ANGLE_MAX)
- {
- an = R_PointToAngle2 (actor->x,
- actor->y,
- other->x,
- other->y)
- - actor->angle;
-
- if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2)))
- {
- // if real close, react anyway
- // [KS] but respect minimum distance rules
- if (mindist || dist > MELEERANGE)
- {
- other = NULL; // outside of fov
- goto endcheck;
- }
- }
- }
- else
- {
- if(!((actor->flags4 & MF4_LOOKALLAROUND) || (fov >= ANGLE_MAX))) // Just in case angle_t doesn't clamp stuff, because I can't be too sure.
- {
- an = R_PointToAngle2 (actor->x,
- actor->y,
- other->x,
- other->y)
- - actor->angle;
-
- if (an > ANG90 && an < ANG270)
- {
- // if real close, react anyway
- // [KS] but respect minimum distance rules
- if (mindist || dist > MELEERANGE)
- {
- other = NULL; // behind back
- goto endcheck;
- }
- }
- }
- }
- }
- }
-
- endcheck:
-
- if (other != NULL)
- {
- if (actor->goal && actor->target == actor->goal)
- actor->reactiontime = 0;
-
- actor->target = other;
- actor->LastLookActor = other;
- return true;
- }
-
- // The actor's TID could change because of death or because of
- // Thing_ChangeTID. If it's not what we expect, then don't use
- // it as a base for the iterator.
- if (actor->LastLookActor != NULL &&
- actor->LastLookActor->tid != actor->TIDtoHate)
- {
- actor->LastLookActor = NULL;
- }
-
- FActorIterator iterator (actor->TIDtoHate, actor->LastLookActor);
- int c = (pr_look3() & 31) + 7; // Look for between 7 and 38 hatees at a time
- while ((other = iterator.Next()) != actor->LastLookActor)
- {
- if (other == NULL)
- {
- if (reachedend)
- {
- // we have cycled through the entire list at least once
- // so let's abort because even if we continue nothing can
- // be found.
- break;
- }
- reachedend = true;
- continue;
- }
-
- if (!(other->flags & MF_SHOOTABLE))
- continue; // not shootable (observer or dead)
-
- if (other == actor)
- continue; // don't hate self
-
- if (other->health <= 0)
- continue; // dead
-
- if (other->flags2 & MF2_DORMANT)
- continue; // don't target dormant things
-
- if (--c == 0)
- break;
-
- if (!(actor->flags3 & MF3_NOSIGHTCHECK))
- {
- if (!P_CheckSight (actor, other, 2))
- continue; // out of sight
-
- dist = P_AproxDistance (other->x - actor->x,
- other->y - actor->y);
-
- if (maxdist && dist > maxdist)
- continue; // [KS] too far
-
- if (mindist && dist < mindist)
- continue; // [KS] too close
-
- if (fov && fov < ANGLE_MAX)
- {
- an = R_PointToAngle2 (actor->x,
- actor->y,
- other->x,
- other->y)
- - actor->angle;
-
- if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2)))
- {
- // if real close, react anyway
- // [KS] but respect minimum distance rules
- if (mindist || dist > MELEERANGE)
- continue; // outside of fov
- }
- }
- else
- {
- if(!((actor->flags4 & MF4_LOOKALLAROUND) || (fov >= ANGLE_MAX))) // Just in case angle_t doesn't clamp stuff, because I can't be too sure.
- {
- an = R_PointToAngle2 (actor->x,
- actor->y,
- other->x,
- other->y)
- - actor->angle;
-
- if (an > ANG90 && an < ANG270)
- {
- // if real close, react anyway
- // [KS] but respect minimum distance rules
- if (mindist || dist > MELEERANGE)
- continue; // behind back
- }
- }
- }
- }
-
- // [RH] Need to be sure the reactiontime is 0 if the monster is
- // leaving its goal to go after something else.
- if (actor->goal && actor->target == actor->goal)
- actor->reactiontime = 0;
-
- actor->target = other;
- actor->LastLookActor = other;
- return true;
- }
- actor->LastLookActor = other;
- if (actor->target == NULL)
- {
- // [RH] use goal as target
- if (actor->goal != NULL && chasegoal)
- {
- actor->target = actor->goal;
- return true;
- }
- // Use last known enemy if no hatee sighted -- killough 2/15/98:
- if (actor->lastenemy != NULL && actor->lastenemy->health > 0)
- {
- if (!actor->IsFriend(actor->lastenemy))
- {
- actor->target = actor->lastenemy;
- actor->lastenemy = NULL;
- return true;
- }
- else
- {
- actor->lastenemy = NULL;
- }
- }
- }
- return false;
-}
-
-bool P_NewLookEnemies (AActor *actor, angle_t fov, fixed_t mindist, fixed_t maxdist, bool chasegoal)
-{
- AActor *other;
-
- actor->LookExMinDist = mindist;
- actor->LookExMaxDist = maxdist;
- actor->LookExFOV = fov;
- other = P_BlockmapSearch (actor, 10, LookForEnemiesInBlockEx);
-
- if (other != NULL)
- {
- if (actor->goal && actor->target == actor->goal)
- actor->reactiontime = 0;
-
- actor->target = other;
-// actor->LastLook.Actor = other;
- return true;
- }
-
- if (actor->target == NULL)
- {
- // [RH] use goal as target
- if (actor->goal != NULL)
- {
- actor->target = actor->goal;
- return true;
- }
- // Use last known enemy if no hatee sighted -- killough 2/15/98:
- if (actor->lastenemy != NULL && actor->lastenemy->health > 0)
- {
- if (!actor->IsFriend(actor->lastenemy))
- {
- actor->target = actor->lastenemy;
- actor->lastenemy = NULL;
- return true;
- }
- else
- {
- actor->lastenemy = NULL;
- }
- }
- }
- return false;
-}
-
-bool P_NewLookPlayers (AActor *actor, angle_t fov, fixed_t mindist, fixed_t maxdist, bool chasegoal)
-{
- int c;
- int stop;
- int pnum;
- player_t* player;
- angle_t an;
- fixed_t dist;
-
- if (actor->TIDtoHate != 0)
- {
- if (P_NewLookTID (actor, fov, mindist, maxdist, chasegoal))
- {
- return true;
- }
- if (!(actor->flags3 & MF3_HUNTPLAYERS))
- {
- return false;
- }
- }
- else if (actor->flags & MF_FRIENDLY)
- {
- if (!deathmatch) // [SP] If you don't see any enemies in deathmatch, look for players.
- return P_NewLookEnemies (actor, fov, mindist, maxdist, chasegoal);
- else if ( P_NewLookEnemies (actor, fov, mindist, maxdist, chasegoal) )
- return true;
- } // [SP] if false, and in deathmatch, intentional fall-through
-
- if (!(gameinfo.gametype & (GAME_DoomStrifeChex)) &&
- !multiplayer &&
- players[0].health <= 0)
- { // Single player game and player is dead; look for monsters
- return P_LookForMonsters (actor);
- }
-
- c = 0;
- if (actor->TIDtoHate != 0)
- {
- pnum = pr_look2() & (MAXPLAYERS-1);
- }
- else
- {
- pnum = actor->LastLookPlayerNumber;
- }
- stop = (pnum - 1) & (MAXPLAYERS-1);
-
- for (;;)
- {
- pnum = (pnum + 1) & (MAXPLAYERS-1);
- if (!playeringame[pnum])
- continue;
-
- if (actor->TIDtoHate == 0)
- {
- actor->LastLookPlayerNumber = pnum;
- }
-
- if (++c == MAXPLAYERS-1 || pnum == stop)
- {
- // done looking
- if (actor->target == NULL)
- {
- // [RH] use goal as target
- // [KS] ...unless we're ignoring goals and we don't already have one
- if (actor->goal != NULL && chasegoal)
- {
- actor->target = actor->goal;
- return true;
- }
- // Use last known enemy if no players sighted -- killough 2/15/98:
- if (actor->lastenemy != NULL && actor->lastenemy->health > 0)
- {
- if (!actor->IsFriend(actor->lastenemy))
- {
- actor->target = actor->lastenemy;
- actor->lastenemy = NULL;
- return true;
- }
- else
- {
- actor->lastenemy = NULL;
- }
- }
- }
- return actor->target == actor->goal && actor->goal != NULL;
- }
-
- player = &players[pnum];
-
- if (!(player->mo->flags & MF_SHOOTABLE))
- continue; // not shootable (observer or dead)
-
- if (player->cheats & CF_NOTARGET)
- continue; // no target
-
- if (player->health <= 0)
- continue; // dead
-
- if (!P_CheckSight (actor, player->mo, 2))
- continue; // out of sight
-
- dist = P_AproxDistance (player->mo->x - actor->x,
- player->mo->y - actor->y);
-
- if (maxdist && dist > maxdist)
- continue; // [KS] too far
-
- if (mindist && dist < mindist)
- continue; // [KS] too close
-
- // [SP] Deathmatch fixes - if we have MF_FRIENDLY we're definitely in deathmatch
- // 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 (fov)
- {
- an = R_PointToAngle2 (actor->x,
- actor->y,
- player->mo->x,
- player->mo->y)
- - actor->angle;
-
- if (an > (fov / 2) && an < (ANGLE_MAX - (fov / 2)))
- {
- // if real close, react anyway
- // [KS] but respect minimum distance rules
- if (mindist || dist > MELEERANGE)
- continue; // outside of fov
- }
- }
- else
- {
- if(!((actor->flags4 & MF4_LOOKALLAROUND) || (fov >= ANGLE_MAX)))
- {
- an = R_PointToAngle2 (actor->x,
- actor->y,
- player->mo->x,
- player->mo->y)
- - actor->angle;
-
- if (an > ANG90 && an < ANG270)
- {
- // if real close, react anyway
- // [KS] but respect minimum distance rules
- if (mindist || dist > MELEERANGE)
- continue; // behind back
- }
- }
- }
- if ((player->mo->flags & MF_SHADOW && !(i_compatflags & COMPATF_INVISIBILITY)) ||
- player->mo->flags3 & MF3_GHOST)
- {
- if ((P_AproxDistance (player->mo->x - actor->x,
- player->mo->y - actor->y) > 2*MELEERANGE)
- && P_AproxDistance (player->mo->velx, player->mo->vely)
- < 5*FRACUNIT)
- { // Player is sneaking - can't detect
- return false;
- }
- if (pr_lookforplayers() < 225)
- { // Player isn't sneaking, but still didn't detect
- return false;
- }
- }
-
- // [RH] Need to be sure the reactiontime is 0 if the monster is
- // leaving its goal to go after a player.
- if (actor->goal && actor->target == actor->goal)
- actor->reactiontime = 0;
-
- actor->target = player->mo;
- return true;
- }
-}
-
-//
-// ACTION ROUTINES
-//
-
-//
-// A_Look
-// Stay in state until a player is sighted.
-// [RH] Will also leave state to move to goal.
-//
-// A_LookEx (int flags, fixed minseedist, fixed maxseedist, fixed maxheardist, fixed fov, state wakestate)
-// [KS] Borrowed the A_Look code to make a parameterized version.
-//
-
-enum LO_Flags
-{
- LOF_NOSIGHTCHECK = 1,
- LOF_NOSOUNDCHECK = 2,
- LOF_DONTCHASEGOAL = 4,
- LOF_NOSEESOUND = 8,
- LOF_FULLVOLSEESOUND = 16,
-};
-
-DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_LookEx)
-{
- ACTION_PARAM_START(6);
- ACTION_PARAM_INT(flags, 0);
- ACTION_PARAM_FIXED(minseedist, 1);
- ACTION_PARAM_FIXED(maxseedist, 2);
- ACTION_PARAM_FIXED(maxheardist, 3);
- ACTION_PARAM_ANGLE(fov, 4);
- ACTION_PARAM_STATE(seestate, 5);
-
- AActor *targ = NULL; // Shuts up gcc
- fixed_t dist;
-
- if (self->flags5 & MF5_INCONVERSATION)
- return;
-
- // [RH] Set goal now if appropriate
- if (self->special == Thing_SetGoal && self->args[0] == 0)
- {
- NActorIterator iterator (NAME_PatrolPoint, self->args[1]);
- self->special = 0;
- self->goal = iterator.Next ();
- self->reactiontime = self->args[2] * TICRATE + level.maptime;
- if (self->args[3] == 0) self->flags5 &=~ MF5_CHASEGOAL;
- else self->flags5 |= MF5_CHASEGOAL;
- }
-
- self->threshold = 0; // any shot will wake up
-
- if (self->TIDtoHate != 0)
- {
- targ = self->target;
- }
- else
- {
- if (!(flags & LOF_NOSOUNDCHECK))
- {
- targ = self->LastHeard;
- if (targ != NULL)
- {
- // [RH] If the soundtarget is dead, don't chase it
- if (targ->health <= 0)
- {
- targ = NULL;
- }
- else
- {
- dist = P_AproxDistance (targ->x - self->x,
- targ->y - self->y);
-
- // [KS] If the target is too far away, don't respond to the sound.
- if (maxheardist && dist > maxheardist)
- {
- targ = NULL;
- self->LastHeard = NULL;
- }
- }
- }
- }
-
- if (targ && targ->player && (targ->player->cheats & CF_NOTARGET))
- {
- return;
- }
- }
-
- // [RH] Andy Baker's stealth monsters
- if (self->flags & MF_STEALTH)
- {
- self->visdir = -1;
- }
-
- if (targ && (targ->flags & MF_SHOOTABLE))
- {
- if (self->IsFriend (targ)) // be a little more precise!
- {
- if (!(self->flags4 & MF4_STANDSTILL))
- {
- if (!(flags & LOF_NOSIGHTCHECK))
- {
- // If we find a valid target here, the wandering logic should *not*
- // be activated! If would cause the seestate to be set twice.
- if (P_NewLookPlayers(self, fov, minseedist, maxseedist, !(flags & LOF_DONTCHASEGOAL)))
- goto seeyou;
- }
-
- // Let the self wander around aimlessly looking for a fight
- if (!(self->flags & MF_INCHASE))
- {
- if (seestate)
- {
- self->SetState (seestate);
- }
- else
- {
- if (self->SeeState != NULL)
- {
- self->SetState (self->SeeState);
- }
- else
- {
- CALL_ACTION(A_Wander, self);
- }
- }
- }
- }
- }
- else
- {
- self->target = targ; //We already have a target?
-
- // [KS] The target can become ourselves in rare circumstances (like
- // if we committed suicide), so if that's the case, just ignore it.
- if (self->target == self) self->target = NULL;
-
- if (self->target != NULL)
- {
- if (self->flags & MF_AMBUSH)
- {
- dist = P_AproxDistance (self->target->x - self->x,
- self->target->y - self->y);
- if (P_CheckSight (self, self->target, 2) &&
- (!minseedist || dist > minseedist) &&
- (!maxseedist || dist < maxseedist))
- {
- goto seeyou;
- }
- }
- else
- goto seeyou;
- }
- }
- }
-
- if (!(flags & LOF_NOSIGHTCHECK))
- {
- if (!P_NewLookPlayers(self, fov, minseedist, maxseedist, !(flags & LOF_DONTCHASEGOAL)))
- return;
- }
- else
- {
- return;
- }
-
- // go into chase state
- seeyou:
- // [RH] Don't start chasing after a goal if it isn't time yet.
- if (self->target == self->goal)
- {
- if (self->reactiontime > level.maptime)
- self->target = NULL;
- }
- else if (self->SeeSound && !(flags & LOF_NOSEESOUND))
- {
- if (flags & LOF_FULLVOLSEESOUND)
- { // full volume
- S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NONE);
- }
- else
- {
- S_Sound (self, CHAN_VOICE, self->SeeSound, 1, ATTN_NORM);
- }
- }
-
- if (self->target && !(self->flags & MF_INCHASE))
- {
- if (seestate)
- {
- self->SetState (seestate);
- }
- else
- {
- self->SetState (self->SeeState);
- }
- }
-}
-
-// [KS] *** End additions by me ***
diff --git a/src/p_interaction.cpp b/src/p_interaction.cpp
index 03d489b8..b508d8f5 100644
--- a/src/p_interaction.cpp
+++ b/src/p_interaction.cpp
@@ -882,6 +882,7 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
int painchance = 0;
FState * woundstate = NULL;
PainChanceList * pc = NULL;
+ bool justhit = false;
if (target == NULL || !((target->flags & MF_SHOOTABLE) || (target->flags6 & MF6_VULNERABLE)))
{ // Shouldn't happen
@@ -893,12 +894,6 @@ void P_DamageMobj (AActor *target, AActor *inflictor, AActor *source, int damage
{
if (inflictor == NULL || !(inflictor->flags4 & MF4_SPECTRAL))
{
- /*
- if (target->MissileState != NULL)
- {
- target->SetState (target->MissileState);
- }
- */
return;
}
}
@@ -1285,7 +1280,7 @@ dopain:
{
if (pr_lightning() < 96)
{
- target->flags |= MF_JUSTHIT; // fight back!
+ justhit = true;
FState * painstate = target->FindState(NAME_Pain, mod);
if (painstate != NULL) target->SetState (painstate);
}
@@ -1300,7 +1295,7 @@ dopain:
}
else
{
- target->flags |= MF_JUSTHIT; // fight back!
+ justhit = true;
FState * painstate = target->FindState(NAME_Pain, mod);
if (painstate != NULL) target->SetState (painstate);
if (mod == NAME_PoisonCloud)
@@ -1345,6 +1340,11 @@ dopain:
}
}
}
+
+ // killough 11/98: Don't attack a friend, unless hit by that friend.
+ if (justhit && (target->target == source || !target->target || !target->IsFriend(target->target)))
+ target->flags |= MF_JUSTHIT; // fight back!
+
}
bool AActor::OkayToSwitchTarget (AActor *other)
diff --git a/src/p_local.h b/src/p_local.h
index 1ac7687e..c0fbaefa 100644
--- a/src/p_local.h
+++ b/src/p_local.h
@@ -320,7 +320,7 @@ public:
#define PT_ADDLINES 1
#define PT_ADDTHINGS 2
-AActor *P_BlockmapSearch (AActor *origin, int distance, AActor *(*func)(AActor *, int));
+AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params = NULL);
AActor *P_RoughMonsterSearch (AActor *mo, int distance);
//
@@ -431,9 +431,10 @@ const secplane_t * P_CheckSlopeWalk (AActor *actor, fixed_t &xmove, fixed_t &ymo
// (For ZDoom itself this doesn't make any difference here but for GZDoom it does.)
//
//----------------------------------------------------------------------------------
+subsector_t *P_PointInSubsector (fixed_t x, fixed_t y);
inline sector_t *P_PointInSector(fixed_t x, fixed_t y)
{
- return R_PointInSubsector(x,y)->sector;
+ return P_PointInSubsector(x,y)->sector;
}
//
diff --git a/src/p_maputl.cpp b/src/p_maputl.cpp
index 0c9b6569..3f8ddd32 100644
--- a/src/p_maputl.cpp
+++ b/src/p_maputl.cpp
@@ -40,7 +40,7 @@
#include "r_state.h"
#include "templates.h"
-static AActor *RoughBlockCheck (AActor *mo, int index);
+static AActor *RoughBlockCheck (AActor *mo, int index, void *);
//==========================================================================
@@ -1279,7 +1279,7 @@ AActor *P_RoughMonsterSearch (AActor *mo, int distance)
return P_BlockmapSearch (mo, distance, RoughBlockCheck);
}
-AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int))
+AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, int, void *), void *params)
{
int blockX;
int blockY;
@@ -1298,7 +1298,7 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
if (startX >= 0 && startX < bmapwidth && startY >= 0 && startY < bmapheight)
{
- if ( (target = check (mo, startY*bmapwidth+startX)) )
+ if ( (target = check (mo, startY*bmapwidth+startX, params)) )
{ // found a target right away
return target;
}
@@ -1335,7 +1335,7 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
// Trace the first block section (along the top)
for (; blockIndex <= firstStop; blockIndex++)
{
- if ( (target = check (mo, blockIndex)) )
+ if ( (target = check (mo, blockIndex, params)) )
{
return target;
}
@@ -1343,7 +1343,7 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
// Trace the second block section (right edge)
for (blockIndex--; blockIndex <= secondStop; blockIndex += bmapwidth)
{
- if ( (target = check (mo, blockIndex)) )
+ if ( (target = check (mo, blockIndex, params)) )
{
return target;
}
@@ -1351,7 +1351,7 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
// Trace the third block section (bottom edge)
for (blockIndex -= bmapwidth; blockIndex >= thirdStop; blockIndex--)
{
- if ( (target = check (mo, blockIndex)) )
+ if ( (target = check (mo, blockIndex, params)) )
{
return target;
}
@@ -1359,7 +1359,7 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
// Trace the final block section (left edge)
for (blockIndex++; blockIndex > finalStop; blockIndex -= bmapwidth)
{
- if ( (target = check (mo, blockIndex)) )
+ if ( (target = check (mo, blockIndex, params)) )
{
return target;
}
@@ -1374,7 +1374,7 @@ AActor *P_BlockmapSearch (AActor *mo, int distance, AActor *(*check)(AActor*, in
//
//===========================================================================
-static AActor *RoughBlockCheck (AActor *mo, int index)
+static AActor *RoughBlockCheck (AActor *mo, int index, void *)
{
FBlockNode *link;
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index 9ab3a780..70c193ff 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -241,6 +241,7 @@ void AActor::Serialize (FArchive &arc)
<< movedir
<< visdir
<< movecount
+ << strafecount
<< target
<< lastenemy
<< LastHeard
@@ -5519,11 +5520,9 @@ void PrintMiscActorInfo(AActor * query)
FIXED2FLOAT(query->wallbouncefactor), query->BounceFlags);
for (flagi = 0; flagi < 31; flagi++)
if (query->BounceFlags & 1<alpha), query->renderflags);
- /*
for (flagi = 0; flagi < 31; flagi++)
if (query->renderflags & 1<>3);
int Pitch = Width * step_x;
+ /*
if (hdr.img_desc&32)
{
ptr += (Width-1) * step_x;
step_x =- step_x;
}
- if (!(hdr.img_desc&64))
+ */
+ if (!(hdr.img_desc&32))
{
ptr += (Height-1) * Pitch;
Pitch = -Pitch;
@@ -557,12 +559,14 @@ int FTGATexture::CopyTrueColorPixels(FBitmap *bmp, int x, int y, int w, int h, i
int step_x = (hdr.bpp>>3);
int Pitch = Width * step_x;
+ /*
if (hdr.img_desc&32)
{
ptr += (Width-1) * step_x;
step_x =- step_x;
}
- if (!(hdr.img_desc&64))
+ */
+ if (!(hdr.img_desc&32))
{
ptr += (Height-1) * Pitch;
Pitch = -Pitch;
diff --git a/src/thingdef/thingdef_data.cpp b/src/thingdef/thingdef_data.cpp
index c65cb5d2..5b207c85 100644
--- a/src/thingdef/thingdef_data.cpp
+++ b/src/thingdef/thingdef_data.cpp
@@ -141,6 +141,7 @@ static FFlagDef ActorFlags[]=
DEFINE_FLAG(MF3, NOTARGET, AActor, flags3),
DEFINE_FLAG(MF3, DONTGIB, AActor, flags3),
DEFINE_FLAG(MF3, NOBLOCKMONST, AActor, flags3),
+ DEFINE_FLAG(MF3, AVOIDMELEE, AActor, flags3),
DEFINE_FLAG(MF3, FULLVOLDEATH, AActor, flags3),
DEFINE_FLAG(MF3, FOILINVUL, AActor, flags3),
DEFINE_FLAG(MF3, NOTELEOTHER, AActor, flags3),
@@ -295,7 +296,7 @@ static FFlagDef WeaponFlags[] =
DEFINE_FLAG(WIF, POWERED_UP, AWeapon, WeaponFlags),
DEFINE_FLAG(WIF, STAFF2_KICKBACK, AWeapon, WeaponFlags),
DEFINE_FLAG(WIF_BOT, EXPLOSIVE, AWeapon, WeaponFlags),
- DEFINE_FLAG2(WIF_BOT_MELEE, MELEEWEAPON, AWeapon, WeaponFlags),
+ DEFINE_FLAG(WIF, MELEEWEAPON, AWeapon, WeaponFlags),
DEFINE_FLAG(WIF_BOT, BFG, AWeapon, WeaponFlags),
DEFINE_FLAG(WIF, CHEATNOTWEAPON, AWeapon, WeaponFlags),
DEFINE_FLAG(WIF, NO_AUTO_SWITCH, AWeapon, WeaponFlags),
diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp
index f04c6ba8..4f29d272 100644
--- a/src/thingdef/thingdef_properties.cpp
+++ b/src/thingdef/thingdef_properties.cpp
@@ -130,15 +130,15 @@ void HandleDeprecatedFlags(AActor *defaults, FActorInfo *info, bool set, int ind
break;
// the bounce flags will set the compatibility bounce modes to remain compatible
case DEPF_HERETICBOUNCE:
- defaults->BounceFlags &= ~BOUNCE_TypeMask;
+ defaults->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound);
if (set) defaults->BounceFlags |= BOUNCE_HereticCompat;
break;
case DEPF_HEXENBOUNCE:
- defaults->BounceFlags &= ~BOUNCE_TypeMask;
+ defaults->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound);
if (set) defaults->BounceFlags |= BOUNCE_HexenCompat;
break;
case DEPF_DOOMBOUNCE:
- defaults->BounceFlags &= ~BOUNCE_TypeMask;
+ defaults->BounceFlags &= ~(BOUNCE_TypeMask|BOUNCE_UseSeeSound);
if (set) defaults->BounceFlags |= BOUNCE_DoomCompat;
break;
case DEPF_PICKUPFLASH:
diff --git a/src/version.h b/src/version.h
index c5846e74..6ee0c795 100644
--- a/src/version.h
+++ b/src/version.h
@@ -77,7 +77,7 @@
// SAVESIG should match SAVEVER.
// MINSAVEVER is the minimum level snapshot version that can be loaded.
-#define MINSAVEVER 1823
+#define MINSAVEVER 1848
#if ZD_SVN_REVISION_NUMBER < MINSAVEVER
// Never write a savegame with a version lower than what we need
diff --git a/wadsrc_bm/brightmaps.vcproj b/wadsrc_bm/brightmaps.vcproj
index 4c3919d1..c0f0243b 100644
--- a/wadsrc_bm/brightmaps.vcproj
+++ b/wadsrc_bm/brightmaps.vcproj
@@ -2,7 +2,7 @@