#include "vaultscript.h"
#include <map>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <ctime>
#include <cstdlib>
using namespace vaultmp;
enum class MutantState : unsigned int
{
MUTANT_IDLE = 0x01,
MUTANT_ALERT = MUTANT_IDLE << 1,
MUTANT_AGGRO = MUTANT_ALERT << 1,
MUTANT_DEAD = MUTANT_AGGRO << 1,
};
static Base mutantType = static_cast<Base>(CREA::CrSuperMutant1GunA);
static IDHash<MutantState> mutantsAI;
static IDHash<Value> mutantsHealth;
static IDHash<ID> mutantsTarget;
static Value mutantHealth = 150.0;
static Value mutantAlert = 500.0;
static Value mutantAggro = 700.0;
static Value mutantLeash = 1300.0;
static UCount mutantRate = 4;
Void VAULTSCRIPT exec() noexcept
{
std::printf("My first C++ vaultscript <3\n");
SetServerName("vaultmp 0.1a server");
SetServerRule("website", "vaultmp.com");
SetServerMap("the wasteland");
std::srand(std::time(nullptr));
}
void AdvancePosition(Value& X, Value& Y, Value aZ, Value offset)
{
X += (offset * std::sin((aZ / 360.0) * 2 * M_PI));
Y += (offset * std::cos((aZ / 360.0) * 2 * M_PI));
}
Result RemoveObject(ID object_) noexcept
{
DestroyObject(object_);
mutantsAI.erase(object_);
mutantsTarget.erase(object_);
mutantsHealth.erase(object_);
KillTimer();
return static_cast<Result>(0);
}
Result MutantAI(ID) noexcept;
Result SleepTimer2(ID object_) noexcept
{
KillTimer();
AddItem(object_, static_cast<Base>(WEAP::WeapHuntingRifle));
EquipItem(object_, static_cast<Base>(WEAP::WeapHuntingRifle));
return static_cast<Result>(0);
}
Result SleepTimer(ID object_) noexcept
{
KillTimer();
CreateTimerEx(MutantAI, static_cast<Interval>(100), object_);
return static_cast<Result>(0);
}
Result MutantAI(ID mutant_) noexcept
{
Actor mutant(mutant_);
if (mutant)
{
if (mutant.GetActorDead())
{
mutantsAI[mutant_] = MutantState::MUTANT_DEAD;
KillTimer();
CreateTimerEx(RemoveObject, static_cast<Interval>(8000), mutant_);
}
else
{
if (mutantsAI[mutant_] == MutantState::MUTANT_AGGRO)
{
if (!mutant.GetActorAlerted())
{
mutant.SetActorAlerted(True);
KillTimer();
CreateTimerEx(SleepTimer, static_cast<Interval>(2000), mutant_);
}
else
{
Actor actor(mutantsTarget[mutant_]);
static Index idle = static_cast<Index>(0x00);
if (actor && !actor.GetActorDead())
{
Value actorX, actorY, actorZ;
Value mutantX, mutantY, mutantZ, mutantAX, mutantAY, mutantAZ;
actor.GetPos(actorX, actorY, actorZ);
mutant.GetPos(mutantX, mutantY, mutantZ);
mutant.GetAngle(mutantAX, mutantAY, mutantAZ);
mutantAZ = atan2(actorX - mutantX, actorY - mutantY) * 180 / M_PI;
if (mutantAZ < 0)
mutantAZ += 360.0;
mutant.SetAngle(mutantAX, mutantAY, mutantAZ);
static Index aim = static_cast<Index>(0x11);
mutant.SetActorWeaponAnimation(aim);
if (!mutant.IsNearPoint(actorX, actorY, actorZ, mutantLeash))
{
mutant.SetActorAlerted(False);
mutant.SetActorWeaponAnimation(idle);
mutantsAI[mutant_] = MutantState::MUTANT_IDLE;
}
else
{
static unsigned int rate = 0;
if (rate == mutantRate)
{
mutant.FireWeapon();
rate = 0;
}
else
rate++;
}
}
else
{
mutant.SetActorAlerted(False);
mutant.SetActorWeaponAnimation(idle);
mutantsAI[mutant_] = MutantState::MUTANT_IDLE;
}
}
}
else
{
auto actors = Actor::GetList();
auto players = Player::GetList();
actors.insert(actors.end(), players.begin(), players.end());
for (const auto& actor_ : actors)
{
Actor actor(actor_);
if (actor.GetBase() == mutantType || actor.GetActorDead())
continue;
Value X, Y, Z;
actor.GetPos(X, Y, Z);
if (actor.GetCell() == mutant.GetCell() && mutant.IsNearPoint(X, Y, Z, mutantAlert) && mutantsAI[mutant_] == MutantState::MUTANT_IDLE)
mutantsAI[mutant_] = MutantState::MUTANT_ALERT;
}
}
}
}
else
KillTimer();
return static_cast<Result>(0);
}
Void VAULTSCRIPT OnServerInit() noexcept
{
}
NPC_ VAULTSCRIPT OnPlayerRequestGame(ID player) noexcept
{
return static_cast<NPC_>(0x00000000);
}
State VAULTSCRIPT OnPlayerChat(ID player, RawString message) noexcept
{
if (!std::strcmp(message, "/mutant"))
{
static std::map<unsigned char, std::pair<double, double>> values {
{0x00, {2.000000, 2.000000}},
{0x01, {4.000000, 4.000000}},
{0x02, {50.000000, 50.000000}},
{0x03, {50.000000, 50.000000}},
{0x05, {7.000000, 7.000000}},
{0x06, {4.000000, 4.000000}},
{0x07, {6.000000, 6.000000}},
{0x08, {2.000000, 2.000000}},
{0x09, {2.000000, 2.000000}},
{0x0A, {6.000000, 6.000000}},
{0x0B, {5.000000, 5.000000}},
{0x0D, {220.000000, 220.000000}},
{0x0E, {5.000000, 5.000000}},
{0x0F, {5.000000, 5.000000}},
{0x10, {mutantHealth, mutantHealth}},
{0x11, {3.000000, 3.000000}},
{0x13, {25.000000, 25.000000}},
{0x14, {10.000000, 10.000000}},
{0x15, {100.000000, 100.000000}},
{0x16, {100.000000, 100.000000}},
{0x17, {-500.000000, -500.000000}},
{0x19, {100.000000, 100.000000}},
{0x1A, {100.000000, 100.000000}},
{0x1B, {100.000000, 100.000000}},
{0x1C, {100.000000, 100.000000}},
{0x1D, {100.000000, 100.000000}},
{0x1E, {100.000000, 100.000000}},
{0x1F, {100.000000, 100.000000}},
{0x21, {75.000000, 75.000000}},
{0x22, {75.000000, 75.000000}},
{0x23, {75.000000, 75.000000}},
{0x26, {75.000000, 75.000000}},
{0x29, {75.000000, 75.000000}},
{0x2D, {75.000000, 75.000000}},
{0x38, {4.000000, 4.250000}},
{0x39, {2.000000, 2.000000}}
};
static Value offset = 1000.0;
Value X, Y, Z, aX, aY, aZ;
GetPos(player, X, Y, Z);
GetAngle(player, aX, aY, aZ);
AdvancePosition(X, Y, aZ, offset);
ID mutant = CreateActor(static_cast<Base>(mutantType), GetCell(player), X, Y, Z);
aZ += 180.0;
if (aZ > 360.0)
aZ -= 360.0;
else if (aZ < 0.00)
aZ += 360.0;
SetAngle(mutant, aX, aY, aZ);
for (const auto& value : values)
{
SetActorBaseValue(mutant, static_cast<ActorValue>(value.first), value.second.first);
SetActorValue(mutant, static_cast<ActorValue>(value.first), value.second.second);
}
CreateTimerEx(SleepTimer2, static_cast<Interval>(1500), mutant);
mutantsAI[mutant] = MutantState::MUTANT_IDLE;
mutantsHealth[mutant] = mutantHealth;
CreateTimerEx(MutantAI, static_cast<Interval>(100), mutant);
}
else if (!std::strcmp(message, "/away"))
DestroyObject(GetID(static_cast<Ref>(0x04135B)));
else if (!std::strcmp(message, "/smoke"))
PlayIdle(player, IDLE::LooseSmokingStanding);
else if (!std::strcmp(message, "/drink"))
PlayIdle(player, IDLE::DukovDrinkStand01);
else if (!std::strcmp(message, "/young"))
AgeActorBaseRace(player, -1);
else if (!std::strcmp(message, "/male"))
SetActorBaseSex(player, False);
else if (!std::strcmp(message, "/female"))
SetActorBaseSex(player, True);
else
return True;
return False;
}
Void VAULTSCRIPT OnSpawn(ID object) noexcept
{
Player player(object);
if (player)
{
player.UIMessage("Hello, " + player.GetBaseName() + "!");
player.AddItem({
{WEAP::Weap10mmPistol},
{WEAP::WeapShotgunSawedOff},
{AMMO::Ammo10mm, 500},
{AMMO::AmmoShotgunShell, 500},
{ARMO::KIDOutfitWastelandChild01}
});
}
}
Void VAULTSCRIPT OnActorValueChange(ID actor, ActorValue index, Value value) noexcept
{
if (mutantsAI.find(actor) != mutantsAI.end() && index == ActorValue::Health)
mutantsHealth[actor] = value;
}
void MutantAttackRoutine(ID actor)
{
Value X, Y, Z;
GetPos(actor, X, Y, Z);
for (auto& mutant_ : mutantsAI)
{
Actor mutant(mutant_.first);
if (mutant && mutant.GetCell() == GetCell(actor) && mutant.IsNearPoint(X, Y, Z, mutantAggro) && (mutant_.second == MutantState::MUTANT_IDLE || mutant_.second == MutantState::MUTANT_ALERT))
{
mutant_.second = MutantState::MUTANT_AGGRO;
mutantsTarget[mutant_.first] = actor;
}
}
}
Void VAULTSCRIPT OnActorPunch(ID actor, State power) noexcept
{
MutantAttackRoutine(actor);
}
Void VAULTSCRIPT OnActorFireWeapon(ID actor, WEAP weapon) noexcept
{
MutantAttackRoutine(actor);
}