#pragma semicolon 1 #include #include public Plugin myinfo = { name = "Prop Spawner", author = "Moltard / LightningZLaser", description = "A plugin to spawn props", version = "0.1", url = "https://steamcommunity.com/id/0123456789ABC/" }; Menu g_MainMenu = null; Menu g_RotationMenu = null; Menu g_PhysicMenu = null; Menu g_DynamicMenu = null; Menu g_NpcMenu = null; KeyValues g_Models; public void OnPluginStart() { LoadTranslations("common.phrases"); char sModelsFile[PLATFORM_MAX_PATH]; BuildPath(Path_SM, sModelsFile, sizeof(sModelsFile), "configs/PropSpawner.cfg"); if(!FileExists(sModelsFile)) { SetFailState("Could not find config: \"%s\"", sModelsFile); return; } g_Models = new KeyValues("models"); if(!g_Models.ImportFromFile(sModelsFile)) { delete g_Models; SetFailState("ImportFromFile() failed!"); return; } g_Models.Rewind(); // Go back to the root node RegAdminCmd("sm_propspawner", Command_MainMenu, ADMFLAG_CHANGEMAP); //g } public void OnMapStart() { g_Models.Rewind(); g_MainMenu = BuildMainMenu(); g_RotationMenu = BuildRotationMenu(); g_PhysicMenu = BuildModelsMenu("physic"); g_DynamicMenu = BuildModelsMenu("dynamic"); g_NpcMenu = BuildModelsMenu("npc"); } public void OnMapEnd() { if (g_MainMenu != null) { delete(g_MainMenu); g_MainMenu = null; } if (g_RotationMenu != null) { delete(g_RotationMenu); g_RotationMenu = null; } if (g_PhysicMenu != null) { delete(g_PhysicMenu); g_PhysicMenu = null; } if (g_DynamicMenu != null) { delete(g_DynamicMenu); g_DynamicMenu = null; } if (g_NpcMenu != null) { delete(g_NpcMenu); g_NpcMenu = null; } } /* ----------------------------------- */ Menu BuildMainMenu(){ Menu menu = new Menu(MainMenuHandler); menu.SetTitle("Prop Spawner"); menu.AddItem("menu_prop_delete", "Delete Prop"); menu.AddItem("menu_prop_rotate", "Rotate Prop"); menu.AddItem("menu_prop_dynamic", "Dynamic/Static Props"); menu.AddItem("menu_prop_physic", "Physic Props"); menu.AddItem("menu_prop_npc", "NPCs"); menu.ExitButton = true; return menu; } Menu BuildRotationMenu(){ Menu menu = new Menu(RotationHandler); SetMenuTitle(menu, "Rotate Menu"); menu.AddItem( "X_+45", "Rotate X +45 Degrees"); menu.AddItem( "X_-45", "Rotate X -45 Degrees"); menu.AddItem( "Y_+45", "Rotate Y +45 Degrees"); menu.AddItem( "Y_-45", "Rotate Y -45 Degrees"); menu.AddItem( "Z_+45", "Rotate Z +45 Degrees"); menu.AddItem( "Z_-45", "Rotate Z -45 Degrees"); menu.ExitBackButton = true; menu.ExitButton = true; return menu; } Menu BuildModelsMenu(char[] modelType){ Menu menu; if(StrEqual(modelType, "physic")){ menu = new Menu(PhysicHandler); SetMenuTitle(menu, "Physic Props"); } else if(StrEqual(modelType, "dynamic")){ menu = new Menu(DynamicHandler); SetMenuTitle(menu, "Dynamic Props"); } else if(StrEqual(modelType, "npc")){ menu = new Menu(NpcHandler); SetMenuTitle(menu, "NPCs"); } menu.AddItem("deleteProp", "Delete Prop"); if(g_Models.JumpToKey(modelType, false)){ for(int i = 0; i < 100000; i++){ char sName[32]; char sIndex[11]; IntToString(i,sIndex, sizeof(sIndex)); // Index i of the model if (!(g_Models.JumpToKey(sIndex, false))) // if the key doesnt exist break; // we stop the loop g_Models.GetString("name", sName, sizeof(sName)); // Name of the model menu.AddItem(sIndex,sName); g_Models.GoBack(); // First sub key of the prop category } } g_Models.Rewind(); // Go back to the root node menu.ExitBackButton = true; menu.ExitButton = true; return menu; } /* ----------------------------------- */ public Action Command_MainMenu(int client, int args) { g_MainMenu.Display(client, MENU_TIME_FOREVER); return Plugin_Handled; } public int MainMenuHandler(Menu menu, MenuAction action, int client, int param2) { char info[32]; menu.GetItem(param2, info, sizeof(info)); // Get the string of the picked option switch(action) { case(MenuAction_Select): { if(StrEqual(info, "menu_prop_delete")){ DeleteProp(client); g_MainMenu.Display(client, MENU_TIME_FOREVER); } else if(StrEqual(info, "menu_prop_rotate")){ g_RotationMenu.Display(client, MENU_TIME_FOREVER); } else if(StrEqual(info, "menu_prop_dynamic")){ g_DynamicMenu.Display(client, MENU_TIME_FOREVER); } else if(StrEqual(info, "menu_prop_physic")){ g_PhysicMenu.Display(client, MENU_TIME_FOREVER); } else if(StrEqual(info, "menu_prop_npc")){ g_NpcMenu.Display(client, MENU_TIME_FOREVER); } } } } public RotationHandler(Menu menu, MenuAction action, int client, int param2) { char info[32]; menu.GetItem(param2, info, sizeof(info)); // Get the string of the picked option switch(action) { case(MenuAction_Select): { if(StrEqual(info, "X_+45")) { RotateProp(45.0,0,client); } else if(StrEqual(info, "Y_+45")) { RotateProp(45.0,1,client); } else if(StrEqual(info, "Z_+45")) { RotateProp(45.0,2,client); } else if(StrEqual(info, "X_-45")) { RotateProp(-45.0,0,client); } else if(StrEqual(info, "Y_-45")) { RotateProp(-45.0,1,client); } else if(StrEqual(info, "Z_-45")) { RotateProp(-45.0,2,client); } g_RotationMenu.Display(client, MENU_TIME_FOREVER); } case(MenuAction_Cancel): { if(param2 == MenuCancel_ExitBack) { g_MainMenu.Display(client, MENU_TIME_FOREVER); } } } } public PhysicHandler(Menu menu, MenuAction action, int client, int param2) { char info[32]; menu.GetItem(param2, info, sizeof(info)); // Get the string of the picked option switch(action) { case(MenuAction_Select): { if(StrEqual(info, "deleteProp")) { DeleteProp(client); g_PhysicMenu.Display(client, MENU_TIME_FOREVER); } else{ // Info has the index of the model SpawnProp("physic",info,client); } } case(MenuAction_Cancel): { if(param2 == MenuCancel_ExitBack) { g_MainMenu.Display(client, MENU_TIME_FOREVER); } } } } public DynamicHandler(Menu menu, MenuAction action, int client, int param2) { char info[32]; menu.GetItem(param2, info, sizeof(info)); // Get the string of the picked option switch(action) { case(MenuAction_Select): { if(StrEqual(info, "deleteProp")) { DeleteProp(client); g_DynamicMenu.Display(client, MENU_TIME_FOREVER); // We display again the menu } else{ // Info has the index of the model in the array SpawnProp("dynamic",info,client); } } case(MenuAction_Cancel): { if(param2 == MenuCancel_ExitBack) { g_MainMenu.Display(client, MENU_TIME_FOREVER); } } } } public NpcHandler(Menu menu, MenuAction action, int client, int param2) { char info[32]; menu.GetItem(param2, info, sizeof(info)); // Get the string of the picked option switch(action) { case(MenuAction_Select): { if(StrEqual(info, "deleteProp")) { DeleteProp(client); g_NpcMenu.Display(client, MENU_TIME_FOREVER); // We display again the menu } else{ // Info has the index of the model in the array SpawnProp("npc",info,client); } } case(MenuAction_Cancel): { if(param2 == MenuCancel_ExitBack) { g_MainMenu.Display(client, MENU_TIME_FOREVER); } } } } bool isAProp(char[] classname){ if(StrEqual(classname, "prop_physics") || StrEqual(classname, "prop_physics_override") || StrEqual(classname, "prop_dynamic") || StrEqual(classname, "prop_dynamic_override") || StrEqual(classname, "prop_physics_multiplayer") || StrEqual(classname, "prop_dynamic_ornament") || StrEqual(classname, "prop_static")){ return true; } return false; } void DeleteProp(int client){ char classname[64]; new DeleteIndex = GetClientAimTarget(client, false); if (DeleteIndex != -1) { GetEdictClassname(DeleteIndex, classname, sizeof(classname)); if(isAProp(classname)) { AcceptEntityInput(DeleteIndex, "Kill", -1, -1, 0); ShowActivity2(client, "\x01[SM] \x04", "deleted a prop."); LogAction(client, -1, "\"%L\" deleted a prop.", client); } } if ((DeleteIndex == -1) || !isAProp(classname)) { ReplyToCommand(client, "[SM] No entity found or invalid entity."); } } void RotateProp(float RotateValue, int RotateAxis, int client){ char classname[64]; float RotateVec[3]; int RotateIndex = GetClientAimTarget(client, false); if (RotateIndex != -1) { GetEdictClassname(RotateIndex, classname, sizeof(classname)); if(isAProp(classname)) { GetEntPropVector(RotateIndex, Prop_Send, "m_angRotation", RotateVec); RotateVec[RotateAxis] = RotateVec[RotateAxis] + RotateValue; TeleportEntity(RotateIndex, NULL_VECTOR, RotateVec, NULL_VECTOR); AcceptEntityInput(RotateIndex, "EnableCollision"); AcceptEntityInput(RotateIndex, "TurnOn", RotateIndex, RotateIndex, 0); ShowActivity2(client, "\x01[SM] \x04", "rotated a prop."); LogAction(client, -1, "\"%L\" rotated a prop.", client); } } if ((RotateIndex == -1) || !isAProp(classname)) { ReplyToCommand(client, "[SM] No entity found or invalid entity."); } } void SpawnProp(char[] TypeProp, char[] PropId, int client){ if(StrEqual(TypeProp, "physic") || StrEqual(TypeProp, "dynamic") || StrEqual(TypeProp, "npc")){ if(g_Models.JumpToKey(TypeProp, false)){ if (g_Models.JumpToKey(PropId, false)){ prop_any_create(client); } } if(StrEqual(TypeProp, "physic")){ g_PhysicMenu.Display(client, MENU_TIME_FOREVER); } else if(StrEqual(TypeProp, "dynamic")){ g_DynamicMenu.Display(client, MENU_TIME_FOREVER); } else if(StrEqual(TypeProp, "npc")){ g_NpcMenu.Display(client, MENU_TIME_FOREVER); } int i_PropId = StringToInt(PropId)+1; // +1 cause of 'Delete Prop' in the menu int pageMenu = RoundToFloor(float(i_PropId)/7); // We get the quotient of the division for(int i = 1; i <= pageMenu; i++){ // We change the menu page until we are back where we were FakeClientCommandEx(client, "menuselect 9"); } } } bool TraceEntityFilter_FilterCaller(int entity, int contentsMask, int client) { return entity != client; } void prop_any_create(int client) { char sModelName[64]; g_Models.GetString("name", sModelName, sizeof(sModelName)); // Name of the model char sModelPath[128]; g_Models.GetString("model", sModelPath, sizeof(sModelPath)); // Path of the model int z_Offset = g_Models.GetNum("z_offset",0); // if "z_offset" is not set, then it's 0 char sModelHealth[11]; char sModelExplodeDamage[11]; char sModelExplodeRadius[11]; int iModelExplode = g_Models.GetNum("explode",0); // if "explode" is not set, then it's 0 g_Models.GetString("health", sModelHealth, sizeof(sModelHealth),"0"); // if "health" is not set, then it's 0 g_Models.GetString("explodedamage", sModelExplodeDamage, sizeof(sModelExplodeDamage),"1"); g_Models.GetString("exploderadius", sModelExplodeRadius, sizeof(sModelExplodeRadius),"1"); if(g_Models.JumpToKey("precache", false)){ // Precache each model used by the prop for(int i = 0; i < 100000; i++){ char sIndex[11]; IntToString(i,sIndex, sizeof(sIndex)); // Index i of the model if (!(g_Models.JumpToKey(sIndex, false))) // if the key doesnt exist break; // we stop the loop char sModelPrecache[128]; g_Models.GetString(NULL_STRING, sModelPrecache, sizeof(sModelPrecache)); PrecacheModel(sModelPrecache,true); g_Models.GoBack(); } g_Models.GoBack(); // Back to the index of the prop } else{ // If "precache" doesnt exist, we precache only the model we spawn PrecacheModel(sModelPath,true); } g_Models.GoBack(); // Back to the type of prop (physic, dynamic, npc) char sPropType[32]; g_Models.GetSectionName(sPropType, sizeof(sPropType)); // physic, dynamic, npc int prop; if(StrEqual(sPropType,"physic")){ prop = CreateEntityByName("prop_physics_override"); } else if(StrEqual(sPropType,"dynamic") || StrEqual(sPropType,"npc")){ prop = CreateEntityByName("prop_dynamic_override"); } g_Models.Rewind(); // Back to root node DispatchKeyValue(prop, "model", sModelPath); if (!StrEqual(sModelHealth,"0")) { DispatchKeyValue(prop, "health", sModelHealth); } if (iModelExplode != 0) { DispatchKeyValue(prop, "explodedamage", sModelExplodeDamage); DispatchKeyValue(prop, "exploderadius", sModelExplodeRadius); } float VecOrigin[3]; float VecAngles[3]; float normal[3]; GetClientEyePosition(client, VecOrigin); GetClientEyeAngles(client, VecAngles); TR_TraceRayFilter(VecOrigin, VecAngles, MASK_SOLID, RayType_Infinite, TraceEntityFilter_FilterCaller, client); TR_GetEndPosition(VecOrigin); DispatchKeyValue(prop, "StartDisabled", "false"); DispatchKeyValue(prop, "Solid", "6"); SetEntProp(prop, Prop_Data, "m_CollisionGroup", 5); if(StrEqual(sPropType,"physic")){ VecAngles[0] = 0.0; VecAngles[2] = 0.0; VecOrigin[2] = VecOrigin[2] + z_Offset; SetEntityMoveType(prop, MOVETYPE_VPHYSICS); TeleportEntity(prop, VecOrigin, VecAngles, NULL_VECTOR); } else if(StrEqual(sPropType,"dynamic") || StrEqual(sPropType,"npc")){ TR_GetPlaneNormal(INVALID_HANDLE, normal); GetVectorAngles(normal, normal); normal[0] += 90.0; TeleportEntity(prop, VecOrigin, normal, NULL_VECTOR); AcceptEntityInput(prop, "TurnOn", prop, prop, 0); } DispatchSpawn(prop); AcceptEntityInput(prop, "TurnOn", prop, prop, 0); AcceptEntityInput(prop, "EnableCollision"); ShowActivity2(client, "\x01[SM] \x04", "\x01Spawned \x04%s\x01.", sModelName); LogAction(client, -1, "\"%L\" Spawned \"%s\".", client, sModelName); }