diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ea8ebcb853..26871cf1ec 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -741,6 +741,7 @@ set( NOT_COMPILED_SOURCE_FILES
g_hexen/a_fighterquietus.cpp
g_hexen/a_firedemon.cpp
g_hexen/a_flechette.cpp
+ g_hexen/a_flies.cpp
g_hexen/a_fog.cpp
g_hexen/a_healingradius.cpp
g_hexen/a_heresiarch.cpp
diff --git a/src/actor.h b/src/actor.h
index 78c82066c1..862858b32a 100644
--- a/src/actor.h
+++ b/src/actor.h
@@ -1035,7 +1035,7 @@ public:
virtual bool UpdateWaterLevel (fixed_t oldz, bool splash=true);
bool isFast();
bool isSlow();
- void SetIdle();
+ void SetIdle(bool nofunction=false);
void ClearCounters();
FState *GetRaiseState();
void Revive();
diff --git a/src/g_hexen/a_flies.cpp b/src/g_hexen/a_flies.cpp
new file mode 100644
index 0000000000..3c677d5cb3
--- /dev/null
+++ b/src/g_hexen/a_flies.cpp
@@ -0,0 +1,106 @@
+static FRandom pr_fly("GetOffMeFly");
+
+//===========================================================================
+//
+// FindCorpse
+//
+// Finds a corpse to buzz around. We can't use a blockmap check because
+// corpses generally aren't linked into the blockmap.
+//
+//===========================================================================
+
+static AActor *FindCorpse(AActor *fly, sector_t *sec, int recurselimit)
+{
+ AActor *fallback = NULL;
+ sec->validcount = validcount;
+
+ // Search the current sector
+ for (AActor *check = sec->thinglist; check != NULL; check = check->snext)
+ {
+ if (check == fly)
+ continue;
+ if (!(check->flags & MF_CORPSE))
+ continue;
+ if (!P_CheckSight(fly, check))
+ continue;
+ fallback = check;
+ if (pr_fly(2)) // 50% chance to try to pick a different corpse
+ continue;
+ return check;
+ }
+ if (--recurselimit <= 0 || (fallback != NULL && pr_fly(2)))
+ {
+ return fallback;
+ }
+ // Try neighboring sectors
+ for (int i = 0; i < sec->linecount; ++i)
+ {
+ line_t *line = sec->lines[i];
+ sector_t *sec2 = (line->frontsector == sec) ? line->backsector : line->frontsector;
+ if (sec2 != NULL && sec2->validcount != validcount)
+ {
+ AActor *neighbor = FindCorpse(fly, sec2, recurselimit);
+ if (neighbor != NULL)
+ {
+ return neighbor;
+ }
+ }
+ }
+ return fallback;
+}
+
+DEFINE_ACTION_FUNCTION(AActor, A_FlySearch)
+{
+ // The version from the retail beta is not so great for general use:
+ // 1. Pick one of the first fifty thinkers at random.
+ // 2. Starting from that thinker, find one that is an actor, not itself,
+ // and within sight. Give up after 100 sequential thinkers.
+ // It's effectively useless if there are more than 150 thinkers on a map.
+ //
+ // So search the sectors instead. We can't potentially find something all
+ // the way on the other side of the map and we can't find invisible corpses,
+ // but at least we aren't crippled on maps with lots of stuff going on.
+ validcount++;
+ AActor *other = FindCorpse(self, self->Sector, 5);
+ if (other != NULL)
+ {
+ self->target = other;
+ self->SetState(self->FindState("Buzz"));
+ }
+}
+
+DEFINE_ACTION_FUNCTION(AActor, A_FlyBuzz)
+{
+ AActor *targ = self->target;
+
+ if (targ == NULL || !(targ->flags & MF_CORPSE) || pr_fly() < 5)
+ {
+ self->SetIdle();
+ return;
+ }
+
+ angle_t ang = R_PointToAngle2(self->x, self->y, targ->x, targ->y);
+ self->angle = ang;
+ self->args[0]++;
+ ang >>= ANGLETOFINESHIFT;
+ if (!P_TryMove(self, self->x + 6 * finecosine[ang], self->y + 6 * finesine[ang], true))
+ {
+ self->SetIdle(true);
+ return;
+ }
+ if (self->args[0] & 2)
+ {
+ self->velx += (pr_fly() - 128) << BOBTOFINESHIFT;
+ self->vely += (pr_fly() - 128) << BOBTOFINESHIFT;
+ }
+ int zrand = pr_fly();
+ if (targ->z + 5*FRACUNIT < self->z && zrand > 150)
+ {
+ zrand = -zrand;
+ }
+ self->velz = zrand << BOBTOFINESHIFT;
+ if (pr_fly() < 40)
+ {
+ S_Sound(self, CHAN_VOICE, self->ActiveSound, 0.5f, ATTN_STATIC);
+ }
+}
diff --git a/src/g_hexen/a_hexenmisc.cpp b/src/g_hexen/a_hexenmisc.cpp
index fa07a67599..1141f381f9 100644
--- a/src/g_hexen/a_hexenmisc.cpp
+++ b/src/g_hexen/a_hexenmisc.cpp
@@ -38,6 +38,7 @@
#include "a_fighterquietus.cpp"
#include "a_firedemon.cpp"
#include "a_flechette.cpp"
+#include "a_flies.cpp"
#include "a_fog.cpp"
#include "a_healingradius.cpp"
#include "a_heresiarch.cpp"
diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp
index c12bd53db5..9dd9f1ddcc 100644
--- a/src/p_mobj.cpp
+++ b/src/p_mobj.cpp
@@ -6236,11 +6236,11 @@ void AActor::Crash()
}
}
-void AActor::SetIdle()
+void AActor::SetIdle(bool nofunction)
{
FState *idle = FindState (NAME_Idle);
if (idle == NULL) idle = SpawnState;
- SetState(idle);
+ SetState(idle, nofunction);
}
int AActor::SpawnHealth()
diff --git a/wadsrc/static/actors/hexen/flies.txt b/wadsrc/static/actors/hexen/flies.txt
new file mode 100644
index 0000000000..6be4a749f7
--- /dev/null
+++ b/wadsrc/static/actors/hexen/flies.txt
@@ -0,0 +1,28 @@
+
+// Buzzy fly ----------------------------------------------------------------
+
+ACTOR LittleFly 112
+{
+ Game Hexen
+ +NOBLOCKMAP +NOGRAVITY
+ +CANPASS
+
+ Speed 6
+ Radius 5
+ Height 5
+ Mass 2
+ ActiveSound "FlyBuzz"
+
+ action native A_FlySearch();
+ action native A_FlyBuzz();
+
+ States
+ {
+ Spawn:
+ TNT1 A 20 A_FlySearch // [RH] Invisible when not flying
+ Loop
+ Buzz:
+ AFLY ABCD 3 A_FlyBuzz
+ Loop
+ }
+}
diff --git a/wadsrc/static/decorate.txt b/wadsrc/static/decorate.txt
index ae4b6f8517..46f1854b99 100644
--- a/wadsrc/static/decorate.txt
+++ b/wadsrc/static/decorate.txt
@@ -93,6 +93,7 @@
#include "actors/hexen/mageplayer.txt"
#include "actors/hexen/pig.txt"
#include "actors/hexen/flame.txt"
+#include "actors/hexen/flies.txt"
#include "actors/hexen/hexenarmor.txt"
#include "actors/hexen/hexendecorations.txt"
#include "actors/hexen/hexenkeys.txt"
diff --git a/zdoom.vcproj b/zdoom.vcproj
index a6a94cafe4..9c3367ff20 100644
--- a/zdoom.vcproj
+++ b/zdoom.vcproj
@@ -5228,6 +5228,42 @@
/>
+
+
+
+
+
+
+
+
+
+
+
+
+
+