1330 lines
28 KiB
SourcePawn
1330 lines
28 KiB
SourcePawn
/*
|
|
**
|
|
*/
|
|
#if defined _FLY_MM_included
|
|
#endinput
|
|
#endif
|
|
#define _FLY_MM_included
|
|
#include <basic>
|
|
#include <vscripts>
|
|
#include <adt_array>
|
|
#include <float>
|
|
|
|
enum Fly_Type
|
|
{
|
|
eFlyBase = 0,
|
|
eFlySmall = 1,
|
|
eFly = 2,
|
|
eFlyEnd = 3,
|
|
eFlyEndHovno = 4
|
|
};
|
|
|
|
float TOASTER_POSITION[] = { 7063.0, 2329.0, -360.0 };
|
|
|
|
const int t_len = 6;
|
|
float TARGET_NODES[][] = {
|
|
{-2400.0, 5136.0, -611.0},
|
|
{5824.0, 2337.0, -64.0},
|
|
{3600.0, 4496.0, -256.0},
|
|
{3456.0, 7680.0, -375.98},
|
|
{2080.0, 9790.1, -2696.0},
|
|
{1100.99, 10777.0, -2680.0}
|
|
};
|
|
|
|
//const int t_len_0 = 6, t_len_1 = 1;
|
|
//float TARGET_NODES2[][][] = {
|
|
//{
|
|
//{5756.0, 4749.0, -390.0},
|
|
//{6000.0, 2336.0, -288.0},
|
|
//{3608.0, 4496.0, -472.0},
|
|
//{3456.0, 7680.0, -375.98},
|
|
//{2080.0, 9790.1, -2696.0},
|
|
//{1100.99, 10777.0, -2680.0}
|
|
//},
|
|
//{
|
|
//{895.99, 11192.0, -2216.0},
|
|
//{0.0, 0.0, 0.0},
|
|
//{0.0, 0.0, 0.0},
|
|
//{0.0, 0.0, 0.0},
|
|
//{0.0, 0.0, 0.0},
|
|
//{0.0, 0.0, 0.0}
|
|
//}
|
|
//};
|
|
|
|
public bool IsValidPlayer(int player)
|
|
{
|
|
return player >= 1 && player <= 64 && IsValidEntity(player) && IsPlayerAlive(player);
|
|
}
|
|
|
|
methodmap Fly_base < Basic
|
|
{
|
|
public Fly_base(int entity)
|
|
{
|
|
Basic myclass = new Basic();
|
|
myclass.SetInt("iEntity", entity);
|
|
myclass.SetFloat("fSpeed", 25.0);
|
|
myclass.SetFloat("fRotation_speed", 0.05);
|
|
myclass.SetFloat("fPrevious_distance_to_target", -1.0);
|
|
myclass.SetFloat("fCurrent_distance_to_target", -1.0);
|
|
myclass.SetFloat("fBlocker1", 0.0);
|
|
myclass.SetFloat("fBlocker2", 100.0);
|
|
myclass.SetFloat("fRot_speed_min", 0.05);
|
|
myclass.SetFloat("fRot_speed_max", 0.2);
|
|
myclass.SetFloat("fRot_speed_acceleration", 0.0005);
|
|
myclass.SetFloat("fRot_err", 0.15);
|
|
myclass.SetFloat("fSpeed_acceleration", 0.3);
|
|
myclass.SetFloat("fMax_speed", 50.0);
|
|
myclass.SetInt("iType", view_as<int>(eFlyBase));
|
|
myclass.SetBool("bDoNextTick", true);
|
|
return view_as<Fly_base>(myclass);
|
|
}
|
|
|
|
property bool doNextTick
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetBool("bDoNextTick");
|
|
}
|
|
public set(bool val)
|
|
{
|
|
this.SetBool("bDoNextTick", val);
|
|
}
|
|
}
|
|
|
|
property Fly_Type type
|
|
{
|
|
public get()
|
|
{
|
|
return view_as<Fly_Type>(this.GetInt("iType"));
|
|
}
|
|
public set(Fly_Type val)
|
|
{
|
|
this.SetInt("iType", view_as<int>(val));
|
|
}
|
|
}
|
|
|
|
property float max_speed
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetFloat("fMax_speed");
|
|
}
|
|
public set(float val)
|
|
{
|
|
this.SetFloat("fMax_speed", val);
|
|
}
|
|
}
|
|
|
|
property float speed_acceleration
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetFloat("fSpeed_acceleration");
|
|
}
|
|
public set(float val)
|
|
{
|
|
this.SetFloat("fSpeed_acceleration", val);
|
|
}
|
|
}
|
|
|
|
property float rot_err
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetFloat("fRot_err");
|
|
}
|
|
public set(float val)
|
|
{
|
|
this.SetFloat("fRot_err", val);
|
|
}
|
|
}
|
|
|
|
property float rot_speed_acceleration
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetFloat("fRot_speed_acceleration");
|
|
}
|
|
public set(float val)
|
|
{
|
|
this.SetFloat("fRot_speed_acceleration", val);
|
|
}
|
|
}
|
|
|
|
property float rot_speed_min
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetFloat("fRot_speed_min");
|
|
}
|
|
public set(float val)
|
|
{
|
|
this.SetFloat("fRot_speed_min", val);
|
|
}
|
|
}
|
|
|
|
property float rot_speed_max
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetFloat("fRot_speed_max");
|
|
}
|
|
public set(float val)
|
|
{
|
|
this.SetFloat("fRot_speed_max", val);
|
|
}
|
|
}
|
|
|
|
property float blocker1
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetFloat("fBlocker1");
|
|
}
|
|
public set(float val)
|
|
{
|
|
this.SetFloat("fBlocker1", val);
|
|
}
|
|
}
|
|
|
|
property float blocker2
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetFloat("fBlocker2");
|
|
}
|
|
public set(float val)
|
|
{
|
|
this.SetFloat("fBlocker2", val);
|
|
}
|
|
}
|
|
|
|
property int entity
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetInt("iEntity");
|
|
}
|
|
}
|
|
|
|
property float speed
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetFloat("fSpeed");
|
|
}
|
|
public set(float val)
|
|
{
|
|
this.SetFloat("fSpeed", val);
|
|
}
|
|
}
|
|
|
|
property float rotation_speed
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetFloat("fRotation_speed");
|
|
}
|
|
public set(float val)
|
|
{
|
|
this.SetFloat("fRotation_speed", val);
|
|
}
|
|
}
|
|
|
|
property float previous_distance_to_target
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetFloat("fPrevious_distance_to_target");
|
|
}
|
|
public set(float val)
|
|
{
|
|
this.SetFloat("fPrevious_distance_to_target", val);
|
|
}
|
|
}
|
|
|
|
property float current_distance_to_target
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetFloat("fCurrent_distance_to_target");
|
|
}
|
|
public set(float val)
|
|
{
|
|
this.SetFloat("fCurrent_distance_to_target", val);
|
|
}
|
|
}
|
|
public void MoveTowardsTarget(const float[3] fly, const float[3] target)
|
|
{
|
|
float targetDir[3];
|
|
SubtractVectors(target, fly, targetDir);
|
|
NormalizeVector(targetDir, targetDir);
|
|
float currentDir[3];
|
|
GetForwardVector(this.entity, currentDir);
|
|
float dir[3];
|
|
GetNewDir(this, targetDir, currentDir, dir);
|
|
dir[2] = targetDir[2];
|
|
SetForwardVector(this.entity, dir);
|
|
MoveForward(this, this.blocker1, this.blocker2);
|
|
}
|
|
}
|
|
|
|
methodmap Fly_Small < Fly_base
|
|
{
|
|
public Fly_Small(int entity)
|
|
{
|
|
Fly_base myclass = new Fly_base(entity);
|
|
myclass.SetBool("bDead", false);
|
|
myclass.SetInt("iRetarget", 10);
|
|
myclass.SetInt("iTarget", -1);
|
|
myclass.type = eFlySmall;
|
|
return view_as<Fly_Small>(myclass);
|
|
}
|
|
|
|
property bool dead
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetBool("bDead");
|
|
}
|
|
public set(bool val)
|
|
{
|
|
this.SetBool("bDead", val);
|
|
}
|
|
}
|
|
|
|
property int retarget
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetInt("iRetarget");
|
|
}
|
|
public set(int val)
|
|
{
|
|
this.SetInt("iRetarget", val);
|
|
}
|
|
}
|
|
|
|
property int target
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetInt("iTarget");
|
|
}
|
|
public set(int val)
|
|
{
|
|
this.SetInt("iTarget", val);
|
|
}
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
|
|
float currentAngle[3];
|
|
GetForwardVector(this.entity, currentAngle);
|
|
currentAngle[2] = 0.0;
|
|
SetForwardVector(this.entity, currentAngle);
|
|
float orig[3];
|
|
GetOrigin(this.entity, orig);
|
|
orig[2] += 40.0;
|
|
SetOrigin(this.entity, orig);
|
|
|
|
CreateTimer(0.0, Tick_Cb, this, TIMER_FLAG_NO_MAPCHANGE);
|
|
}
|
|
|
|
public void Tick()
|
|
{
|
|
|
|
float flyPos[3], flyPos_copy[3];
|
|
GetOrigin(this.entity, flyPos);
|
|
GetOrigin(this.entity, flyPos_copy);
|
|
flyPos_copy[2] -= 300.0;
|
|
if (this.dead)
|
|
{
|
|
float distToFloor = TraceLine(flyPos, flyPos_copy, this.entity);
|
|
if (distToFloor < 0.03)
|
|
{
|
|
|
|
EntFireByIndex(this.entity, "SetAnimation", "dead", "0.0", -1);
|
|
EntFireByIndex(this.entity, "SetAnimation", "dead_loop", "2.0", -1);
|
|
EntFireByIndex(this.entity, "kill", "", "20.0", -1);
|
|
delete this;
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
|
|
MoveDir(this, {0.0, 0.0, -1.0});
|
|
}
|
|
}
|
|
|
|
/*** Move towards a targetted player ***/
|
|
else if(IsValidPlayer(this.target))
|
|
{
|
|
|
|
ChasePlayer(this, flyPos);
|
|
}
|
|
|
|
/*** Search for a target player ***/
|
|
else
|
|
{
|
|
|
|
this.target = GetNewTarget(this);
|
|
flyPos_copy[2] += 400.0;
|
|
if (this.target == -1 && TraceLine(flyPos, flyPos_copy, this.entity) >= 1.0)
|
|
{
|
|
MoveDir(this, {0.0, 0.0, 1.0});
|
|
}
|
|
}
|
|
CreateTimer(0.0, Tick_Cb, this, TIMER_FLAG_NO_MAPCHANGE);
|
|
}
|
|
public void Die()
|
|
{
|
|
|
|
this.dead = true;
|
|
this.speed = 0.0;
|
|
}
|
|
}
|
|
|
|
methodmap Fly < Fly_Small
|
|
{
|
|
public Fly(int entity)
|
|
{
|
|
Fly_Small myclass = new Fly_Small(entity);
|
|
myclass.type = eFly;
|
|
myclass.speed = 35.0;
|
|
myclass.retarget = 8;
|
|
myclass.blocker1 = 50.0;
|
|
myclass.blocker2 = 160.0;
|
|
myclass.rot_speed_min = 0.025;
|
|
myclass.rot_speed_max = 0.1;
|
|
myclass.speed_acceleration = 0.25;
|
|
myclass.max_speed = 85.0;
|
|
myclass.SetBool("bStarted", false);
|
|
myclass.SetBool("bGrabbed_player", false);
|
|
myclass.SetBool("bReturn_to_toaster", false);
|
|
myclass.SetBool("bSpawn_eggs", false);
|
|
myclass.SetInt("iHealth", 1000);
|
|
myclass.SetInt("iPlayers_in_arena", 0);
|
|
myclass.SetInt("iEggs_currently_spawned", 0);
|
|
myclass.SetInt("iMax_spawned_eggs", 0);
|
|
myclass.SetHandle("lGrabbed_players", new ArrayList());
|
|
myclass.SetHandle("lGrabbed_players_dead", new ArrayList());
|
|
return view_as<Fly>(myclass);
|
|
}
|
|
|
|
property bool started
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetBool("bStarted");
|
|
}
|
|
public set(bool val)
|
|
{
|
|
this.SetBool("bStarted", val);
|
|
}
|
|
}
|
|
property bool grabbed_player
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetBool("bGrabbed_player");
|
|
}
|
|
public set(bool val)
|
|
{
|
|
this.SetBool("bGrabbed_player", val);
|
|
}
|
|
}
|
|
property bool return_to_toaster
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetBool("bReturn_to_toaster");
|
|
}
|
|
public set(bool val)
|
|
{
|
|
this.SetBool("bReturn_to_toaster", val);
|
|
}
|
|
}
|
|
property bool spawn_eggs
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetBool("bSpawn_eggs");
|
|
}
|
|
public set(bool val)
|
|
{
|
|
this.SetBool("bSpawn_eggs", val);
|
|
}
|
|
}
|
|
property int health
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetInt("iHealth");
|
|
}
|
|
public set(int val)
|
|
{
|
|
this.SetInt("iHealth", val);
|
|
}
|
|
}
|
|
property int players_in_arena
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetInt("iPlayers_in_arena");
|
|
}
|
|
public set(int val)
|
|
{
|
|
this.SetInt("iPlayers_in_arena", val);
|
|
}
|
|
}
|
|
property int eggs_currently_spawned
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetInt("iEggs_currently_spawned");
|
|
}
|
|
public set(int val)
|
|
{
|
|
this.SetInt("iEggs_currently_spawned", val);
|
|
}
|
|
}
|
|
property int max_spawned_eggs
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetInt("iMax_spawned_eggs");
|
|
}
|
|
public set(int val)
|
|
{
|
|
this.SetInt("iMax_spawned_eggs", val);
|
|
}
|
|
}
|
|
property ArrayList grabbed_players
|
|
{
|
|
public get()
|
|
{
|
|
return view_as<ArrayList>(this.GetHandle("lGrabbed_players"));
|
|
}
|
|
public set(ArrayList list)
|
|
{
|
|
this.SetHandle("lGrabbed_players", list);
|
|
}
|
|
}
|
|
property ArrayList grabbed_players_dead
|
|
{
|
|
public get()
|
|
{
|
|
return view_as<ArrayList>(this.GetHandle("lGrabbed_players_dead"));
|
|
}
|
|
public set(ArrayList list)
|
|
{
|
|
this.SetHandle("lGrabbed_players_dead", list);
|
|
}
|
|
}
|
|
|
|
public void TeleportGrabbedPlayers(const float[3] position)
|
|
{
|
|
for (int i = 0; i < this.grabbed_players.Length; i++)
|
|
{
|
|
if (IsValidPlayer(this.grabbed_players.Get(i)))
|
|
{
|
|
if(GetClientTeam(this.grabbed_players.Get(i)) == 3)
|
|
SetOrigin(this.grabbed_players.Get(i), position);
|
|
}
|
|
}
|
|
}
|
|
|
|
public bool IsValidTarget()
|
|
{
|
|
return IsValidPlayer(this.target) && !IsElementInArray(this.target, this.grabbed_players) && !IsElementInArray(this.target, this.grabbed_players_dead);
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
this.max_spawned_eggs = this.players_in_arena / 6;
|
|
this.started = true;
|
|
EntFireByIndex(this.entity, "SetAnimation", "fly", "0.00", -1);
|
|
CreateTimer(0.0, Tick_Cb, this, TIMER_FLAG_NO_MAPCHANGE);
|
|
}
|
|
|
|
public void KillFly()
|
|
{
|
|
delete this.grabbed_players_dead;
|
|
delete this.grabbed_players;
|
|
delete this;
|
|
}
|
|
|
|
public void Tick()
|
|
{
|
|
float flyPos[3], flyPos_copy[3];
|
|
GetOrigin(this.entity, flyPos);
|
|
GetOrigin(this.entity, flyPos_copy);
|
|
flyPos_copy[2] -= 300.0;
|
|
float distToFloor = TraceLine(flyPos, flyPos_copy, this.entity);
|
|
|
|
/*****************************/
|
|
/*** Stuff done every tick ***/
|
|
/*****************************/
|
|
|
|
/*** Grab a near player ***/
|
|
int playerNear;
|
|
float point[3], fwd[3];
|
|
GetForwardVector(this.entity, fwd);
|
|
ScaleVector(fwd, 80.0);
|
|
AddVectors(flyPos, fwd, point);
|
|
|
|
if(!this.dead && (playerNear = FindEntityByClassnameWithin(playerNear, "player", point, 64.0)) != -1)
|
|
{
|
|
if(GetClientTeam(playerNear) == 3)
|
|
{
|
|
if(!IsElementInArray(playerNear, this.grabbed_players) && !IsElementInArray(playerNear, this.grabbed_players_dead))
|
|
{
|
|
this.grabbed_players.Push(playerNear);
|
|
this.grabbed_players_dead.Push(playerNear);
|
|
|
|
if ((this.target = GetNewTarget(this)) == -1 || !this.IsValidTarget())
|
|
this.return_to_toaster = true;
|
|
else if (!this.grabbed_player)
|
|
CreateTimer(15.0, SetReturn_Cb, this, TIMER_FLAG_NO_MAPCHANGE);
|
|
if (playerNear == this.target)
|
|
this.target = -1;
|
|
|
|
this.grabbed_player = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*** Teleport grabbed players ***/
|
|
if (!this.dead)
|
|
{
|
|
flyPos_copy[2] += 260;
|
|
this.TeleportGrabbedPlayers(flyPos_copy);
|
|
}
|
|
|
|
/*** Random chance to spawn an egg ***/
|
|
if (!this.grabbed_player && this.eggs_currently_spawned != this.max_spawned_eggs && GetRandomInt(0, 500) == 0 && distToFloor > 0.1)
|
|
{
|
|
this.spawn_eggs = true;
|
|
}
|
|
|
|
/*************************/
|
|
/*** Decide what to do ***/
|
|
/*************************/
|
|
|
|
/*** Fly died - fall to the ground ***/
|
|
if (this.dead)
|
|
{
|
|
|
|
if (distToFloor < 0.05)
|
|
{
|
|
EntFire("fly_dead", "FireUser1", "", "0.00", -1);
|
|
EntFire("fly", "Kill", "", "0.02", -1);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
MoveDir(this, {0.0, 0.0, -1.0});
|
|
}
|
|
}
|
|
|
|
/*** Move to the floor to spawn eggs ***/
|
|
else if (!this.grabbed_player && this.spawn_eggs && this.eggs_currently_spawned < this.max_spawned_eggs && distToFloor < 1.0 && this.speed < this.max_speed / 2.0)
|
|
{
|
|
this.spawn_eggs = false;
|
|
this.eggs_currently_spawned++;
|
|
int eggSpawner = GetEntityIndexByHammerID(1248969, "env_entity_maker");
|
|
TeleportEntity(eggSpawner, flyPos, { 0.0, 0.0, 0.0 }, NULL_VECTOR);
|
|
AcceptEntityInput(eggSpawner, "ForceSpawn");
|
|
}
|
|
|
|
/*** Move towards a targetted player ***/
|
|
else if(!this.return_to_toaster && IsValidPlayer(this.target))
|
|
{
|
|
ChasePlayer(this, flyPos);
|
|
}
|
|
|
|
/*** Take the grabbed player(s) above the toaster ***/
|
|
else if(this.return_to_toaster)
|
|
{
|
|
// Fast approx of distance without needing sqrt
|
|
this.current_distance_to_target = FloatAbs(TOASTER_POSITION[0] - flyPos[0]) + FloatAbs(TOASTER_POSITION[1] - flyPos[1]);
|
|
|
|
float distToToaster[3];
|
|
SubtractVectors(flyPos, TOASTER_POSITION, distToToaster);
|
|
if (FloatAbs(distToToaster[0]) < 80.0 && FloatAbs(distToToaster[1]) < 80.0 && FloatAbs(distToToaster[2]) < 80.0)
|
|
{
|
|
this.grabbed_player = false;
|
|
this.return_to_toaster = false;
|
|
this.grabbed_players.Clear();
|
|
this.previous_distance_to_target = -1.0;
|
|
}
|
|
else
|
|
{
|
|
this.MoveTowardsTarget(flyPos, TOASTER_POSITION);
|
|
this.previous_distance_to_target = this.current_distance_to_target;
|
|
}
|
|
}
|
|
|
|
/*** Search for a target player ***/
|
|
else
|
|
{
|
|
this.target = GetNewTarget(this);
|
|
if (!this.IsValidTarget())
|
|
this.target = -1;
|
|
flyPos_copy[2] += 140;
|
|
if (this.target == -1 && TraceLine(flyPos, flyPos_copy, this.entity) >= 1.0)
|
|
MoveDir(this, { 0.0, 0.0, 1.0 } );
|
|
}
|
|
CreateTimer(0.0, Tick_Cb, this, TIMER_FLAG_NO_MAPCHANGE);
|
|
}
|
|
|
|
public void SetReturn(bool state)
|
|
{
|
|
this.return_to_toaster = state;
|
|
}
|
|
|
|
public void AddHealth(int hp)
|
|
{
|
|
this.health += hp;
|
|
this.players_in_arena++;
|
|
}
|
|
|
|
public void Hit()
|
|
{
|
|
if (this.started && !this.dead)
|
|
{
|
|
this.health--;
|
|
char param[256];
|
|
Format(param, sizeof(param), "message Fly %i HP", this.health);
|
|
EntFire("fly_text", "AddOutput", param, "0.0", -1);
|
|
EntFire("fly_text", "Display", "", "0.01", -1);
|
|
}
|
|
|
|
if (this.health == 0 && !this.dead)
|
|
{
|
|
EntFire("fly_dead_relay", "Trigger", "", "0.0", -1);
|
|
this.dead = true;
|
|
float flyPos[3];
|
|
GetOrigin(this.entity, flyPos);
|
|
flyPos[2] += 160.0;
|
|
this.TeleportGrabbedPlayers(flyPos);
|
|
this.grabbed_player = false;
|
|
this.grabbed_players.Clear();
|
|
this.speed = 0.0;
|
|
}
|
|
}
|
|
|
|
public void IncrementEggCount(int count)
|
|
{
|
|
this.eggs_currently_spawned += count;
|
|
}
|
|
}
|
|
|
|
public Action SetReturn_Cb(Handle timer, Fly fly)
|
|
{
|
|
KillTimer(timer);
|
|
fly.SetReturn(true);
|
|
return Plugin_Stop;
|
|
}
|
|
|
|
methodmap Fly_End < Fly_base
|
|
{
|
|
public Fly_End(int entity)
|
|
{
|
|
Fly_base myclass = new Fly_base(entity);
|
|
myclass.type = eFlyEnd;
|
|
myclass.blocker1 = 60.0;
|
|
myclass.blocker2 = 60.0;
|
|
myclass.rot_speed_max = 0.4;
|
|
myclass.rot_speed_min = 0.1;
|
|
myclass.speed_acceleration = 0.25;
|
|
myclass.max_speed = 85.0;
|
|
myclass.SetBool("bEnd", false);
|
|
myclass.SetInt("iCurrent_node", 0);
|
|
myclass.SetHandle("lGrabbed_players", new ArrayList());
|
|
myclass.speed = 35.0;
|
|
return view_as<Fly_End>(myclass);
|
|
}
|
|
property bool end
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetBool("bEnd");
|
|
}
|
|
public set(bool val)
|
|
{
|
|
this.SetBool("bEnd", val);
|
|
}
|
|
}
|
|
property int current_node
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetInt("iCurrent_node");
|
|
}
|
|
public set(int val)
|
|
{
|
|
this.SetInt("iCurrent_node", val);
|
|
}
|
|
}
|
|
property ArrayList grabbed_players
|
|
{
|
|
public get()
|
|
{
|
|
return view_as<ArrayList>(this.GetHandle("lGrabbed_players"));
|
|
}
|
|
public set(ArrayList list)
|
|
{
|
|
this.SetHandle("lGrabbed_players", list);
|
|
}
|
|
}
|
|
public void TeleportGrabbedPlayers(const float[3] position)
|
|
{
|
|
for (int i = 0; i < this.grabbed_players.Length; i++)
|
|
{
|
|
if (IsValidPlayer(this.grabbed_players.Get(i)))
|
|
{
|
|
if(GetClientTeam(this.grabbed_players.Get(i)) == 3)
|
|
SetOrigin(this.grabbed_players.Get(i), position);
|
|
}
|
|
}
|
|
}
|
|
|
|
public void KillFly()
|
|
{
|
|
delete this.grabbed_players;
|
|
delete this;
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
EntFireByIndex(this.entity, "SetAnimation", "fly", "0.00", -1);
|
|
CreateTimer(0.0, Tick_Cb, this, TIMER_FLAG_NO_MAPCHANGE);
|
|
}
|
|
public void Tick()
|
|
{
|
|
float flyPos[3], flyPos_copy[3];
|
|
GetOrigin(this.entity, flyPos);
|
|
GetOrigin(this.entity, flyPos_copy);
|
|
float targetNode[3];
|
|
MakeVectorFromPoints( { 0.0, 0.0, 0.0 }, TARGET_NODES[this.current_node], targetNode);
|
|
int playerNear;
|
|
float point[3], fwd[3];
|
|
GetForwardVector(this.entity, fwd);
|
|
ScaleVector(fwd, 80.0);
|
|
AddVectors(flyPos, fwd, point);
|
|
|
|
/*** Kill nearby physboxes ***/
|
|
int physbox;
|
|
if ((physbox = FindEntityByClassnameWithin(physbox, "func_physbox", flyPos, 350.0)) != -1)
|
|
{
|
|
EntFireByIndex(physbox, "FireUser2", "", "0.00", -1);
|
|
}
|
|
|
|
/*** Grab a near player ***/
|
|
if((playerNear = FindEntityByClassnameWithin(playerNear, "player", point, 100.0)) != -1)
|
|
{
|
|
if(GetClientTeam(playerNear) == 3)
|
|
{
|
|
if(!IsElementInArray(playerNear, this.grabbed_players))
|
|
{
|
|
this.grabbed_players.Push(playerNear);
|
|
}
|
|
}
|
|
}
|
|
|
|
if((playerNear = FindEntityByClassnameWithin(playerNear, "player", point, 100.0)) != -1)
|
|
{
|
|
if(GetClientTeam(playerNear) == 3)
|
|
{
|
|
if(!IsElementInArray(playerNear, this.grabbed_players))
|
|
{
|
|
this.grabbed_players.Push(playerNear);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*** Teleport grabbed players ***/
|
|
flyPos_copy[2] -= 40.0;
|
|
this.TeleportGrabbedPlayers(flyPos_copy);
|
|
|
|
/*** Move towards the next node ***/
|
|
// Fast approx of distance without needing sqrt
|
|
this.current_distance_to_target = FloatAbs(targetNode[0] - flyPos[0]) + FloatAbs(targetNode[1] - flyPos[1]);
|
|
|
|
float distToTarget[3];
|
|
SubtractVectors(flyPos, targetNode, distToTarget);
|
|
|
|
if (FloatAbs(distToTarget[0]) < 80.0 && FloatAbs(distToTarget[1]) < 80.0 && FloatAbs(distToTarget[2]) < 80.0)
|
|
{
|
|
if (this.current_node < t_len - 1)
|
|
{
|
|
this.current_node++;
|
|
}
|
|
else
|
|
{
|
|
EntFireByIndex(this.entity, "SetAnimation", "idle", "0.00", -1);
|
|
EntFireByIndex(this.entity, "SetAnimation", "attack", "2.00", -1);
|
|
EntFire("boss_fly_sound_end", "StopSound", "", "0.00", -1);
|
|
//EntFire("4_fly_hovno", "FireUser1", "", "0.50", -1);
|
|
//EntFire("5_fly_hovno", "FireUser1", "", "0.50", -1);
|
|
//EntFire("fly_hovno_sound4", "PlaySound", "", "0.50", -1);
|
|
//EntFire("fly_hovno_sound5", "PlaySound", "", "0.50", -1);
|
|
flyPos_copy[2] += 200;
|
|
this.TeleportGrabbedPlayers(flyPos_copy);
|
|
this.grabbed_players.Clear();
|
|
float angles[3];
|
|
GetForwardVector(this.entity, angles);
|
|
angles[2] = 0.0;
|
|
SetForwardVector(this.entity, angles);
|
|
this.end = true;
|
|
return;
|
|
}
|
|
|
|
this.previous_distance_to_target = -1.0;
|
|
}
|
|
else
|
|
{
|
|
this.MoveTowardsTarget(flyPos, targetNode);
|
|
this.previous_distance_to_target = this.current_distance_to_target;
|
|
}
|
|
|
|
if (!this.end)
|
|
CreateTimer(0.0, Tick_Cb, this, TIMER_FLAG_NO_MAPCHANGE);
|
|
}
|
|
|
|
}
|
|
|
|
//methodmap Fly_End_Hovno < Fly_End
|
|
//{
|
|
//public Fly_End_Hovno(int entity)
|
|
//{
|
|
//Fly_End myclass = new Fly_End(entity);
|
|
//myclass.type = eFlyEndHovno;
|
|
//myclass.rot_speed_acceleration = 0.16;
|
|
//myclass.rot_speed_max = 0.24;
|
|
//myclass.rot_speed_min = 0.16;
|
|
//myclass.max_speed = 120.0;
|
|
//myclass.speed_acceleration = 0.4;
|
|
//myclass.SetBool("bStop_on_last_node", true);
|
|
//myclass.SetInt("iPath", 0);
|
|
//return view_as<Fly_End_Hovno>(myclass);
|
|
//}
|
|
//property bool stop_on_last_node
|
|
//{
|
|
//public get()
|
|
//{
|
|
//return this.GetBool("bStop_on_last_node");
|
|
//}
|
|
//public set(bool val)
|
|
//{
|
|
//this.SetBool("bStop_on_last_node", val);
|
|
//}
|
|
//}
|
|
//property int path
|
|
//{
|
|
//public get()
|
|
//{
|
|
//return this.GetInt("iPath");
|
|
//}
|
|
//public set(int val)
|
|
//{
|
|
//this.SetInt("iPath", val);
|
|
//}
|
|
//}
|
|
//public void Start(int p, bool stop)
|
|
//{
|
|
//this.path = p;
|
|
//this.stop_on_last_node = stop;
|
|
//EntFireByIndex(this.entity, "SetAnimation", "fly", "0.00", -1);
|
|
//CreateTimer(0.0, Tick_Cb, this, TIMER_FLAG_NO_MAPCHANGE);
|
|
//}
|
|
//
|
|
//public void Tick()
|
|
//{
|
|
//float flyPos[3], flyPos_copy[3];
|
|
//GetOrigin(this.entity, flyPos);
|
|
//GetOrigin(this.entity, flyPos_copy);
|
|
//float targetNode[3];
|
|
//MakeVectorFromPoints( { 0.0, 0.0, 0.0 }, TARGET_NODES2[this.path][this.current_node], targetNode);
|
|
//flyPos_copy[2] -= 40;
|
|
|
|
|
|
/*** Teleport grabbed players ***/
|
|
//this.TeleportGrabbedPlayers(flyPos_copy);
|
|
|
|
/*** Move towards the next node ***/
|
|
// Fast approx of distance without needing sqrt
|
|
//this.current_distance_to_target = FloatAbs(targetNode[0] - flyPos[0]) + FloatAbs(targetNode[1] - flyPos[1]);
|
|
|
|
//float distToTarget[3];
|
|
//SubtractVectors(flyPos, targetNode, distToTarget);
|
|
|
|
//if (FloatAbs(distToTarget[0]) < 80.0 && FloatAbs(distToTarget[1]) < 80.0 && FloatAbs(distToTarget[2]) < 80.0)
|
|
//{
|
|
//this.previous_distance_to_target = -1.0;
|
|
//int len = (this.path == 0) ? t_len_0:t_len_1;
|
|
//if (this.current_node < len - 1)
|
|
//{
|
|
//this.current_node++;
|
|
//}
|
|
//else if (this.stop_on_last_node)
|
|
//{
|
|
//EntFireByIndex(this.entity, "SetAnimation", "idle", "0.00", -1);
|
|
//flyPos_copy[2] += 200.0;
|
|
//this.TeleportGrabbedPlayers(flyPos_copy);
|
|
//float angles[3];
|
|
//GetForwardVector(this.entity, angles);
|
|
//angles[2] = 0.0;
|
|
//SetForwardVector(this.entity, angles);
|
|
//this.end = true;
|
|
//return;
|
|
//}
|
|
//}
|
|
//if (!this.end)
|
|
//{
|
|
//this.MoveTowardsTarget(flyPos, targetNode);
|
|
//this.previous_distance_to_target = this.current_distance_to_target;
|
|
//CreateTimer(0.0, Tick_Cb, this, TIMER_FLAG_NO_MAPCHANGE);
|
|
//}
|
|
//}
|
|
//}
|
|
|
|
|
|
public void ChasePlayer(Fly_Small fly, const float[3] flyPos)
|
|
{
|
|
|
|
fly.retarget -= 0.01;
|
|
float targetPos[3];
|
|
GetOrigin(fly.target, targetPos);
|
|
targetPos[2] += 48;
|
|
|
|
// Fast approx of distance without needing sqrt
|
|
fly.current_distance_to_target = FloatAbs(targetPos[0] - flyPos[0]) + FloatAbs(targetPos[1] - flyPos[1]);
|
|
if(fly.retarget <= 0.0 || !IsTargetInSight(fly.entity, flyPos, targetPos))
|
|
{
|
|
fly.target = -1;
|
|
}
|
|
else
|
|
{
|
|
fly.MoveTowardsTarget(flyPos, targetPos);
|
|
fly.previous_distance_to_target = fly.current_distance_to_target;
|
|
}
|
|
|
|
}
|
|
|
|
public bool IsTargetInSight(int entity, const float[3] flyPos, const float[3] targetPos)
|
|
{
|
|
return TraceLine(flyPos, targetPos, entity) >= 1.0;
|
|
}
|
|
|
|
|
|
public int GetNewTarget(Fly_Small fly)
|
|
{
|
|
|
|
if(!IsValidPlayer(fly.target))
|
|
{
|
|
fly.target = -1;
|
|
}
|
|
|
|
int player = -1;
|
|
ArrayList playerArr = new ArrayList();
|
|
|
|
while(-1 != (player = FindEntityByClassname(player, "player")))
|
|
{
|
|
if(GetClientTeam(player) == 3)
|
|
{
|
|
float playerPos[3], selfPos[3];
|
|
GetOrigin(fly.entity, selfPos);
|
|
GetOrigin(player, playerPos);
|
|
playerPos[2] += 48;
|
|
if(IsTargetInSight(fly.entity, selfPos, playerPos))
|
|
playerArr.Push(player);
|
|
}
|
|
}
|
|
if(playerArr.Length > 0)
|
|
{
|
|
fly.retarget = 8;
|
|
int target = playerArr.Get(GetRandomInt(0, playerArr.Length - 1));
|
|
delete playerArr;
|
|
|
|
return target;
|
|
}
|
|
else
|
|
{
|
|
delete playerArr;
|
|
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
public void MoveForward(Fly_base fly, float blocker1, float blocker2)
|
|
{
|
|
if(!IsValidEntity(fly.entity))
|
|
return;
|
|
|
|
float pos1[3], pos2[3], selfPos[3], selfFwd[3];
|
|
GetOrigin(fly.entity, selfPos);
|
|
GetForwardVector(fly.entity, selfFwd);
|
|
ScaleVector(selfFwd, blocker1);
|
|
AddVectors(selfPos, selfFwd, pos1);
|
|
GetForwardVector(fly.entity, selfFwd);
|
|
ScaleVector(selfFwd, blocker2);
|
|
AddVectors(selfPos, selfFwd, pos2);
|
|
|
|
if (TraceLine(pos1, pos2, fly.entity) < 1.0)
|
|
{
|
|
|
|
fly.speed = 0.0;
|
|
}
|
|
else
|
|
{
|
|
float newpos[3];
|
|
GetForwardVector(fly.entity, selfFwd);
|
|
ScaleVector(selfFwd, fly.speed);
|
|
AddVectors(selfPos, selfFwd, newpos);
|
|
SetOrigin(fly.entity, newpos);
|
|
}
|
|
|
|
}
|
|
|
|
public void MoveDir(Fly_base fly, float[3] dir)
|
|
{
|
|
if(!IsValidEntity(fly.entity))
|
|
return;
|
|
|
|
if(fly.speed < fly.max_speed) fly.speed += fly.speed_acceleration;
|
|
float currentAngle[3], origin[3], newpos[3], dir_copy[3];
|
|
dir_copy[0] = dir[0];
|
|
dir_copy[1] = dir[1];
|
|
dir_copy[2] = dir[2];
|
|
GetForwardVector(fly.entity, currentAngle);
|
|
currentAngle[2] = 0.0;
|
|
SetForwardVector(fly.entity, currentAngle);
|
|
GetOrigin(fly.entity, origin);
|
|
ScaleVector(dir_copy, fly.speed / 4.0);
|
|
AddVectors(origin, dir_copy, newpos);
|
|
SetOrigin(fly.entity, newpos);
|
|
|
|
}
|
|
|
|
public void GetNewDir(Fly_base fly, const float[3] targetDir, const float[3] currentDir, float[3] newDir)
|
|
{
|
|
if(!IsValidEntity(fly.entity))
|
|
return;
|
|
|
|
float rotDir = currentDir[0] * targetDir[1] - currentDir[1] * targetDir[0];
|
|
if (FloatAbs(rotDir) > 0.3)
|
|
{
|
|
if (fly.speed > 0)
|
|
fly.speed -= 0.6 * fly.speed_acceleration;
|
|
if (fly.rotation_speed < fly.rot_speed_max)
|
|
fly.rotation_speed += fly.rot_speed_acceleration;
|
|
}
|
|
else
|
|
{
|
|
if (fly.speed < fly.max_speed)
|
|
fly.speed += fly.speed_acceleration;
|
|
if (fly.rotation_speed > fly.rot_speed_min)
|
|
fly.rotation_speed -= fly.rot_speed_acceleration;
|
|
}
|
|
|
|
if (rotDir > fly.rot_err || rotDir >= 0 && fly.previous_distance_to_target < fly.current_distance_to_target)
|
|
{
|
|
Rotate2D(currentDir, fly.rotation_speed, newDir);
|
|
}
|
|
else if (rotDir < -fly.rot_err || rotDir < 0 && fly.previous_distance_to_target < fly.current_distance_to_target)
|
|
{
|
|
Rotate2D(currentDir, -fly.rotation_speed, newDir);
|
|
}
|
|
else
|
|
{
|
|
newDir[0] = currentDir[0];
|
|
newDir[1] = currentDir[1];
|
|
newDir[2] = currentDir[2];
|
|
}
|
|
|
|
}
|
|
|
|
public void Rotate2D(const float[3] vector, const float angle, float[3] buffer)
|
|
{
|
|
buffer[0] = vector[0] * Cosine(angle) - vector[1] * Sine(angle);
|
|
buffer[1] = vector[0] * Sine(angle) + vector[1] * Cosine(angle);
|
|
}
|
|
|
|
public int GetRandomValue(const int max){
|
|
return GetRandomInt(0, max + 1);
|
|
}
|
|
|
|
public bool IsElementInArray(const any element, const ArrayList arr)
|
|
{
|
|
for (int i = 0; i < arr.Length; i++)
|
|
{
|
|
if (element == arr.Get(i))
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
methodmap Microwave < Basic
|
|
{
|
|
public Microwave(int entity)
|
|
{
|
|
Basic myclass = new Basic();
|
|
myclass.SetInt("iEntity", entity);
|
|
myclass.SetBool("bDead", false);
|
|
myclass.SetBool("bStarted", false);
|
|
myclass.SetInt("iHealth", 69);
|
|
return view_as<Microwave>(myclass);
|
|
}
|
|
|
|
property int entity
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetInt("iEntity");
|
|
}
|
|
public set(int val)
|
|
{
|
|
this.SetInt("iEntity", val);
|
|
}
|
|
}
|
|
|
|
property bool dead
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetBool("bDead");
|
|
}
|
|
public set(bool val)
|
|
{
|
|
this.SetBool("bDead", val);
|
|
}
|
|
}
|
|
|
|
property bool started
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetBool("bStarted");
|
|
}
|
|
public set(bool val)
|
|
{
|
|
this.SetBool("bStarted", val);
|
|
}
|
|
}
|
|
|
|
property int health
|
|
{
|
|
public get()
|
|
{
|
|
return this.GetInt("iHealth");
|
|
}
|
|
public set(int val)
|
|
{
|
|
this.SetInt("iHealth", val);
|
|
}
|
|
}
|
|
|
|
public void Start()
|
|
{
|
|
this.started = true;
|
|
}
|
|
|
|
public void AddHealth(int hp)
|
|
{
|
|
this.health += hp;
|
|
}
|
|
|
|
public void Hit(int hp)
|
|
{
|
|
if (this.started && !this.dead)
|
|
{
|
|
this.health -= hp;
|
|
if (this.health < 0)
|
|
{
|
|
this.health = 0;
|
|
}
|
|
char msg[250];
|
|
Format(msg, sizeof(msg), "message Microwave %d HP", this.health);
|
|
EntFire("fly_text", "AddOutput", msg, "0.0", -1);
|
|
EntFire("fly_text", "Display", "", "0.01", -1);
|
|
}
|
|
|
|
if (this.health <= 0 && !this.dead)
|
|
{
|
|
EntFire("microwave_dead_relay", "Trigger", "", "0.0", -1);
|
|
this.dead = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
public Action Tick_Cb(Handle timer, Fly_base fly_base)
|
|
{
|
|
KillTimer(timer);
|
|
if(fly_base)
|
|
{
|
|
switch(fly_base.type)
|
|
{
|
|
case eFlySmall:
|
|
{
|
|
Fly_Small fly = view_as<Fly_Small>(fly_base);
|
|
if(fly.doNextTick)
|
|
{
|
|
|
|
fly.Tick();
|
|
}
|
|
else
|
|
{
|
|
|
|
delete fly;
|
|
}
|
|
}
|
|
case eFly:
|
|
{
|
|
Fly fly = view_as<Fly>(fly_base);
|
|
if(fly.doNextTick)
|
|
{
|
|
|
|
fly.Tick();
|
|
}
|
|
else
|
|
{
|
|
|
|
fly.KillFly();
|
|
}
|
|
}
|
|
case eFlyEnd:
|
|
{
|
|
Fly_End fly = view_as<Fly_End>(fly_base);
|
|
if(fly.doNextTick)
|
|
{
|
|
|
|
fly.Tick();
|
|
}
|
|
else
|
|
{
|
|
|
|
fly.KillFly();
|
|
}
|
|
}
|
|
//case eFlyEndHovno:
|
|
//{
|
|
//Fly_End_Hovno fly = view_as<Fly_End_Hovno>(fly_base);
|
|
//if(fly.doNextTick)
|
|
//{
|
|
//
|
|
//fly.Tick();
|
|
//}
|
|
//else
|
|
//{
|
|
//
|
|
//delete fly;
|
|
//}
|
|
//}
|
|
}
|
|
}
|
|
return Plugin_Stop;
|
|
} |