diff --git a/ChaosMod/ChaosMod.vcxproj b/ChaosMod/ChaosMod.vcxproj
index c6cc7cdf9..5c32bc3c6 100644
--- a/ChaosMod/ChaosMod.vcxproj
+++ b/ChaosMod/ChaosMod.vcxproj
@@ -119,6 +119,7 @@
+
diff --git a/ChaosMod/Effects/db/Peds/PedsAliens.cpp b/ChaosMod/Effects/db/Peds/PedsAliens.cpp
new file mode 100644
index 000000000..8af65f266
--- /dev/null
+++ b/ChaosMod/Effects/db/Peds/PedsAliens.cpp
@@ -0,0 +1,193 @@
+/*
+ Effect By OnlyRealNubs
+*/
+
+#include
+
+#include "Util/Peds.h"
+
+static std::list m_aliens;
+static const std::vector m_weapons =
+{
+ GET_HASH_KEY("WEAPON_RAYPISTOL"),
+ GET_HASH_KEY("WEAPON_RAYCARBINE"),
+ GET_HASH_KEY("WEAPON_RAYMINIGUN")
+};
+
+#pragma region UFO
+static const Hash ufoModel = 0xB467C540;
+static Object ufo;
+static bool ufoBusy = false;
+#pragma endregion
+
+#pragma region PTFX
+static const char *ptfxDict = "scr_rcbarry1";
+static const char *ptfxCreate = "scr_alien_teleport";
+#pragma endregion
+
+static void OnStart()
+{
+ m_aliens.clear();
+ Vector3 playerPos = GET_ENTITY_COORDS(PLAYER_PED_ID(), true);
+
+ LoadModel(ufoModel);
+ ufo = CreatePoolProp(ufoModel, 0.f, -4000.f, playerPos.z + 40, true);
+ SET_ENTITY_AS_MISSION_ENTITY(ufo, false, false);
+ SET_MODEL_AS_NO_LONGER_NEEDED(ufoModel);
+
+ REQUEST_NAMED_PTFX_ASSET(ptfxDict);
+ while (!HAS_NAMED_PTFX_ASSET_LOADED(ptfxDict))
+ {
+ WAIT(0);
+ }
+
+ Hash groupHash;
+ ADD_RELATIONSHIP_GROUP("_ALIENS", &groupHash);
+ SET_RELATIONSHIP_BETWEEN_GROUPS(5, groupHash, GET_HASH_KEY("PLAYER"));
+ SET_RELATIONSHIP_BETWEEN_GROUPS(5, groupHash, GET_HASH_KEY("CIVMALE"));
+ SET_RELATIONSHIP_BETWEEN_GROUPS(5, groupHash, GET_HASH_KEY("CIVFEMALE"));
+
+ ENABLE_ALIEN_BLOOD_VFX(true);
+
+ SET_AI_MELEE_WEAPON_DAMAGE_MODIFIER(.1f);
+ SET_AI_WEAPON_DAMAGE_MODIFIER(.1f);
+
+ while (!SLIDE_OBJECT(ufo, playerPos.x, playerPos.y, GET_ENTITY_COORDS(ufo, true).z, 10.f, 10.f, 1.f, false))
+ {
+ WAIT(0);
+ }
+}
+
+static void OnStop()
+{
+ for (Ped ped : m_aliens)
+ {
+ if (DOES_ENTITY_EXIST(ped))
+ {
+ Vector3 pedPos = GET_ENTITY_COORDS(ped, true);
+ USE_PARTICLE_FX_ASSET(ptfxDict);
+ START_PARTICLE_FX_NON_LOOPED_AT_COORD(ptfxCreate, pedPos.x, pedPos.y, pedPos.z, 0.f, 0.f, 0.f, 1.2f,
+ false, false, false);
+ DELETE_PED(&ped);
+ }
+ }
+ ufoBusy = false;
+
+ while (!SLIDE_OBJECT(ufo, 0.f, -4000.f, GET_ENTITY_COORDS(ufo, true).z, 10.f, 10.f, 1.f, false))
+ {
+ WAIT(0);
+ }
+
+ if (DOES_ENTITY_EXIST(ufo))
+ {
+ SET_OBJECT_AS_NO_LONGER_NEEDED(&ufo);
+ }
+
+ ENABLE_ALIEN_BLOOD_VFX(false);
+
+ RESET_AI_MELEE_WEAPON_DAMAGE_MODIFIER();
+ RESET_AI_WEAPON_DAMAGE_MODIFIER();
+}
+
+static void OnTick()
+{
+ static DWORD64 lastTick;
+ DWORD64 curTick = GetTickCount64();
+ static constexpr int MAX_ALIENS = 5;
+ static constexpr Hash MODEL_HASH = 0x64611296;
+
+ static Hash alienGroupHash = GET_HASH_KEY("_ALIENS");
+
+ Ped playerPed = PLAYER_PED_ID();
+ Vector3 playerPos = GET_ENTITY_COORDS(playerPed, false);
+
+ if (m_aliens.size() <= MAX_ALIENS && !ufoBusy)
+ {
+ Vector3 spawnPos;
+ if (GET_NTH_CLOSEST_VEHICLE_NODE(playerPos.x, playerPos.y, playerPos.z, 15 + m_aliens.size(), &spawnPos, 0, 0,
+ 0)
+ && GET_DISTANCE_BETWEEN_COORDS(playerPos.x, playerPos.y, playerPos.z, spawnPos.x, spawnPos.y, spawnPos.z,
+ false)
+ < 300.f)
+ {
+ ufoBusy = true;
+
+ while (!SLIDE_OBJECT(ufo, spawnPos.x, spawnPos.y, GET_ENTITY_COORDS(ufo, true).z, 1.f, 1.f, 1.f, false))
+ {
+ WAIT(0);
+ }
+
+ LoadModel(MODEL_HASH);
+
+ Ped alien = CreatePoolPed(26, MODEL_HASH, spawnPos.x, spawnPos.y, spawnPos.z, .0f);
+
+ SET_PED_COMPONENT_VARIATION(alien, 0, 0, 0, 0);
+ SET_PED_COMPONENT_VARIATION(alien, 3, 0, 0, 0);
+ SET_PED_COMPONENT_VARIATION(alien, 4, 0, 0, 0);
+ SET_PED_COMPONENT_VARIATION(alien, 5, 0, 0, 0);
+ SET_PED_COMPONENT_VARIATION(alien, 6, 0, 0, 0);
+
+ m_aliens.push_back(alien);
+
+ SET_PED_RELATIONSHIP_GROUP_HASH(alien, alienGroupHash);
+ SET_PED_COMBAT_ATTRIBUTES(alien, 5, true);
+ SET_PED_COMBAT_ATTRIBUTES(alien, 46, true);
+
+ SET_AMBIENT_VOICE_NAME(alien, "ALIENS");
+ DISABLE_PED_PAIN_AUDIO(alien, true);
+
+ GIVE_WEAPON_TO_PED(alien, m_weapons.at(g_Random.GetRandomInt(0, m_weapons.size()-1)), 9999, false, true);
+
+ TASK_COMBAT_PED(alien, playerPed, 0, 16);
+ SET_PED_FIRING_PATTERN(alien, 0x7A845691);
+
+ SET_MODEL_AS_NO_LONGER_NEEDED(MODEL_HASH);
+
+ Vector3 pedPos = GET_ENTITY_COORDS(alien, true);
+ USE_PARTICLE_FX_ASSET(ptfxDict);
+ START_PARTICLE_FX_NON_LOOPED_AT_COORD(ptfxCreate, pedPos.x, pedPos.y, pedPos.z, 0.f, 0.f, 0.f, 1.2f, false,
+ false, false);
+
+ ufoBusy = false;
+ }
+ }
+
+ for (std::list::iterator it = m_aliens.begin(); it != m_aliens.end();)
+ {
+ Ped alien = *it;
+ if (DOES_ENTITY_EXIST(alien))
+ {
+ Vector3 alienPos = GET_ENTITY_COORDS(alien, false);
+ if (GET_DISTANCE_BETWEEN_COORDS(playerPos.x, playerPos.y, playerPos.z, alienPos.x, alienPos.y, alienPos.z,
+ false)
+ < 300.f)
+ {
+ if (IS_PED_DEAD_OR_DYING(alien, true))
+ {
+ SET_PED_AS_NO_LONGER_NEEDED(&alien);
+ }
+ it++;
+ continue;
+ }
+ SET_PED_AS_NO_LONGER_NEEDED(&alien);
+ }
+ it = m_aliens.erase(it);
+ }
+
+ //Slowly rotate the ufo
+ if (lastTick < curTick - 10)
+ {
+ lastTick = curTick;
+
+ SET_ENTITY_ROTATION(ufo, 0.f, 0.f, GET_ENTITY_HEADING(ufo) + 0.1f, 2, true);
+ }
+}
+
+// clang-format off
+REGISTER_EFFECT(OnStart, OnStop, OnTick, EffectInfo
+ {
+ .Name = "Alien Invasion",
+ .Id = "aliens",
+ .IsTimed = true
+ }
+);
\ No newline at end of file
diff --git a/ConfigApp/Effects.cs b/ConfigApp/Effects.cs
index e045e76e7..8e2ad7b9a 100644
--- a/ConfigApp/Effects.cs
+++ b/ConfigApp/Effects.cs
@@ -372,6 +372,7 @@ public enum EffectTimedType
{ "screen_colorfulworld", new EffectInfo("Colorful World", EffectCategory.Screen, true) },
{ "screen_arc", new EffectInfo("Arced Screen", EffectCategory.Screen, true, true) },
{ "world_blackhole", new EffectInfo("Black Hole", EffectCategory.Misc, true, true) },
+ { "aliens", new EffectInfo("Alien Invasion", EffectCategory.Peds, true) },
};
}
}