Files
SMScripts/scripting/temp/beskeleton.sp

551 lines
16 KiB
SourcePawn
Raw Permalink Normal View History

2025-04-15 22:27:20 -04:00
#include <sdkhooks>
#include <tf2_stocks>
#include <tf2items>
#pragma newdecls required;
#define MODEL_SKELETON "models/bots/skeleton_sniper_boss/skeleton_sniper_boss.mdl"
#define PLUGIN_VERSION "1.2"
bool g_bSpecial[MAXPLAYERS + 1];
bool g_bSkeleton[MAXPLAYERS + 1];
TFTeam g_iOldTeam[MAXPLAYERS + 1];
Handle g_hCvarStompDamage;
public Plugin myinfo =
{
name = "[TF2] Be The Skeleton King!",
author = "Pelipoika",
description = "Spooky scary skeleton",
version = PLUGIN_VERSION,
url = ""
}
public void OnPluginStart()
{
AddTempEntHook("TFBlood", TempHook);
RegAdminCmd("sm_beskeleton", Command_Skeleton, ADMFLAG_ROOT);
HookEvent("post_inventory_application", Event_SkeletonDeath);
HookEvent("player_death", Event_SkeletonDeath, EventHookMode_Pre);
CreateConVar("tf2_beskeleton_version", PLUGIN_VERSION, "Be the Skeleton King version", FCVAR_NOTIFY|FCVAR_DONTRECORD|FCVAR_SPONLY);
g_hCvarStompDamage = CreateConVar("tf2_beskeleton_stompdamage", "120", "Movement speed penalty when carrying a bomb", FCVAR_NOTIFY|FCVAR_DONTRECORD, true, 0.0, true, 1.0);
for (int client = 1; client <= MaxClients; client++)
{
if(client > 0 && client <= MaxClients && IsClientInGame(client))
{
g_bSkeleton[client] = false;
g_bSpecial[client] = false;
g_iOldTeam[client] = TF2_GetClientTeam(client);
SDKHook(client, SDKHook_OnTakeDamageAlive, TakeDamage);
}
}
AddNormalSoundHook(SkeletonSH);
}
public APLRes AskPluginLoad2(Handle myself, bool late, char[] error, int err_max)
{
CreateNative("BeSkeletonKing_MakeSkeleton", Native_SetSkeleton);
CreateNative("BeSkeletonKing_IsSkeleton", Native_IsSkeleton);
RegPluginLibrary("beskeleton");
return APLRes_Success;
}
public Action TempHook(const char[] te_name, const Players[], int numClients, float delay)
{
int client = TE_ReadNum("entindex");
if (client > 0 && client <= MaxClients && IsClientInGame(client) && g_bSkeleton[client])
{
float m_vecOrigin[3];
m_vecOrigin[0] = TE_ReadFloat("m_vecOrigin[0]");
m_vecOrigin[1] = TE_ReadFloat("m_vecOrigin[1]");
m_vecOrigin[2] = TE_ReadFloat("m_vecOrigin[2]");
if(GetEntProp(client, Prop_Send, "m_iTeamNum") == 0)
{
CreateParticle("spell_skeleton_goop_green", m_vecOrigin);
}
else
{
switch(TF2_GetClientTeam(client))
{
case TFTeam_Red: CreateParticle("spell_pumpkin_mirv_goop_red", m_vecOrigin);
case TFTeam_Blue: CreateParticle("spell_pumpkin_mirv_goop_blue", m_vecOrigin);
}
}
return Plugin_Stop;
}
return Plugin_Continue;
}
public void OnMapStart()
{
PrecacheModel(MODEL_SKELETON);
PrecacheSound("misc/halloween/skeleton_break.wav");
}
public void OnClientPutInServer(int client)
{
g_bSkeleton[client] = false;
g_bSpecial[client] = false;
g_iOldTeam[client] = TFTeam_Spectator;
SDKHook(client, SDKHook_OnTakeDamageAlive, TakeDamage);
}
public Action Command_Skeleton(int client, int args)
{
char arg1[32], arg2[6];
GetCmdArg(1, arg1, sizeof(arg1));
GetCmdArg(2, arg2, sizeof(arg2));
char target_name[MAX_TARGET_LENGTH];
int target_list[MAXPLAYERS];
int target_count;
bool tn_is_ml;
if ((target_count = ProcessTargetString(
arg1,
client,
target_list,
MAXPLAYERS,
0,
target_name,
sizeof(target_name),
tn_is_ml)) <= 0)
{
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
for (int i = 0; i < target_count; i++)
{
int player = target_list[i];
if(player > 0 && player <= MaxClients && IsClientInGame(player) && IsPlayerAlive(player))
{
if(StringToInt(arg2) == 1)
MakeSkeleton(player, true);
else
MakeSkeleton(player);
}
}
return Plugin_Handled;
}
public Action GetMaxHealth(int client, int &MaxHealth)
{
if (client > 0 && client <= MaxClients && IsClientInGame(client))
{
MaxHealth = 1000;
return Plugin_Changed;
}
return Plugin_Continue;
}
public Action SetModel(int client, const char[] model)
{
SetVariantString(model);
AcceptEntityInput(client, "SetCustomModel");
SetEntProp(client, Prop_Send, "m_bUseClassAnimations", 1);
}
stock void MakeSkeleton(int client, bool spectator = false)
{
if(spectator)
{
g_iOldTeam[client] = TF2_GetClientTeam(client);
SetEntProp(client, Prop_Send, "m_bForcedSkin", 1);
SetEntProp(client, Prop_Send, "m_nForcedSkin", 2);
SetEntProp(client, Prop_Send, "m_iTeamNum", 0);
}
SetVariantString("2.0");
AcceptEntityInput(client, "SetModelScale");
SetModel(client, MODEL_SKELETON);
TF2_SetPlayerClass(client, TFClass_Sniper, _, false);
TF2_RemoveAllWearables(client);
TF2_RemoveAllWeapons(client);
Handle hWeaponFists = TF2Items_CreateItem(OVERRIDE_ALL);
TF2Items_SetClassname(hWeaponFists, "tf_weapon_club");
TF2Items_SetItemIndex(hWeaponFists, 3);
TF2Items_SetQuality(hWeaponFists, 6);
TF2Items_SetAttribute(hWeaponFists, 0, 15, 0.0);
TF2Items_SetAttribute(hWeaponFists, 1, 5, 1.65);
TF2Items_SetAttribute(hWeaponFists, 2, 402, 1.0);
TF2Items_SetNumAttributes(hWeaponFists, 3);
int iEntity = TF2Items_GiveNamedItem(client, hWeaponFists);
EquipPlayerWeapon(client, iEntity);
CloseHandle(hWeaponFists);
SetEntityRenderMode(iEntity, RENDER_TRANSCOLOR);
SetEntityRenderColor(iEntity, 255, 255, 255, 0);
SetEntProp(iEntity, Prop_Send, "m_fEffects", 16);
char anim[16];
Format(anim, 32, "spawn0%i", GetRandomInt(1, 7));
PlayAnimation(client, anim);
g_bSpecial[client] = true;
SetNextAttack(iEntity, 2.0);
SDKHook(client, SDKHook_GetMaxHealth, GetMaxHealth);
SetEntProp(client, Prop_Send, "m_iHealth", 1000);
g_bSkeleton[client] = true;
}
stock void PlayAnimation(int client, char[] anim)
{
TeleportEntity(client, NULL_VECTOR, NULL_VECTOR, view_as<float>({0.0, 0.0, 0.0}));
SetEntityRenderMode(client, RENDER_TRANSCOLOR);
SetEntityRenderColor(client, 255, 255, 255, 0);
SetEntProp(client, Prop_Send, "m_bUseClassAnimations", 0);
SetEntityMoveType(client, MOVETYPE_NONE);
float vecOrigin[3], vecAngles[3];
GetClientAbsOrigin(client, vecOrigin);
GetClientAbsAngles(client, vecAngles);
vecAngles[0] = 0.0;
int animationentity = CreateEntityByName("prop_dynamic_override");
if(IsValidEntity(animationentity))
{
DispatchKeyValueVector(animationentity, "origin", vecOrigin);
DispatchKeyValueVector(animationentity, "angles", vecAngles);
DispatchKeyValue(animationentity, "model", MODEL_SKELETON);
DispatchKeyValue(animationentity, "defaultanim", anim);
DispatchSpawn(animationentity);
SetEntPropEnt(animationentity, Prop_Send, "m_hOwnerEntity", client);
if(GetEntProp(client, Prop_Send, "m_iTeamNum") == 0)
SetEntProp(animationentity, Prop_Send, "m_nSkin", GetEntProp(client, Prop_Send, "m_nForcedSkin"));
else
SetEntProp(animationentity, Prop_Send, "m_nSkin", GetClientTeam(client) - 2);
SetEntPropFloat(animationentity, Prop_Send, "m_flModelScale", 2.0);
SetVariantString("OnAnimationDone !self:KillHierarchy::0.0:1");
AcceptEntityInput(animationentity, "AddOutput");
HookSingleEntityOutput(animationentity, "OnAnimationDone", OnAnimationDone, true);
}
}
public void OnAnimationDone(const char[] output, int caller, int activator, float delay)
{
if(IsValidEntity(caller))
{
int client = GetEntPropEnt(caller, Prop_Send, "m_hOwnerEntity");
if(client > 0 && client <= MaxClients && IsClientInGame(client) && IsPlayerAlive(client))
{
SetEntityMoveType(client, MOVETYPE_WALK);
SetEntProp(client, Prop_Send, "m_bUseClassAnimations", 1);
SetEntityRenderMode(client, RENDER_TRANSCOLOR);
SetEntityRenderColor(client, 255, 255, 255, 255);
g_bSpecial[client] = false;
}
}
}
public Action OnPlayerRunCmd(int client, int &iButtons, int &iImpulse, float fVel[3], float fAng[3], int &iWeapon)
{
if (IsPlayerAlive(client))
{
if(iButtons & IN_ATTACK2 && !g_bSpecial[client] && g_bSkeleton[client] && GetEntPropEnt(client, Prop_Send, "m_hGroundEntity") != -1)
{
SetNextAttack(GetPlayerWeaponSlot(client, TFWeaponSlot_Melee), 2.0);
PlayAnimation(client, "MELEE_swing3");
g_bSpecial[client] = true;
float vecAngles[3], vecOrigin[3];
GetClientAbsAngles(client, vecAngles);
GetClientAbsOrigin(client, vecOrigin);
vecAngles[0] = 0.0;
Handle pack;
CreateDataTimer(0.75, Timer_PerformStomp, pack, TIMER_FLAG_NO_MAPCHANGE);
WritePackCell(pack, client);
WritePackFloat(pack, vecOrigin[0]);
WritePackFloat(pack, vecOrigin[1]);
WritePackFloat(pack, vecOrigin[2]);
WritePackFloat(pack, vecAngles[0]);
WritePackFloat(pack, vecAngles[1]);
WritePackFloat(pack, vecAngles[2]);
}
}
return Plugin_Continue;
}
public Action Timer_PerformStomp(Handle timer, Handle pack)
{
ResetPack(pack);
int client = ReadPackCell(pack);
float vecAngles[3], vecOrigin[3];
vecOrigin[0] = ReadPackFloat(pack);
vecOrigin[1] = ReadPackFloat(pack);
vecOrigin[2] = ReadPackFloat(pack);
vecAngles[0] = ReadPackFloat(pack);
vecAngles[1] = ReadPackFloat(pack);
vecAngles[2] = ReadPackFloat(pack);
float vForward[3], vLeft[3];
GetAngleVectors(vecAngles, vForward, NULL_VECTOR, NULL_VECTOR);
GetAngleVectors(vecAngles, NULL_VECTOR, vLeft, NULL_VECTOR);
vecOrigin[0] += (vForward[0] * 55);
vecOrigin[1] += (vForward[1] * 55);
vecOrigin[2] += (vForward[2] * 55);
vecOrigin[0] += (vLeft[0] * -35);
vecOrigin[1] += (vLeft[1] * -35);
vecOrigin[2] += (vLeft[2] * -35);
CreateParticle("bomibomicon_ring", vecOrigin); //The effect actually comes out of his leg VALVE
float pos2[3], Vec[3], AngBuff[3];
for(int i = 1; i <= MaxClients; i++)
{
if(IsClientInGame(i) && IsPlayerAlive(i) && i != client && GetClientTeam(i) != GetClientTeam(client))
{
GetClientAbsOrigin(i, pos2);
if(GetVectorDistance(vecOrigin, pos2) <= 200.0)
{
MakeVectorFromPoints(vecOrigin, pos2, Vec);
GetVectorAngles(Vec, AngBuff);
AngBuff[0] -= 30.0;
GetAngleVectors(AngBuff, Vec, NULL_VECTOR, NULL_VECTOR);
NormalizeVector(Vec, Vec);
ScaleVector(Vec, 500.0);
Vec[2] += 250.0;
SDKHooks_TakeDamage(i, client, client, GetConVarFloat(g_hCvarStompDamage));
TeleportEntity(i, NULL_VECTOR, NULL_VECTOR, Vec);
}
}
}
}
public Action TakeDamage(int victim, int &attacker, int &inflictor, float &damage, int &damagetype)
{
if(victim > 0 && victim <= MaxClients && IsClientInGame(victim)
&& attacker > 0 && attacker <= MaxClients && IsClientInGame(attacker)
&& attacker != victim)
{
if(g_bSkeleton[attacker])
{
damage = GetRandomFloat(95.0, 120.0);
return Plugin_Changed;
}
}
return Plugin_Continue;
}
public Action Event_SkeletonDeath(Handle hEvent, char[] name, bool dontBroadcast)
{
int client = GetClientOfUserId(GetEventInt(hEvent, "userid"));
int attacker = GetEventInt(hEvent, "inflictor_entindex");
if(g_bSkeleton[client])
{
EmitSoundToAll("misc/halloween/skeleton_break.wav", client);
g_bSkeleton[client] = false;
g_bSpecial[client] = false;
SDKUnhook(client, SDKHook_GetMaxHealth, GetMaxHealth);
SetEntityMoveType(client, MOVETYPE_WALK);
SetEntProp(client, Prop_Send, "m_bUseClassAnimations", 1);
SetEntProp(client, Prop_Send, "m_bForcedSkin", 0);
if(GetEntProp(client, Prop_Send, "m_iTeamNum") == 0)
{
SetEntProp(client, Prop_Send, "m_iTeamNum", g_iOldTeam[client]);
g_iOldTeam[client] = TFTeam_Spectator;
}
SetEntityRenderMode(client, RENDER_TRANSCOLOR);
SetEntityRenderColor(client, 255, 255, 255, 255);
SetVariantString("");
AcceptEntityInput(client, "SetCustomModel");
SetVariantString("1.0");
AcceptEntityInput(client, "SetModelScale");
float vecOrigin[3];
GetClientAbsOrigin(client, vecOrigin);
//Drop a Rare spellbook
int spell = CreateEntityByName("tf_spell_pickup");
if(IsValidEntity(spell))
{
DispatchKeyValueVector(spell, "origin", vecOrigin);
DispatchKeyValueVector(spell, "basevelocity", view_as<float>({0.0, 0.0, 0.0}));
DispatchKeyValueVector(spell, "velocity", view_as<float>({0.0, 0.0, 0.0}));
DispatchKeyValue(spell, "powerup_model", "models/props_halloween/hwn_spellbook_upright_major.mdl");
DispatchKeyValue(spell, "OnPlayerTouch", "!self,Kill,,0,-1");
DispatchSpawn(spell);
SetVariantString("OnUser1 !self:kill::60:1");
AcceptEntityInput(spell, "AddOutput");
AcceptEntityInput(spell, "FireUser1");
SetEntPropEnt(spell, Prop_Send, "m_hOwnerEntity", client);
SetEntProp(spell, Prop_Data, "m_nTier", 1);
}
}
if(attacker > 0 && attacker <= MaxClients && IsClientInGame(attacker) && g_bSkeleton[attacker])
{
SetEventInt(hEvent, "attacker", 0);
SetEventString(hEvent, "weapon", "spellbook_skeleton");
SetEventInt(hEvent, "customkill", 66);
SetEventString(hEvent, "weapon_logclassname", "spellbook_skeleton");
}
return Plugin_Continue;
}
public Action SkeletonSH(clients[64], int &numClients, char sample[PLATFORM_MAX_PATH], int &entity, int &channel, float &volume, int &level, int &pitch, int &flags, char soundEntry[PLATFORM_MAX_PATH], int &seed)
{
if (entity > 0 && entity <= MaxClients && IsClientInGame(entity))
{
if (!g_bSkeleton[entity]) return Plugin_Continue;
if (StrContains(sample, "vo/sniper", false) != -1)
{
Format(sample, sizeof(sample), "misc/halloween/skeletons/skelly_giant_0%i.wav", GetRandomInt(1, 3));
PrecacheSound(sample);
EmitSoundToAll(sample, entity, channel, level, flags, volume);
return Plugin_Changed;
}
}
return Plugin_Continue;
}
stock void TF2_RemoveAllWearables(int client)
{
int wearable = -1;
while ((wearable = FindEntityByClassname(wearable, "tf_wearable*")) != -1)
{
if (IsValidEntity(wearable))
{
int player = GetEntPropEnt(wearable, Prop_Send, "m_hOwnerEntity");
if (client == player)
{
TF2_RemoveWearable(client, wearable);
}
}
}
while ((wearable = FindEntityByClassname(wearable, "vgui_screen")) != -1)
{
if (IsValidEntity(wearable))
{
int player = GetEntPropEnt(wearable, Prop_Data, "m_hOwnerEntity");
if (client == player)
{
AcceptEntityInput(wearable, "Kill");
}
}
}
while ((wearable = FindEntityByClassname(wearable, "tf_powerup_bottle")) != -1)
{
if (IsValidEntity(wearable))
{
int player = GetEntPropEnt(wearable, Prop_Send, "m_hOwnerEntity");
if (client == player)
{
TF2_RemoveWearable(client, wearable);
}
}
}
while ((wearable = FindEntityByClassname(wearable, "tf_weapon_spellbook")) != -1)
{
if (IsValidEntity(wearable))
{
int player = GetEntPropEnt(wearable, Prop_Send, "m_hOwnerEntity");
if (client == player)
{
TF2_RemoveWearable(client, wearable);
}
}
}
}
stock void SetNextAttack(int weapon, float duration = 0.0)
{
if (!IsValidEntity(weapon)) return;
float next = GetGameTime() + duration;
SetEntPropFloat(weapon, Prop_Send, "m_flNextPrimaryAttack", next);
SetEntPropFloat(weapon, Prop_Send, "m_flNextSecondaryAttack", next);
}
stock void CreateParticle(char[] particle, float pos[3])
{
int tblidx = FindStringTable("ParticleEffectNames");
char tmp[256];
int count = GetStringTableNumStrings(tblidx);
int stridx = INVALID_STRING_INDEX;
for(int i = 0; i < count; i++)
{
ReadStringTable(tblidx, i, tmp, sizeof(tmp));
if(StrEqual(tmp, particle, false))
{
stridx = i;
break;
}
}
for(int i = 1; i <= GetMaxClients(); i++)
{
if(!IsValidEntity(i)) continue;
if(!IsClientInGame(i)) continue;
TE_Start("TFParticleEffect");
TE_WriteFloat("m_vecOrigin[0]", pos[0]);
TE_WriteFloat("m_vecOrigin[1]", pos[1]);
TE_WriteFloat("m_vecOrigin[2]", pos[2]);
TE_WriteNum("m_iParticleSystemIndex", stridx);
TE_WriteNum("entindex", -1);
TE_WriteNum("m_iAttachType", 5); //Dont associate with any entity
TE_SendToClient(i, 0.0);
}
}
public int Native_SetSkeleton(Handle plugin, int args)
{
MakeSkeleton(GetNativeCell(1));
}
public int Native_IsSkeleton(Handle plugin, int args)
{
return g_bSkeleton[GetNativeCell(1)];
}