/* ** */ #if defined _AESTHETIC_included #endinput #endif #define _AESTHETIC_included #include #include #define CELL_SIZE 128.0 methodmap Chess < Basic { public Chess(int greenStart, int greenEnd, int purpleStart, int purpleEnd) { Basic myclass = new Basic(); myclass.SetFloat("fGreenX", 2.0); myclass.SetFloat("fGreenY", 6.0); myclass.SetFloat("fPurpleX", 4.0); myclass.SetFloat("fPurpleY", 1.0); myclass.SetInt("iGreenStart", greenStart); myclass.SetInt("iGreenEnd", greenEnd); myclass.SetInt("iPurpleStart", purpleStart); myclass.SetInt("iPurpleEnd", purpleEnd); myclass.SetBool("bDead", false); return view_as(myclass); } property bool bDead { public get() { return this.GetBool("bDead"); } public set(bool val) { this.SetBool("bDead", val); } } property float greenX { public get() { return this.GetFloat("fGreenX"); } public set(float val) { this.SetFloat("fGreenX", val); } } property float greenY { public get() { return this.GetFloat("fGreenY"); } public set(float val) { this.SetFloat("fGreenY", val); } } property float purpleX { public get() { return this.GetFloat("fPurpleX"); } public set(float val) { this.SetFloat("fPurpleX", val); } } property float purpleY { public get() { return this.GetFloat("fPurpleY"); } public set(float val) { this.SetFloat("fPurpleY", val); } } property int greenStart { public get() { return this.GetInt("iGreenStart"); } } property int greenEnd { public get() { return this.GetInt("iGreenEnd"); } } property int purpleStart { public get() { return this.GetInt("iPurpleStart"); } } property int purpleEnd { public get() { return this.GetInt("iPurpleEnd"); } } public bool Check(float x, float y) { return (-1.0 < x && x < 8.0 && -1.0 < y && y < 8.0 && !((x == this.greenX && y == this.greenY) || (x == this.purpleX && y == this.purpleY))); } public void UpdateGreen(float dx, float dy) { this.greenX += dx; this.greenY += dy; } public void UpdateGreenEnd(float dx, float dy) { float currentPos[3]; GetOrigin(this.greenEnd, currentPos); float moveVector[3] = { 0.0, ... }; moveVector[0] = dx * CELL_SIZE; moveVector[1] = dy * CELL_SIZE; float tmp[3]; AddVectors(currentPos, moveVector, tmp); SetOrigin(this.greenEnd, tmp); } public void MoveGreen(float dx, float dy) { if (this.Check(this.greenX + dx, this.greenY + dy)) { this.UpdateGreen(dx, dy); this.UpdateGreenEnd(dx, dy); } } public void MoveStartToEnd(int start, int end) { float e_Orig[3]; GetOrigin(end, e_Orig); SetOrigin(start, e_Orig); } public void UpdatePurple(float dx, float dy) { this.purpleX += dx; this.purpleY += dy; } public void UpdatePurpleEnd(float dx, float dy) { float currentPos[3]; GetOrigin(this.purpleEnd, currentPos); float moveVector[3] = { 0.0, ... }; moveVector[0] = dx * CELL_SIZE; moveVector[1] = dy * CELL_SIZE; float tmp[3]; AddVectors(currentPos, moveVector, tmp); SetOrigin(this.purpleEnd, tmp); } public void MovePurple(float dx, float dy) { if (this.Check(this.purpleX + dx, this.purpleY + dy)) { this.UpdatePurple(dx, dy); this.UpdatePurpleEnd(dx, dy); } } public void CheckInLove() { if(this.bDead) return; float dx = this.greenX - this.purpleX; float dy = this.greenY - this.purpleY; if (dx < 0.0) dx *= -1.0; if (dy < 0.0) dy *= -1.0; if (dx + dy == 1.0) { this.bDead = true; EntFire("TotalTrigger", "FireUser2", "", "0.0", -1); } } } const int DEFAULT_RETARGET_TICKS = 200; const float DEFAULT_MAX_VEL = 16.0; const float DEFAULT_MAX_ACC = 0.1; const float DEFAULT_RANGE = 100000.0; const float DEFAULT_PER_FRAME_MAX_VEL_DELTA = 0.0003333; // 2.0 / (120.0 * 50.0); const float DEFAULT_PER_FRAME_MAX_ACC_DELTA = 0.0000125; // 0.075 / (120.0 * 50.0); #define PI 3.14159 public bool SphereCollideWithWorld(const float[3] orig, const float radius, float degree, float[3] buffer, int entity) { float inc = PI / degree; float phiStop = PI - inc; float minDist = 1.0; for (float phi = 0.0; phi < PI; phi += inc) { // Avoid computing the full circle on the edge cases float theta = 0.0; if (phi == 0.0 || phi == phiStop) theta = PI - inc; float cp = Cosine(phi); float sp = Sine(phi); for (; theta < 2 * PI; theta += inc) { float ct = Cosine(theta); float st = Sine(theta); float vec[3]; vec[0] = ct * sp; vec[1] = st * sp; vec[2] = cp; ScaleVector(vec, radius); float end[3]; AddVectors(orig, vec, end); float dist = TraceLine(orig, end, entity); if ( 0 < dist && dist < minDist) { ScaleVector(vec, dist); AddVectors(orig, vec, buffer); return true; } } } return false; } methodmap Eye < Basic { public Eye(int entity) { Basic myclass = new Basic(); myclass.SetInt("iEntity", entity); myclass.SetInt("iTarget", -1); myclass.SetFloat("fBossRadius", 72.0); myclass.SetInt("iBossTeamTarget", 3); myclass.SetInt("iRetargetTicks", 0); myclass.SetFloat("fMaxVel", DEFAULT_MAX_VEL); myclass.SetFloat("fMaxAcc", DEFAULT_MAX_ACC); myclass.SetVector("vVec", { 0.0, 0.0, 0.0 } ); myclass.SetVector("vAcc", { 0.0, 0.0, 0.0 } ); myclass.SetFloat("fSavedVel", 0.0); myclass.SetFloat("fSavedAcc", 0.0); return view_as(myclass); } property int entity { public get() { return this.GetInt("iEntity"); } } property int target { public get() { return this.GetInt("iTarget"); } public set(int val) { this.SetInt("iTarget", val); } } property float bossRadius { public get() { return this.GetFloat("fBossRadius"); } public set(float val) { this.SetFloat("fBossRadius", val); } } property int bossTeamTarget { public get() { return this.GetInt("iBossTeamTarget"); } public set(int val) { this.SetInt("iBossTeamTarget", val); } } property int retargetTicks { public get() { return this.GetInt("iRetargetTicks"); } public set(int val) { this.SetInt("iRetargetTicks", val); } } property float maxVel { public get() { return this.GetFloat("fMaxVel"); } public set(float val) { this.SetFloat("fMaxVel", val); } } property float maxAcc { public get() { return this.GetFloat("fMaxAcc"); } public set(float val) { this.SetFloat("fMaxAcc", val); } } property float savedVel { public get() { return this.GetFloat("fSavedVel"); } public set(float val) { this.SetFloat("fSavedVel", val); } } property float savedAcc { public get() { return this.GetFloat("fSavedAcc"); } public set(float val) { this.SetFloat("fSavedAcc", val); } } public void GetVel(float[3] vel) { this.GetVector("vVel", vel); } public void SetVel(const float[3] vel) { this.SetVector("vVel", vel); } public void GetAcc(float[3] acc) { this.GetVector("vAcc", acc); } public void SetAcc(const float[3] acc) { this.SetVector("vAcc", acc); } public void Retarget() { // Start the gig this.retargetTicks = 0; int tempPlayer = -1; int currentPlayer = -1; int checkedPlayers = 0; float distance = DEFAULT_RANGE; // While there is no target or // players found as potential targets aren't humans while (checkedPlayers < MaxClients) { currentPlayer = FindEntityByClassname(currentPlayer, "player"); // Only humans are valid if(currentPlayer != -1 && IsPlayerAlive(currentPlayer) && GetClientTeam(currentPlayer) == this.bossTeamTarget) { float tmp[3], s_orig[3], p_orig[3]; GetOrigin(this.entity, s_orig); GetOrigin(currentPlayer, p_orig); SubtractVectors(s_orig, p_orig, tmp); float length = GetVectorLength(tmp); // Make sure we're close enough if (length < distance) { tempPlayer = currentPlayer; distance = length; } } // Make sure we don't stay here forever checkedPlayers++; } // Try the last bet if no player was found this.target = tempPlayer; } public void Stop() { // Save the values this.savedVel = this.maxVel; this.savedAcc = this.maxAcc; // Block movement (with a bit of velocity to avoid spinning) this.maxVel = 0.01; this.maxAcc = 0.0001; } public void AllowMovement() { // Set either default or saved vals if (this.savedVel == 0.0) this.maxVel = DEFAULT_MAX_VEL; else this.maxVel = this.savedVel; if (this.savedAcc == 0.0) this.maxAcc = DEFAULT_MAX_ACC; else this.maxAcc = this.savedAcc; // Reset saved values this.savedVel = 0.0; this.savedAcc = 0.0; } public void FakePhysicsMovement() { // Get the center and end point float cnt[3]; GetOrigin(this.entity, cnt); // Make the boss face the target float tmp[3]; this.GetVel(tmp); SetForwardVector(this.entity, tmp); // If there is an impact, bounce float collPoint[3]; if (SphereCollideWithWorld(cnt, this.bossRadius, 5.0, collPoint, this.entity)) { float vec[3]; SubtractVectors(cnt, collPoint, vec); float norm[3], norm_copy[3]; NormalizeVector(vec, norm); norm_copy[0] = norm[0]; norm_copy[1] = norm[1]; norm_copy[2] = norm[2]; // Reflect velocity in a hacky way (not plane-accurate) float nn[3]; NormalizeVector(norm, nn); this.GetVel(tmp); float dot = GetVectorDotProduct(tmp, nn); ScaleVector(norm_copy, 2 * dot); SubtractVectors(tmp, norm_copy, tmp); this.SetVel(tmp); EntFireByIndex(this.entity, "FireUser1", "", "0.0", this.target); // Move as far as we can ScaleVector(norm, this.bossRadius); AddVectors(cnt, norm, tmp); SetOrigin(this.entity, tmp); } else { this.GetVel(tmp); AddVectors(cnt, tmp, tmp); SetOrigin(this.entity, tmp); } } public void Move() { // If there is no target or the target is gone/dead, retarget if (this.target == -1 || !IsValidEntity(this.target) || !IsPlayerAlive(this.target) || this.retargetTicks++ >= DEFAULT_RETARGET_TICKS) this.Retarget(); // Perform the update with the data from the previous moment float vel[3], tmp[3], acc[3]; this.GetVel(vel); this.GetAcc(acc); AddVectors(vel, acc, tmp); this.SetVel(tmp); float length = GetVectorLength(tmp); if (length > this.maxVel) { ScaleVector(tmp, this.maxVel / length); this.SetVel(tmp); } this.SetAcc( { 0.0, 0.0, 0.0 } ); // Apply the higher accuracy movement deltas this.maxVel += DEFAULT_PER_FRAME_MAX_VEL_DELTA; this.maxAcc += DEFAULT_PER_FRAME_MAX_ACC_DELTA; // Try to move, finally this.FakePhysicsMovement(); // Keep going if no target's there still if (this.target == -1) return; // Try moving towards our target if it exists, otherwise don't float tgtPos[3]; GetOrigin(this.target, tgtPos); float bssPos[3]; GetOrigin(this.entity, bssPos); float dir[3]; SubtractVectors(tgtPos, bssPos, dir); // Compute the length for later and normalize it if needed length = GetVectorLength(dir); if (length > this.maxVel) ScaleVector(dir, this.maxVel / length); // Compute the acceleration this.GetVel(vel); SubtractVectors(dir, vel, acc); length = GetVectorLength(acc); if (length > this.maxAcc) { ScaleVector(acc, this.maxAcc / length); this.SetAcc(acc); } } }