PHP Code:
#include <sourcemod>
#include <sdktools>
#include <sdkhooks>
#include <tf2>
#include <tf2_stocks>
#include <pets>
#include <smlib>
#pragma semicolon 1
stock AttachParticle(ent, String:particleType[], String:attachBone[], Float:addPos[3]=NULL_VECTOR, Float:addAngle[3]=NULL_VECTOR)
{
new particle = CreateEntityByName("info_particle_system");
if (IsValidEdict(particle))
{
new String:tName[32];
GetEntPropString(ent, Prop_Data, "m_iName", tName, sizeof(tName));
DispatchKeyValue(particle, "targetname", "tf2particle");
DispatchKeyValue(particle, "parentname", tName);
DispatchKeyValue(particle, "effect_name", particleType);
DispatchSpawn(particle);
SetVariantString("!activator");
AcceptEntityInput(particle, "SetParent", ent, ent, 0);
SetVariantString(attachBone);
AcceptEntityInput(particle, "SetParentAttachment", particle, particle, 0);
ActivateEntity(particle);
TeleportEntity(particle, addPos, addAngle, NULL_VECTOR);
AcceptEntityInput(particle, "start");
}
return particle;
}
stock AttachModel(ent, String:Modelname[], String:attachBone[], Float:addPos[3]=NULL_VECTOR, Float:addAngle[3]=NULL_VECTOR)
{
new model = CreateEntityByName("prop_dynamic_override");
if (IsValidEdict(model))
{
new String:tName[32];
GetEntPropString(ent, Prop_Data, "m_iName", tName, sizeof(tName));
DispatchKeyValue(model, "targetname", "tf2modelattach");
DispatchKeyValue(model, "model", Modelname);
DispatchKeyValue(model, "parentname", tName);
SetVariantString("!activator");
AcceptEntityInput(model, "SetParent", ent, ent, 0);
SetVariantString(attachBone);
AcceptEntityInput(model, "SetParentAttachment", model, model, 0);
DispatchSpawn(model);
SetEntityModel(model, Modelname);
TeleportEntity(model, addPos, addAngle, NULL_VECTOR);
}
return model;
}
stock SafeKillTimer(&Handle:timer)
{
if(timer != INVALID_HANDLE)
{
KillTimer(timer);
timer = INVALID_HANDLE;
}
}
stock CreateParticle(String:particle[], Float:pos[3])
{
new tblidx = FindStringTable("ParticleEffectNames");
new String:tmp[256];
new count = GetStringTableNumStrings(tblidx);
new stridx = INVALID_STRING_INDEX;
for(new i=0; i<count; i++)
{
ReadStringTable(tblidx, i, tmp, sizeof(tmp));
if(StrEqual(tmp, particle, false))
{
stridx = i;
break;
}
}
for(new 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_SendToClient(i, 0.0);
}
}
new pet[MAXPLAYERS+1];
new petType[MAXPLAYERS+1];
new petState[MAXPLAYERS+1];
new Handle:soundTimer[MAXPLAYERS+1] = INVALID_HANDLE;
new Float:g_pos[3];
new bool:inColldown[MAXPLAYERS+1];
public OnPluginStart()
{
RegConsoleCmd("givepet", Command_SpawnPet);
RegConsoleCmd("killpet", Command_KillPet);
HookEvent("player_death", Event_Death, EventHookMode_Post);
HookEvent("player_spawn", Event_Spawn, EventHookMode_Post);
}
public OnMapStart()
{
for(new i=1; i<sizeof(petInfo); i++)
{
PrecacheModel(petInfo[i][iModel]);
PrecacheModel(petInfo[i][iHat]);
PrecacheModel(petInfo[i][iWep]);
PrecacheSound(petInfo[i][iSoundGeneric]);
PrecacheSound(petInfo[i][iSoundJump]);
PrecacheSound(petInfo[i][iSoundTaunt]);
PrecacheSound(petInfo[i][iSoundSpawn]);
PrecacheSound(petInfo[i][iSoundDuck]);
PrecacheSound(petInfo[i][iSoundAttack]);
PrecacheSound(petInfo[i][iSoundStun]);
PrecacheSound(petInfo[i][iSoundFoot0]);
PrecacheSound(petInfo[i][iSoundFoot1]);
PrecacheSound(petInfo[i][iSoundFoot2]);
}
}
public Action:Event_Spawn(Handle:event, const String:name[], bool:dontBroadcast)
{
new client = GetClientOfUserId(GetEventInt(event, "userid"));
if(petType[client] != 0)
{
SpawnPet(client);
}
}
public Action:Event_Death(Handle:event, const String:name[], bool:dontBroadcast)
{
new victim = GetClientOfUserId(GetEventInt(event, "userid"));
KillPet(victim);
}
public OnPluginEnd()
{
for (new i = 1; i <=MaxClients; i++)
{
KillPet(i);
}
}
public Action:Command_KillPet(client, args)
{
new String:target[PLATFORM_MAX_PATH];
GetCmdArg(1, target, PLATFORM_MAX_PATH);
decl String:target_name[MAX_TARGET_LENGTH];
decl target_list[MAXPLAYERS], target_count;
new bool:tn_is_ml;
if ((target_count = ProcessTargetString(
target,
client,
target_list,
MAXPLAYERS,
COMMAND_FILTER_ALIVE,
target_name,
sizeof(target_name),
tn_is_ml)) <= 0)
{
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
for (new i = 0; i < target_count; i++)
{
KillPet(target_list[i]);
}
return Plugin_Handled;
}
public Action:Command_SpawnPet(client, args)
{
new String:target[PLATFORM_MAX_PATH];
new String:petindex[PLATFORM_MAX_PATH];
GetCmdArg(1, target, PLATFORM_MAX_PATH);
GetCmdArg(2, petindex, PLATFORM_MAX_PATH);
decl String:target_name[MAX_TARGET_LENGTH];
decl target_list[MAXPLAYERS], target_count;
new bool:tn_is_ml;
if ((target_count = ProcessTargetString(
target,
client,
target_list,
MAXPLAYERS,
COMMAND_FILTER_ALIVE,
target_name,
sizeof(target_name),
tn_is_ml)) <= 0)
{
ReplyToTargetError(client, target_count);
return Plugin_Handled;
}
for (new i = 0; i < target_count; i++)
{
new strint = StringToInt(petindex, 10);
if(strint == 0)
{
ReplyToCommand(client, "[SM] Invalid Pet Index");
}
else
{
KillPet(target_list[i]);
petType[target_list[i]] = strint;
SpawnPet(target_list[i]);
}
}
return Plugin_Handled;
}
public SpawnPet(client)
{
decl Float:pos[3];
GetClientAbsOrigin(client, pos);
OffsetLocation(pos);
if(!(pet[client] = CreateEntityByName("prop_dynamic_override")))
{
return;
}
SetEntPropEnt(pet[client], Prop_Send, "m_hOwnerEntity", client);
new String:clientname[PLATFORM_MAX_PATH];
GetClientName(client, clientname, PLATFORM_MAX_PATH);
new String:PetName[PLATFORM_MAX_PATH];
Format(PetName, PLATFORM_MAX_PATH, "%s Pet", clientname);
DispatchKeyValue(pet[client], "targetname", PetName);
DispatchKeyValue(pet[client], "model", petInfo[petType[client]][iModel]);
DispatchKeyValue(pet[client], "DefaultAnim", petInfo[petType[client]][iAnimIdle]);
SetVariantString(petInfo[petType[client]][iAnimIdle]);
AcceptEntityInput(pet[client], "SetDefaultAnimation");
SetVariantInt(petInfo[petType[client]][iSkin]);
AcceptEntityInput(pet[client], "skin");
SetVariantInt(petInfo[petType[client]][iBodyGroup]);
AcceptEntityInput(pet[client], "SetBodyGroup");
SetVariantInt(2);
AcceptEntityInput(pet[client], "solid");
DispatchKeyValueFloat(pet[client], "modelscale", petInfo[petType[client]][iModelSize]);
AttachModel(pet[client], petInfo[petType[client]][iHat], petInfo[petType[client]][iHatBone]);
AttachModel(pet[client], petInfo[petType[client]][iWep], petInfo[petType[client]][iWepBone]);
AttachParticle(pet[client], petInfo[petType[client]][iParticle], petInfo[petType[client]][iParBone]);
DispatchSpawn(pet[client]);
TeleportEntity(pet[client], pos, NULL_VECTOR, NULL_VECTOR);
SetPetState(client, STATE_SPAWNING);
CreateParticle(petInfo[petType[client]][iSpawnParticle], pos);
EmitAmbientSound(petInfo[petType[client]][iSoundGeneric], pos, pet[client]);
EmitAmbientSound(petInfo[petType[client]][iSoundSpawn], pos);
SafeKillTimer(soundTimer[client]);
soundTimer[client] = CreateTimer(10.0, Timer_GenericSound, client);
SDKHook(client, SDKHook_PreThink, PetThink);
}
public PetThink(client)
{
if(!IsValidEntity(pet[client]))
{
SDKUnhook(client, SDKHook_PreThink, PetThink);
return;
}
decl Float:pos[3], Float:ang[3], Float:clientPos[3], Float:clientAng[3];
GetEntPropVector(pet[client], Prop_Data, "m_vecOrigin", pos);
GetEntPropVector(pet[client], Prop_Data, "m_angRotation", ang);
GetClientAbsOrigin(client, clientPos);
GetClientAbsAngles(client, clientAng);
new Float:dist = GetVectorDistance(clientPos, pos);
new Float:distX = clientPos[0] - pos[0];
new Float:distY = clientPos[1] - pos[1];
new Float:speed = (dist - 64.0) / 54;
Math_Clamp(speed, -4.0, 4.0);
if(FloatAbs(speed) < 0.3)
speed *= 0.1;
if(dist > 1024.0)
{
decl Float:posTmp[3];
GetClientAbsOrigin(client, posTmp);
OffsetLocation(posTmp);
TeleportEntity(pet[client], posTmp, NULL_VECTOR, NULL_VECTOR);
GetEntPropVector(pet[client], Prop_Data, "m_vecOrigin", pos);
}
if(pos[0] < clientPos[0]) pos[0] += speed;
if(pos[0] > clientPos[0]) pos[0] -= speed;
if(pos[1] < clientPos[1]) pos[1] += speed;
if(pos[1] > clientPos[1]) pos[1] -= speed;
switch(petInfo[petType[client]][iHeight])
{
case HEIGHT_GROUND: pos[2] = clientPos[2];
case HEIGHT_HOVER: pos[2] = clientPos[2] + 32.0;
case HEIGHT_FLY: pos[2] = clientPos[2] + 96.0;
}
if(!(GetEntityFlags(client) & FL_ONGROUND))
SetPetState(client, STATE_JUMPING);
else if(FloatAbs(speed) > 0.2)
SetPetState(client, STATE_WALKING);
else if(TF2_IsPlayerInCondition(client, TFCond_Taunting))
SetPetState(client, STATE_TAUNTING);
else if(GetClientButtons(client) & IN_DUCK)
SetPetState(client, STATE_DUCKING);
else if(GetClientButtons(client) & IN_ATTACK)
SetPetState(client, STATE_ATTACKING);
else if(TF2_IsPlayerInCondition(client, TFCond_Dazed))
SetPetState(client, STATE_STUN);
else
SetPetState(client, STATE_IDLE);
ang[1] = (ArcTangent2(distY, distX) * 180) / 3.14;
TeleportEntity(pet[client], pos, ang, NULL_VECTOR);
if(petState[client] == STATE_ATTACKING)
{
TeleportEntity(pet[client], NULL_VECTOR, clientAng, NULL_VECTOR);
}
if(petState[client] == STATE_ATTACKING && inColldown[client] == false)
{
CreateProjectile(client);
inColldown[client] = true;
CreateTimer(3.0, PetColldown, client);
}
if(petState[client] == STATE_WALKING && inColldown[client] == false)
{
new footstep = GetRandomInt(0, 2);
switch(footstep)
{
case 0: EmitAmbientSound(petInfo[petType[client]][iSoundFoot0], pos, pet[client], _, _, _, petInfo[petType[client]][iPitch]);
case 1: EmitAmbientSound(petInfo[petType[client]][iSoundFoot1], pos, pet[client], _, _, _, petInfo[petType[client]][iPitch]);
case 2: EmitAmbientSound(petInfo[petType[client]][iSoundFoot2], pos, pet[client], _, _, _, petInfo[petType[client]][iPitch]);
}
inColldown[client] = true;
CreateTimer(0.5, PetColldown, client);
}
}
public Action:PetColldown(Handle:timer, any:client)
{
inColldown[client] = false;
}
public CreateProjectile(client)
{
if(!SetTeleportEndPoint(client))
{
PrintToChat(client, "[SM] Could not find spawn point.");
}
new Float:vAngles[3];
new Float:vPosition[3];
new Float:ang[3];
GetClientEyeAngles(client, ang);
GetEntPropVector(pet[client], Prop_Data, "m_angRotation", vAngles);
GetEntPropVector(pet[client], Prop_Data, "m_vecOrigin", vPosition);
new iTeam = GetClientTeam(client);
new iProject = CreateEntityByName(petInfo[petType[client]][iProjectile]);
decl Float:vVelocity[3];
decl Float:vBuffer[3];
GetAngleVectors(vAngles, vBuffer, NULL_VECTOR, NULL_VECTOR);
vVelocity[0] = vBuffer[0]*1100.0;
vVelocity[1] = vBuffer[1]*1100.0;
vVelocity[2] = vBuffer[2]*1100.0;
SetEntPropEnt(iProject, Prop_Send, "m_hOwnerEntity", client);
SetEntProp(iProject, Prop_Send, "m_bCritical", 100);
SetEntProp(iProject, Prop_Send, "m_iTeamNum", iTeam, 1);
SetEntProp(iProject, Prop_Send, "m_nSkin", (iTeam-2));
vPosition[2] += 50.0;
TeleportEntity(iProject, vPosition, vAngles, NULL_VECTOR);
SetVariantInt(iTeam);
AcceptEntityInput(iProject, "TeamNum", -1, -1, 0);
SetVariantInt(iTeam);
AcceptEntityInput(iProject, "SetTeam", -1, -1, 0);
DispatchSpawn(iProject);
TeleportEntity(iProject, NULL_VECTOR, ang, vVelocity);
}
public SetTeleportEndPoint(client)
{
decl Float:vAngles[3];
decl Float:vOrigin[3];
decl Float:vBuffer[3];
decl Float:vStart[3];
decl Float:Distance;
GetClientEyePosition(client,vOrigin);
GetClientEyeAngles(client, vAngles);
new Handle:trace = TR_TraceRayFilterEx(vOrigin, vAngles, MASK_SHOT, RayType_Infinite, TraceEntityFilterPlayer);
if(TR_DidHit(trace))
{
TR_GetEndPosition(vStart, trace);
GetVectorDistance(vOrigin, vStart, false);
Distance = -35.0;
GetAngleVectors(vAngles, vBuffer, NULL_VECTOR, NULL_VECTOR);
g_pos[0] = vStart[0] + (vBuffer[0]*Distance);
g_pos[1] = vStart[1] + (vBuffer[1]*Distance);
g_pos[2] = vStart[2] + (vBuffer[2]*Distance);
}
else
{
CloseHandle(trace);
return false;
}
CloseHandle(trace);
return true;
}
public bool:TraceEntityFilterPlayer(entity, contentsMask)
{
return entity > MaxClients;
}
public Action:Timer_GenericSound(Handle:timer, any:client)
{
if(pet[client] == 0 || IsValidEntity(pet[client]) == false)
{
SafeKillTimer(timer);
}
decl Float:pos[3];
GetEntPropVector(pet[client], Prop_Data, "m_vecOrigin", pos);
EmitAmbientSound(petInfo[petType[client]][iSoundGeneric], pos, pet[client], _, _, _, petInfo[petType[client]][iPitch]);
soundTimer[client] = CreateTimer(GetRandomFloat(20.0, 60.0), Timer_GenericSound, client);
}
public SetPetState(client, status)
{
decl Float:pos[3];
GetEntPropVector(pet[client], Prop_Data, "m_vecOrigin", pos);
if(petState[client] == status)
{
return;
}
switch(status)
{
case STATE_IDLE: SetPetAnim(client, petInfo[petType[client]][iAnimIdle]);
case STATE_WALKING: SetPetAnim(client, petInfo[petType[client]][iAnimWalk]);
case STATE_JUMPING:
{
SetPetAnim(client, petInfo[petType[client]][iAnimJump]);
EmitAmbientSound(petInfo[petType[client]][iSoundJump], pos, pet[client], _, _, _, petInfo[petType[client]][iPitch]);
}
case STATE_TAUNTING:
{
SetPetAnim(client, petInfo[petType[client]][iAnimTaunt]);
EmitAmbientSound(petInfo[petType[client]][iSoundTaunt], pos, pet[client], _, _, _, petInfo[petType[client]][iPitch]);
}
case STATE_SPAWNING:
{
SetPetAnim(client, petInfo[petType[client]][iAnimSpawn]);
EmitAmbientSound(petInfo[petType[client]][iSoundSpawn], pos, pet[client], _, _, _, petInfo[petType[client]][iPitch]);
}
case STATE_DUCKING:
{
SetPetAnim(client, petInfo[petType[client]][iAnimDuck]);
EmitAmbientSound(petInfo[petType[client]][iSoundDuck], pos, pet[client], _, _, _, petInfo[petType[client]][iPitch]);
}
case STATE_ATTACKING:
{
SetPetAnim(client, petInfo[petType[client]][iAnimAttack]);
EmitAmbientSound(petInfo[petType[client]][iSoundAttack], pos, pet[client], _, _, _, petInfo[petType[client]][iPitch]);
}
case STATE_STUN:
{
SetPetAnim(client, petInfo[petType[client]][iAnimStun]);
EmitAmbientSound(petInfo[petType[client]][iSoundStun], pos, pet[client], _, _, _, petInfo[petType[client]][iPitch]);
}
}
petState[client] = status;
}
public SetPetAnim(client, const String:anim[])
{
SetVariantString(anim);
AcceptEntityInput(pet[client], "SetAnimation");
}
public OffsetLocation(Float:pos[3])
{
pos[0] += GetRandomFloat(-128.0, 128.0);
pos[1] += GetRandomFloat(-128.0, 128.0);
}
public KillPet(client)
{
if(pet[client] == 0)
{
return;
}
decl Float:pos[3];
GetEntPropVector(pet[client], Prop_Data, "m_vecOrigin", pos);
SDKUnhook(client, SDKHook_PreThink, PetThink);
AcceptEntityInput(pet[client], "Kill");
CreateParticle(petInfo[petType[client]][iDeathParticle], pos);
pet[client] = 0;
}