From 8dca634772614ee3414326b1616f0116fdf8880a Mon Sep 17 00:00:00 2001 From: Battlefield Duck Date: Thu, 18 Apr 2019 04:58:30 +0800 Subject: [PATCH] Add files via upload --- gamedata/tf2items.randomizer.txt | 16 + plugins/TF2Sandbox-ToolGun.smx | Bin 0 -> 18967 bytes scripting/TF2Sandbox-ToolGun.sp | 815 +++++++++++++++++++++++++++++++ scripting/include/build.inc | 140 ++++++ 4 files changed, 971 insertions(+) create mode 100644 gamedata/tf2items.randomizer.txt create mode 100644 plugins/TF2Sandbox-ToolGun.smx create mode 100644 scripting/TF2Sandbox-ToolGun.sp create mode 100644 scripting/include/build.inc diff --git a/gamedata/tf2items.randomizer.txt b/gamedata/tf2items.randomizer.txt new file mode 100644 index 0000000..7868c76 --- /dev/null +++ b/gamedata/tf2items.randomizer.txt @@ -0,0 +1,16 @@ +"Games" +{ + /* Team Fortress 2 */ + "tf" + { + "Offsets" + { + "CTFPlayer::EquipWearable" + { + "windows" "430" + "linux" "431" + "mac" "431" + } + } + } +} diff --git a/plugins/TF2Sandbox-ToolGun.smx b/plugins/TF2Sandbox-ToolGun.smx new file mode 100644 index 0000000000000000000000000000000000000000..838bf68d9774f2ce768ab0ae830fe568f724144e GIT binary patch literal 18967 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 PQSc1GZxH;yv;YX@$L{ZW literal 0 HcmV?d00001 diff --git a/scripting/TF2Sandbox-ToolGun.sp b/scripting/TF2Sandbox-ToolGun.sp new file mode 100644 index 0000000..0da17fa --- /dev/null +++ b/scripting/TF2Sandbox-ToolGun.sp @@ -0,0 +1,815 @@ +#pragma semicolon 1 + +#define DEBUG + +#define PLUGIN_AUTHOR "BattlefieldDuck" +#define PLUGIN_VERSION "1.0" + +#include +#include +#include +#include +#include + +#pragma newdecls required + +public Plugin myinfo = +{ + name = "[TF2] Sandbox - Tool Gun", + author = PLUGIN_AUTHOR, + description = "Allows players to manipulate a variety of functions to create different things.", + version = PLUGIN_VERSION, + url = "https://github.com/tf2-sandbox-studio/Module-ToolGun" +}; + +//Physics Gun Settings +#define WEAPON_SLOT 1 + +#define MODEL_TOOLLASER "materials/sprites/physbeam.vmt" +#define MODEL_HALOINDEX "materials/sprites/halo01.vmt" +#define MODEL_TOOLGUNVM "models/weapons/v_357.mdl" +#define MODEL_TOOLGUNWM "models/weapons/w_357.mdl" + +#define SOUND_TOOLGUN_SHOOT (GetRandomInt(0, 1))? "weapons/airboat/airboat_gun_lastshot1.wav":"weapons/airboat/airboat_gun_lastshot2.wav" +#define SONND_TOOLGUN_SELECT "buttons/button15.wav" + +static const int g_iToolGunWeaponIndex = 1071;//Choose Gold Frying Pan(1071) because the player movement won't become a villager +static const int g_iToolGunQuality = 1; +static const int g_iToolGunLevel = 99-128; //Level displays as 99 but negative level ensures this is unique + +int g_iModelIndex; +int g_iHaloIndex; +int g_iToolGunVM; +int g_iToolGunWM; + +int g_iAimPointRef[MAXPLAYERS + 1]; //Entity aimming point +int g_iClientVMRef[MAXPLAYERS + 1]; //Client physics gun viewmodel ref +int g_iTools[MAXPLAYERS + 1]; +float g_fToolsCD[MAXPLAYERS + 1]; +bool g_bIN_RELOAD[MAXPLAYERS + 1]; +int g_iDisplay[MAXPLAYERS + 1]; +float g_fDisplayCD[MAXPLAYERS + 1]; + +//Duplicator +int g_iCopyEntityRef[MAXPLAYERS + 1]; + +//Color +int g_iEntityColor[MAXPLAYERS + 1]; + +//RenderFx +int g_iEntityRenderFx[MAXPLAYERS + 1]; + + +public void OnPluginStart() +{ + RegAdminCmd("sm_tg", Command_EquipToolGun, 0, "Equip a Tool Gun"); + //RegAdminCmd("sm_toolgun", Command_EquipToolGun, 0, "Equip a Tool Gun"); + + HookEvent("player_spawn", Event_PlayerSpawn); +} + +public void OnMapStart() +{ + g_iModelIndex = PrecacheModel(MODEL_TOOLLASER); + g_iHaloIndex = PrecacheModel(MODEL_HALOINDEX); + g_iToolGunVM = PrecacheModel(MODEL_TOOLGUNVM); + g_iToolGunWM = PrecacheModel(MODEL_TOOLGUNWM); + + PrecacheSound("weapons/airboat/airboat_gun_lastshot1.wav"); + PrecacheSound("weapons/airboat/airboat_gun_lastshot2.wav"); + PrecacheSound(SONND_TOOLGUN_SELECT); + + for (int client = 1; client < MAXPLAYERS; client++) + { + if(client > 0 && client <= MaxClients && IsClientInGame(client)) + { + OnClientPutInServer(client); + } + } +} + +public void OnClientPutInServer(int client) +{ + SDKHook(client, SDKHook_WeaponSwitchPost, WeaponSwitchHookPost); + + g_iClientVMRef[client] = INVALID_ENT_REFERENCE; + g_iAimPointRef[client] = EntIndexToEntRef(CreateAimPoint()); + g_iCopyEntityRef[client] = INVALID_ENT_REFERENCE; +} + +public Action Command_EquipToolGun(int client, int args) +{ + if(client <= 0 || client > MaxClients || !IsClientInGame(client) || !IsPlayerAlive(client)) + { + return Plugin_Continue; + } + + Build_PrintToChat(client, "You have equipped a Tool Gun (Sandbox version)!"); + + //Set tool gun as Active Weapon + int weapon = GetPlayerWeaponSlot(client, WEAPON_SLOT); + if (IsValidEntity(weapon)) + { + SetEntPropEnt(client, Prop_Send, "m_hActiveWeapon", weapon); + } + + //Credits: FlaminSarge + weapon = CreateEntityByName("tf_weapon_builder"); + if (IsValidEntity(weapon)) + { + SetEntityModel(weapon, MODEL_TOOLGUNWM); + SetEntProp(weapon, Prop_Send, "m_iItemDefinitionIndex", g_iToolGunWeaponIndex); + SetEntProp(weapon, Prop_Send, "m_bInitialized", 1); + //Player crashes if quality and level aren't set with both methods, for some reason + SetEntData(weapon, GetEntSendPropOffs(weapon, "m_iEntityQuality", true), g_iToolGunQuality); + SetEntData(weapon, GetEntSendPropOffs(weapon, "m_iEntityLevel", true), g_iToolGunLevel); + SetEntProp(weapon, Prop_Send, "m_iEntityQuality", g_iToolGunQuality); + SetEntProp(weapon, Prop_Send, "m_iEntityLevel", g_iToolGunLevel); + SetEntProp(weapon, Prop_Send, "m_iObjectType", 3); + SetEntProp(weapon, Prop_Data, "m_iSubType", 3); + SetEntProp(weapon, Prop_Send, "m_aBuildableObjectTypes", 0, _, 0); + SetEntProp(weapon, Prop_Send, "m_aBuildableObjectTypes", 0, _, 1); + SetEntProp(weapon, Prop_Send, "m_aBuildableObjectTypes", 0, _, 2); + SetEntProp(weapon, Prop_Send, "m_aBuildableObjectTypes", 1, _, 3); + SetEntProp(weapon, Prop_Send, "m_nSkin", 1); + SetEntProp(weapon, Prop_Send, "m_iWorldModelIndex", g_iToolGunWM); + SetEntProp(weapon, Prop_Send, "m_nModelIndexOverrides", g_iToolGunWM, _, 0); + SetEntProp(weapon, Prop_Send, "m_nSequence", 2); + + TF2_RemoveWeaponSlot(client, WEAPON_SLOT); + DispatchSpawn(weapon); + EquipPlayerWeapon(client, weapon); + } + + return Plugin_Continue; +} + +public void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast) +{ + int client = GetClientOfUserId(event.GetInt("userid")); + + if(client > 0 && client <= MaxClients && IsClientInGame(client)) + { + TF2_RegeneratePlayer(client); + } +} + +//ViewModel Handler +#define EF_NODRAW 32 +public Action WeaponSwitchHookPost(int client, int entity) +{ + if(client <= 0 || client > MaxClients || !IsClientInGame(client) || !IsPlayerAlive(client)) + { + return Plugin_Continue; + } + + int iViewModel = GetEntPropEnt(client, Prop_Send, "m_hViewModel"); + if(IsHoldingToolGun(client) && EntRefToEntIndex(g_iClientVMRef[client]) == INVALID_ENT_REFERENCE) + { + //Hide Original viewmodel + int iEffects = GetEntProp(iViewModel, Prop_Send, "m_fEffects"); + iEffects |= EF_NODRAW; + SetEntProp(iViewModel, Prop_Send, "m_fEffects", iEffects); + + //Create client physics gun viewmodel + g_iClientVMRef[client] = EntIndexToEntRef(CreateVM(client, g_iToolGunVM)); + } + //Remove client physics gun viewmodel + else if (EntRefToEntIndex(g_iClientVMRef[client]) != INVALID_ENT_REFERENCE) + { + AcceptEntityInput(EntRefToEntIndex(g_iClientVMRef[client]), "Kill"); + } + + return Plugin_Continue; +} + +public Action OnPlayerRunCmd(int client, int &buttons, int &impulse, float vel[3], float angles[3], int &weapon, int &subtype, int &cmdnum, int &tickcount, int &seed, int mouse[2]) +{ + if (IsHoldingToolGun(client) && ((buttons & IN_ATTACK) || (buttons & IN_ATTACK2)) && g_fToolsCD[client] <= 0.0) + { + g_fToolsCD[client] = 2.0; + + EmitSoundToClient(client, SOUND_TOOLGUN_SHOOT, client, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, 1.0, 100); + + TE_SetupBeamRingPoint(GetClientAimPosition(client), 5.0, 20.0, g_iModelIndex, g_iHaloIndex, 0, 10, 0.5, 3.0, 10.0, {255, 255, 255, 255}, 10, 0); + TE_SendToAll(); + + int clientvm = EntRefToEntIndex(g_iClientVMRef[client]); + int iAimPoint = EntRefToEntIndex(g_iAimPointRef[client]); + if (clientvm != INVALID_ENT_REFERENCE && iAimPoint != INVALID_ENT_REFERENCE) + { + TeleportEntity(iAimPoint, GetClientAimPosition(client), NULL_VECTOR, NULL_VECTOR); + + TE_SetupBeamEnts(iAimPoint, EntRefToEntIndex(g_iClientVMRef[client]), g_iModelIndex, g_iHaloIndex, 0, 15, 0.1, 1.0, 1.0, 1, 0.0, {255, 255, 255, 255}, 10, 20); + TE_SendToClient(client); + + for (int i = 1; i <= MaxClients; i++) + { + if (client != i && IsClientInGame(i)) + { + TE_SetupBeamEnts(client, iAimPoint, g_iModelIndex, g_iHaloIndex, 0, 15, 0.1, 1.0, 1.0, 1, 0.0, {255, 255, 255, 255}, 10, 20); + TE_SendToClient(i); + } + } + } + + int entity = GetClientAimEntity(client); + switch (g_iTools[client]) + { + //Remove + case(0): + { + if (IsValidEntity(entity)) + { + AcceptEntityInput(entity, "Kill"); + PrintCenterText(client, "Removed (%i)", entity); + } + } + //Resizer + case(1): + { + if (IsValidEntity(entity)) + { + float fSize = GetEntPropFloat(entity, Prop_Send, "m_flModelScale"); + if ((buttons & IN_ATTACK) && (fSize < 2.0)) + { + fSize += 0.1; + } + else if ((buttons & IN_ATTACK2) && (fSize > 0.1)) + { + fSize -= 0.1; + } + SetEntPropFloat(entity, Prop_Send, "m_flModelScale", fSize); + PrintCenterText(client, "Size: %.1f", fSize); + } + } + //Set Collision + case (2): + { + if (IsValidEntity(entity)) + { + if (buttons & IN_ATTACK) + { + SetEntData(entity, FindSendPropInfo("CBaseEntity", "m_CollisionGroup"), 5, 4, true); + PrintCenterText(client, "Collide"); + } + else if (buttons & IN_ATTACK2) + { + SetEntData(entity, FindSendPropInfo("CBaseEntity", "m_CollisionGroup"), 2, 4, true); + PrintCenterText(client, "No Collide"); + } + } + } + //Duplicator + case (3): + { + if (buttons & IN_ATTACK) + { + g_iCopyEntityRef[client] = EntIndexToEntRef(entity); + PrintCenterText(client, "Copied! Index: %i", entity); + } + else if (buttons & IN_ATTACK2) + { + int iCopyEntity = EntRefToEntIndex(g_iCopyEntityRef[client]); + if (iCopyEntity != INVALID_ENT_REFERENCE) + { + int iPasteEntity = Duplicator(iCopyEntity); + if (IsValidEntity(iPasteEntity) && Build_RegisterEntityOwner(iPasteEntity, client)) + { + if (Build_RegisterEntityOwner(iPasteEntity, client)) + { + TeleportEntity(iPasteEntity, GetClientAimPosition(client), NULL_VECTOR, NULL_VECTOR); + PrintCenterText(client, "Pasted! Index: %i", iPasteEntity); + } + else + { + AcceptEntityInput(iPasteEntity, "Kill"); + } + } + } + } + + } + //Set Alpha + case (4): + { + if (IsValidEntity(entity)) + { + int iR, iG, iB, iA; + GetEntityRenderColor(entity, iR, iG, iB, iA); + + SetEntityRenderMode(entity, RENDER_TRANSCOLOR); + + if (buttons & IN_ATTACK && iA > 55) + { + iA -= 10; + if (iA < 0) iA = 55; + } + else if (buttons & IN_ATTACK2 && iA < 255) + { + iA += 10; + if (iA > 255) iA = 255; + } + SetEntityRenderColor(entity, iR, iG, iB, iA); + PrintCenterText(client, "Alpha: %i", iA); + } + } + //Set Color + case (5): + { + if (IsValidEntity(entity)) + { + int iR, iG, iB, iA; + GetEntityRenderColor(entity, iR, iG, iB, iA); + SetEntityRenderMode(entity, RENDER_TRANSCOLOR); + + if (buttons & IN_ATTACK) + { + if (EntRefToEntIndex(g_iCopyEntityRef[client]) == INVALID_ENT_REFERENCE) + { + g_iCopyEntityRef[client] = EntIndexToEntRef(entity); + } + + if (entity == EntRefToEntIndex(g_iCopyEntityRef[client])) + { + (g_iEntityColor[client] < 5)? (g_iEntityColor[client]++):(g_iEntityColor[client] = 0); + } + + char strColor[10]; + switch (g_iEntityColor[client]) + { + case (0): { iR = 128; iG = 0; iB = 128; strColor = "Purple"; } + case (1): { iR = 255; iG = 0; iB = 0; strColor = "Red"; } + case (2): { iR = 255; iG = 165; iB = 0; strColor = "Orange"; } + case (3): { iR = 255; iG = 255; iB = 0; strColor = "Yellow"; } + case (4): { iR = 0; iG = 255; iB = 0; strColor = "Green"; } + case (5): { iR = 0; iG = 0; iB = 255; strColor = "Blue"; } + } + + SetEntityRenderColor(entity, iR, iG, iB, iA); + PrintCenterText(client, "Color: %s", strColor); + + g_iCopyEntityRef[client] = EntIndexToEntRef(entity); + } + else if (buttons & IN_ATTACK2) + { + iR = 255; + iG = 255; + iB = 255; + + SetEntityRenderMode(entity, RENDER_NORMAL); + SetEntityRenderColor(entity, iR, iG, iB, iA); + + if (iA < 255) + { + SetEntityRenderMode(entity, RENDER_TRANSCOLOR); + } + + PrintCenterText(client, "Restored"); + } + } + } + //Set Skin + case (6): + { + if (IsValidEntity(entity)) + { + int iSkin = GetEntProp(entity, Prop_Send, "m_nSkin"); + if (buttons & IN_ATTACK) + { + iSkin += 1; + } + else if (buttons & IN_ATTACK2 && iSkin > 1) + { + iSkin -= 1; + } + SetEntProp(entity, Prop_Send, "m_nSkin", iSkin); + PrintCenterText(client, "Skin: %i", iSkin); + } + } + //Set Render Fx + case (7): + { + if (IsValidEntity(entity)) + { + if (EntRefToEntIndex(g_iCopyEntityRef[client]) == INVALID_ENT_REFERENCE) + { + g_iCopyEntityRef[client] = EntIndexToEntRef(entity); + } + + g_iEntityRenderFx[client] = view_as(GetEntityRenderFx(entity)); + + if (buttons & IN_ATTACK && entity == EntRefToEntIndex(g_iCopyEntityRef[client])) + { + if (g_iEntityRenderFx[client] < 16) + { + g_iEntityRenderFx[client]++; + } + else + { + g_iEntityRenderFx[client] = 0; + } + } + else if (buttons & IN_ATTACK2 && entity == EntRefToEntIndex(g_iCopyEntityRef[client])) + { + if (g_iEntityRenderFx[client] > 0) + { + g_iEntityRenderFx[client]--; + } + else + { + g_iEntityRenderFx[client] = 16; + } + } + + char strRenderFx[40]; + switch (g_iEntityRenderFx[client]) + { + case (0): { strRenderFx = "RENDERFX_NONE"; } + case (1): { strRenderFx = "RENDERFX_PULSE_SLOW"; } + case (2): { strRenderFx = "RENDERFX_PULSE_FAST"; } + case (3): { strRenderFx = "RENDERFX_PULSE_SLOW_WIDE"; } + case (4): { strRenderFx = "RENDERFX_PULSE_FAST_WIDE"; } + case (5): { strRenderFx = "RENDERFX_FADE_SLOW"; } + case (6): { strRenderFx = "RENDERFX_FADE_FAST"; } + case (7): { strRenderFx = "RENDERFX_SOLID_SLOW"; } + case (8): { strRenderFx = "RENDERFX_SOLID_FAST"; } + case (9): { strRenderFx = "RENDERFX_STROBE_SLOW"; } + case (10): { strRenderFx = "RENDERFX_STROBE_FAST"; } + case (11): { strRenderFx = "RENDERFX_STROBE_FASTER"; } + case (12): { strRenderFx = "RENDERFX_FLICKER_SLOW"; } + case (13): { strRenderFx = "RENDERFX_FLICKER_FAST"; } + case (14): { strRenderFx = "RENDERFX_NO_DISSIPATION"; } + case (15): { strRenderFx = "RENDERFX_DISTORT"; } + case (16): { strRenderFx = "RENDERFX_HOLOGRAM"; } + } + + SetEntityRenderFx(entity, view_as(g_iEntityRenderFx[client])); + PrintCenterText(client, "RenderFx: %s (%i)", strRenderFx, g_iEntityRenderFx[client]); + + g_iCopyEntityRef[client] = EntIndexToEntRef(entity); + } + } + + } + } + else if (g_fToolsCD[client] > 0.0) + { + g_fToolsCD[client] -= 0.1; + } + + if (IsHoldingToolGun(client)) + { + //Switch tools + if (buttons & IN_RELOAD && !g_bIN_RELOAD[client]) + { + g_bIN_RELOAD[client] = true; + + EmitSoundToClient(client, SONND_TOOLGUN_SELECT, client, SNDCHAN_AUTO, SNDLEVEL_NORMAL, SND_NOFLAGS, 1.0, 100); + + (g_iTools[client] < 7)? (g_iTools[client]++) : (g_iTools[client] = 0); + + //Reset value + if (g_iTools[client] == 3) + { + g_iCopyEntityRef[client] = INVALID_ENT_REFERENCE; + } + else if (g_iTools[client] == 5) + { + g_iEntityColor[client] = 0; + } + else if (g_iTools[client] == 7) + { + g_iEntityRenderFx[client] = 0; + } + } + else if (!(buttons & IN_RELOAD)) + { + g_bIN_RELOAD[client] = false; + } + + char display[170]; + Format(display, sizeof(display), "------------------------\n%s\n------------------------\n\ + [MOUSE1] %s\n[MOUSE2] %s\n[RELOAD] Switch Tools (%i)" + , GetToolDisplay(g_iTools[client], client), GetToolMouse1(g_iTools[client]), GetToolMouse2(g_iTools[client]), g_iTools[client] ); + + SetHudTextParams(0.75, 0.45, 0.05, 255, 255, 255, 150, 0, 0.0, 0.0, 0.0); + + if (!(buttons & IN_SCORE)) + { + ShowHudText(client, -1, display); + } + + } + + return Plugin_Continue; +} + +/******************** + Stock +*********************/ +bool IsHoldingToolGun(int client) +{ + int iWeapon = GetPlayerWeaponSlot(client, WEAPON_SLOT); + int iActiveWeapon = GetEntPropEnt(client, Prop_Send, "m_hActiveWeapon"); + + return (IsValidEntity(iWeapon) && iWeapon == iActiveWeapon && IsToolGun(iActiveWeapon)); +} + +//Credits: FlaminSarge +bool IsToolGun(int entity) +{ + if (GetEntSendPropOffs(entity, "m_iItemDefinitionIndex", true) <= 0) + { + return false; + } + return GetEntProp(entity, Prop_Send, "m_iItemDefinitionIndex") == g_iToolGunWeaponIndex + && GetEntProp(entity, Prop_Send, "m_iEntityQuality") == g_iToolGunQuality + && GetEntProp(entity, Prop_Send, "m_iEntityLevel") == g_iToolGunLevel; +} + +//Credits: FlaminSarge +#define EF_BONEMERGE (1 << 0) +#define EF_BONEMERGE_FASTCULL (1 << 7) +int CreateVM(int client, int modelindex) +{ + int ent = CreateEntityByName("tf_wearable_vm"); + if (!IsValidEntity(ent)) return -1; + SetEntProp(ent, Prop_Send, "m_nModelIndex", modelindex); + SetEntProp(ent, Prop_Send, "m_fEffects", EF_BONEMERGE|EF_BONEMERGE_FASTCULL); + SetEntProp(ent, Prop_Send, "m_iTeamNum", GetClientTeam(client)); + SetEntProp(ent, Prop_Send, "m_usSolidFlags", 4); + SetEntProp(ent, Prop_Send, "m_CollisionGroup", 11); + DispatchSpawn(ent); + SetVariantString("!activator"); + ActivateEntity(ent); + TF2_EquipWearable(client, ent); + return ent; +} + +//Credits: FlaminSarge +Handle g_hSdkEquipWearable; +int TF2_EquipWearable(int client, int entity) +{ + if (g_hSdkEquipWearable == INVALID_HANDLE) + { + Handle hGameConf = LoadGameConfigFile("tf2items.randomizer"); + if (hGameConf == INVALID_HANDLE) + { + SetFailState("Couldn't load SDK functions. Could not locate tf2items.randomizer.txt in the gamedata folder."); + return; + } + StartPrepSDKCall(SDKCall_Player); + PrepSDKCall_SetFromConf(hGameConf, SDKConf_Virtual, "CTFPlayer::EquipWearable"); + PrepSDKCall_AddParameter(SDKType_CBaseEntity, SDKPass_Pointer); + g_hSdkEquipWearable = EndPrepSDKCall(); + if (g_hSdkEquipWearable == INVALID_HANDLE) + { + SetFailState("Could not initialize call for CTFPlayer::EquipWearable"); + CloseHandle(hGameConf); + return; + } + } + if (g_hSdkEquipWearable != INVALID_HANDLE) SDKCall(g_hSdkEquipWearable, client, entity); +} + +int CreateAimPoint() +{ + int iAimPoint = CreateEntityByName("prop_dynamic_override"); + DispatchKeyValue(iAimPoint, "model", MODEL_TOOLGUNWM); + + SetEntPropFloat(iAimPoint, Prop_Send, "m_flModelScale", 0.0); + + DispatchSpawn(iAimPoint); + return iAimPoint; +} + +//Normally 2 is okay but 4 is more secure +#define FRAME_DELAY 5 + +//Credits: Pelipoika +public void KillAimPointPost(int entity) +{ + static int iFrame = 0; + + if(++iFrame < FRAME_DELAY) + { + RequestFrame(KillAimPointPost, entity); + return; + } + + int iAimPoint = EntRefToEntIndex(entity); + if(iAimPoint != INVALID_ENT_REFERENCE) + { + AcceptEntityInput(iAimPoint, "Kill"); + } + + iFrame = 0; +} + +//Credits: Alienmario +void TE_SetupBeamEnts(int ent1, int ent2, int ModelIndex, int HaloIndex, int StartFrame, int FrameRate, float Life, float Width, float EndWidth, int FadeLength, float Amplitude, const int Color[4], int Speed, int flags) +{ + TE_Start("BeamEnts"); + TE_WriteEncodedEnt("m_nStartEntity", ent1); + TE_WriteEncodedEnt("m_nEndEntity", ent2); + TE_WriteNum("m_nModelIndex", ModelIndex); + TE_WriteNum("m_nHaloIndex", HaloIndex); + TE_WriteNum("m_nStartFrame", StartFrame); + TE_WriteNum("m_nFrameRate", FrameRate); + TE_WriteFloat("m_fLife", Life); + TE_WriteFloat("m_fWidth", Width); + TE_WriteFloat("m_fEndWidth", EndWidth); + TE_WriteFloat("m_fAmplitude", Amplitude); + TE_WriteNum("r", Color[0]); + TE_WriteNum("g", Color[1]); + TE_WriteNum("b", Color[2]); + TE_WriteNum("a", Color[3]); + TE_WriteNum("m_nSpeed", Speed); + TE_WriteNum("m_nFadeLength", FadeLength); + TE_WriteNum("m_nFlags", flags); +} + +float[] GetClientEyePositionEx(int client) +{ + float pos[3]; + GetClientEyePosition(client, pos); + return pos; +} + +float[] GetClientEyeAnglesEx(int client) +{ + float angles[3]; + GetClientEyeAngles(client, angles); + return angles; +} + +float[] GetClientAimPosition(int client) +{ + Handle trace = TR_TraceRayFilterEx(GetClientEyePositionEx(client), GetClientEyeAnglesEx(client), MASK_SOLID, RayType_Infinite, TraceEntityFilter, client); + + float endpos[3]; + if(TR_DidHit(trace)) + { + TR_GetEndPosition(endpos, trace); + } + + CloseHandle(trace); + return endpos; +} + +stock float[] GetClientAimNormal(int client) +{ + Handle trace = TR_TraceRayFilterEx(GetClientEyePositionEx(client), GetClientEyeAnglesEx(client), MASK_SOLID, RayType_Infinite, TraceEntityFilter, client); + + float endnormal[3]; + if(TR_DidHit(trace)) + { + TR_GetPlaneNormal(trace, endnormal); + } + + CloseHandle(trace); + return endnormal; +} + +int GetClientAimEntity(int client) +{ + Handle trace = TR_TraceRayFilterEx(GetClientEyePositionEx(client), GetClientEyeAnglesEx(client), MASK_SOLID, RayType_Infinite, TraceEntityFilter, client); + + if(TR_DidHit(trace)) + { + int entity = TR_GetEntityIndex(trace); + if (entity > 0 && Build_ReturnEntityOwner(entity) == client) + { + CloseHandle(trace); + return entity; + } + } + + CloseHandle(trace); + return -1; +} + +public bool TraceEntityFilter(int entity, int mask, int client) +{ + return (IsValidEntity(entity) + && entity != client + && MaxClients < entity); +} + +int Duplicator(int iEntity) +{ + //Get Value + float fOrigin[3], fAngles[3], fSize; + char szModel[64], szName[128], szClass[32]; + int iCollision, iRed, iGreen, iBlue, iAlpha, iSkin; + RenderFx EntityRenderFx; + + GetEntityClassname(iEntity, szClass, sizeof(szClass)); + GetEntPropString(iEntity, Prop_Data, "m_ModelName", szModel, sizeof(szModel)); + GetEntPropVector(iEntity, Prop_Send, "m_vecOrigin", fOrigin); + GetEntPropVector(iEntity, Prop_Data, "m_angRotation", fAngles); + iCollision = GetEntProp(iEntity, Prop_Data, "m_CollisionGroup", 4); + fSize = GetEntPropFloat(iEntity, Prop_Send, "m_flModelScale"); + GetEntityRenderColor(iEntity, iRed, iGreen, iBlue, iAlpha); + EntityRenderFx = GetEntityRenderFx(iEntity); + iSkin = GetEntProp(iEntity, Prop_Send, "m_nSkin"); + GetEntPropString(iEntity, Prop_Data, "m_iName", szName, sizeof(szName)); + + int iNewEntity = CreateEntityByName(szClass); + if (iNewEntity > MaxClients && IsValidEntity(iNewEntity)) + { + SetEntProp(iNewEntity, Prop_Send, "m_nSolidType", 6); + SetEntProp(iNewEntity, Prop_Data, "m_nSolidType", 6); + + if (!IsModelPrecached(szModel)) + { + PrecacheModel(szModel); + } + + DispatchKeyValue(iNewEntity, "model", szModel); + TeleportEntity(iNewEntity, fOrigin, fAngles, NULL_VECTOR); + DispatchSpawn(iNewEntity); + SetEntData(iNewEntity, FindSendPropInfo("CBaseEntity", "m_CollisionGroup"), iCollision, 4, true); + SetEntPropFloat(iNewEntity, Prop_Send, "m_flModelScale", fSize); + if(iAlpha < 255) SetEntityRenderMode(iNewEntity, RENDER_TRANSCOLOR); + else SetEntityRenderMode(iNewEntity, RENDER_NORMAL); + SetEntityRenderColor(iNewEntity, iRed, iGreen, iBlue, iAlpha); + SetEntityRenderFx(iNewEntity, EntityRenderFx); + SetEntProp(iNewEntity, Prop_Send, "m_nSkin", iSkin); + SetEntPropString(iNewEntity, Prop_Data, "m_iName", szName); + + return iNewEntity; + } + return -1; +} + +#define SPACE " " +char[] GetToolDisplay(int tool, int client) +{ + char toolname[61]; + switch (tool) + { + case (0):toolname = " Remover "; + case (1):toolname = " Resizer "; + case (2):toolname = " Set Collision "; + case (3):toolname = " Duplicator "; + case (4):toolname = " Set Alpha "; + case (5):toolname = " Set Color "; + case (6):toolname = " Set Skin "; + case (7):toolname = " Set Render Fx "; + } + Format(toolname, sizeof(toolname), "%s%s%s", SPACE, toolname, SPACE); + + char display[26] = ""; + for (int i = g_iDisplay[client]; i < (g_iDisplay[client] + 25); i++) + { + Format(display, sizeof(display), "%s%s", display, toolname[i]); + } + + if (g_fDisplayCD[client] <= 0.0) + { + g_fDisplayCD[client] = 1.0; + (g_iDisplay[client] < 35)? (g_iDisplay[client]++) : (g_iDisplay[client] = 0); + } + else if (g_fDisplayCD[client] > 0.0) + { + g_fDisplayCD[client] -= 0.1; + } + + return display; +} + +char[] GetToolMouse1(int tool) +{ + char mouse1[30]; + switch (tool) + { + case (0):mouse1 = "Remove"; + case (1):mouse1 = "Larger"; + case (2):mouse1 = "Collide"; + case (3):mouse1 = "Copy"; + case (4):mouse1 = "More Transparent"; + case (5):mouse1 = "Next Color"; + case (6):mouse1 = "Next Skin"; + case (7):mouse1 = "Next Render Fx"; + } + return mouse1; +} + +char[] GetToolMouse2(int tool) +{ + char mouse2[30]; + switch (tool) + { + case (0):mouse2 = "Remove"; + case (1):mouse2 = "Smaller"; + case (2):mouse2 = "No Collide"; + case (3):mouse2 = "Paste"; + case (4):mouse2 = "More Visible"; + case (5):mouse2 = "Restore"; + case (6):mouse2 = "Previous Skin"; + case (7):mouse2 = "Previous Render Fx"; + } + return mouse2; +} diff --git a/scripting/include/build.inc b/scripting/include/build.inc new file mode 100644 index 0000000..63425b8 --- /dev/null +++ b/scripting/include/build.inc @@ -0,0 +1,140 @@ +#define BUILDMODAPI_VER 3 +#define BUILDMOD_VER "0.75.5" +#define MAX_HOOK_ENTITIES 4096 + +/** + * Register an entity owner. + * + * @param entity_index Entity index. + * @param client_index Client index. + * @param Doll Is prop_ragdoll? + * @return Ture on success. False on failure. + */ +native bool:Build_RegisterEntityOwner(entity_index, client_index, bool:Doll = false); + +/** + * Get an entity owner. + * + * @param entity_index Entity index. + * @return -1 on failure. Any other value indicates a Entity index owner. + */ +native Build_ReturnEntityOwner(entity_index); + +/** + * Set client props limit. + * + * @param client_index Client index. + * @param amount Amount to increase or decrease. If amount = 0 then set limit to 0. + * @param Doll Is prop_ragdoll? + * @noreturn + */ +native Build_SetLimit(client_index, amount, bool:Doll = false); + +/** + * Check client can use BuildMod. + * + * @param client_index Client index. + * @return True on success. False on failure. + */ +native bool:Build_AllowToUse(client_index); + +/** + * Check client can use Fly. + * + * @param client_index Client index. + * @return True on success. False on failure. + */ +native bool:Build_AllowFly(client_index); + +/** + * Get client admin. + * + * @param client_index Client index. + * @param Level2 Level 2 access. + * @return True on admin. False on not. + */ +native bool:Build_IsAdmin(client_index, bool:Level2 = false); + +/** + * Get client aim entity. + * + * @param client_index Client index. + * @param show_message Show a message when entity invalid? + * @param included_clients Allow native to getting clients? + * @return -1 on failure. Any other value indicates a Entity index. + */ +native Build_ClientAimEntity(client_index, bool:show_message = true, bool:included_clients = false); + +/** + * Get an entity of owner is equal client. + * + * @param client_index Client index. + * @param entity_index Entity index. + * @param bIngoreCvar Ingore 'bm_nonowner' cvar? + * @return True on owner. False on not. + */ +native bool:Build_IsEntityOwner(client_index, entity_index, bool:bIngoreCvar = false); + +/** + * Logging commands and args. + * + * @param client_index Client index. + * @param command Command to log. + * @param args Args to log. + * @noreturn + */ +native Build_Logging(client_index, const String:command[], const String:args[]); + +/** + * Prints a message with the BuildMod tag. + * + * @param client_index Client index. + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + */ +native Build_PrintToChat(client_index, const String:format[], any:...); + +/** + * Prints a message to all clients with the BuildMod tag. + * + * @param format Formatting rules. + * @param ... Variable number of format parameters. + * @noreturn + */ +native Build_PrintToAll(const String:format[], any:...); + +/** + * Add client to blacklist. + * + * @param client_index Client index. + * @return True on success. False on failure. + */ +native Build_AddBlacklist(client_index); + +/** + * Remove client from blacklist. + * + * @param client_index Client index. + * @return True on success. False on failure. + */ +native Build_RemoveBlacklist(client_index); + +/** + * Get client is blacklisted. + * + * @param client_index Client index. + * @return True on blacklisted. False on not. + */ +native bool:Build_IsBlacklisted(client_index); + +/** + * Check is target client valid. + * + * @param client_index Client index. + * @param target_index Target index. + * @param Alive Check is target alive. + * @param ReplyTarget Alive result reply target client or self. + * @return True if target valid. Otherwise false. + */ +native bool:Build_IsClientValid(client_index, target_index, bool:Alive = false, bool:ReplyTarget = false);