mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-07 04:53:20 +00:00
Update
This commit is contained in:
parent
44733c3b14
commit
a97e151816
14 changed files with 5830 additions and 843 deletions
145
scripting/include/hats/props/base.sp
Normal file
145
scripting/include/hats/props/base.sp
Normal file
|
@ -0,0 +1,145 @@
|
|||
char g_pendingSaveName[64];
|
||||
int g_pendingSaveClient;
|
||||
|
||||
/* Wish to preface this file:
|
||||
* It's kinda messy. The main structs are:
|
||||
* - ItemData
|
||||
* - CategoryData
|
||||
|
||||
The rest are kinda necessary, for sorting reasons (SearchData, RecentEntry).
|
||||
|
||||
*/
|
||||
enum struct PlayerPropData {
|
||||
ArrayList listBuffer;
|
||||
bool clearListBuffer;
|
||||
int lastCategoryIndex;
|
||||
int lastItemIndex;
|
||||
int lastShowedHint;
|
||||
char classnameOverride[32];
|
||||
|
||||
bool isSearchActive;
|
||||
ArrayList markedProps;
|
||||
|
||||
// Called on PlayerDisconnect
|
||||
void Reset() {
|
||||
if(this.listBuffer != null) delete this.listBuffer;
|
||||
if(this.markedProps != null) delete this.markedProps;
|
||||
this.isSearchActive = false;
|
||||
this.clearListBuffer = false;
|
||||
this.lastCategoryIndex = 0;
|
||||
this.lastItemIndex = 0;
|
||||
this.lastShowedHint = 0;
|
||||
this.classnameOverride[0] = '\0';
|
||||
}
|
||||
|
||||
// Sets the list buffer
|
||||
void SetList(ArrayList list, bool cleanupAfterUse = false) {
|
||||
this.listBuffer = list;
|
||||
this.clearListBuffer = cleanupAfterUse;
|
||||
}
|
||||
|
||||
// Is currently only called on item handler cancel (to clear search/recents buffer)
|
||||
void CleanupBuffer() {
|
||||
if(this.listBuffer != null && this.clearListBuffer) {
|
||||
delete this.listBuffer;
|
||||
this.clearListBuffer = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
PlayerPropData g_PropData[MAXPLAYERS+1];
|
||||
|
||||
enum struct CategoryData {
|
||||
// The display name of category
|
||||
char name[64];
|
||||
// If set, overwrites the classname it is spawned as
|
||||
char classnameOverride[32];
|
||||
bool hasItems; // true: items is ArrayList<ItemData>, false: items is ArrayList<CategoryData>
|
||||
ArrayList items;
|
||||
}
|
||||
enum struct ItemData {
|
||||
char model[128];
|
||||
char name[64];
|
||||
|
||||
void FromSearchData(SearchData search) {
|
||||
strcopy(this.model, sizeof(this.model), search.model);
|
||||
strcopy(this.name, sizeof(this.name), search.name);
|
||||
}
|
||||
}
|
||||
enum struct SearchData {
|
||||
char model[128];
|
||||
char name[64];
|
||||
int index;
|
||||
|
||||
void FromItemData(ItemData item) {
|
||||
strcopy(this.model, sizeof(this.model), item.model);
|
||||
strcopy(this.name, sizeof(this.name), item.name);
|
||||
}
|
||||
}
|
||||
enum struct SaveData {
|
||||
char model[128];
|
||||
buildType type;
|
||||
float origin[3];
|
||||
float angles[3];
|
||||
int color[4];
|
||||
|
||||
void FromEntity(int entity) {
|
||||
// Use this.model as a buffer:
|
||||
GetEntityClassname(entity, this.model, sizeof(this.model));
|
||||
if(StrEqual(this.model, "prop_physics")) this.type = Build_Physics;
|
||||
else if(StrEqual(this.model, "prop_dynamic")) {
|
||||
if(GetEntProp(entity, Prop_Send, "m_nSolidType") == 0) {
|
||||
this.type = Build_NonSolid;
|
||||
} else {
|
||||
this.type = Build_Solid;
|
||||
}
|
||||
}
|
||||
|
||||
GetEntPropString(entity, Prop_Data, "m_ModelName", this.model, sizeof(this.model));
|
||||
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", this.origin);
|
||||
GetEntPropVector(entity, Prop_Send, "m_angRotation", this.angles);
|
||||
GetEntityRenderColor(entity, this.color[0],this.color[1],this.color[2],this.color[3]);
|
||||
}
|
||||
|
||||
void Serialize(char[] output, int maxlen) {
|
||||
Format(
|
||||
output, maxlen, "%s,%d,%.2f,%.2f,%.2f,%.2f,%.2f,%.2f,%d,%d,%d,%d",
|
||||
this.model, this.type, this.origin[0], this.origin[1], this.origin[2],
|
||||
this.angles[0], this.angles[1], this.angles[2],
|
||||
this.color[0], this.color[1], this.color[2], this.color[3]
|
||||
);
|
||||
}
|
||||
|
||||
void Deserialize(const char[] input) {
|
||||
char buffer[16];
|
||||
int index = SplitString(input, ",", this.model, sizeof(this.model));
|
||||
index += SplitString(input[index], ",", buffer, sizeof(buffer));
|
||||
this.type = view_as<buildType>(StringToInt(buffer));
|
||||
for(int i = 0; i < 3; i++) {
|
||||
index += SplitString(input[index], ",", buffer, sizeof(buffer));
|
||||
this.origin[i] = StringToFloat(buffer);
|
||||
}
|
||||
for(int i = 0; i < 3; i++) {
|
||||
index += SplitString(input[index], ",", buffer, sizeof(buffer));
|
||||
this.angles[i] = StringToFloat(buffer);
|
||||
}
|
||||
for(int i = 0; i < 4; i++) {
|
||||
index += SplitString(input[index], ",", buffer, sizeof(buffer));
|
||||
this.color[i] = StringToInt(buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
enum struct RecentEntry {
|
||||
char name[64];
|
||||
int count;
|
||||
}
|
||||
|
||||
ArrayList g_categories; // ArrayList<CategoryData>
|
||||
ArrayList g_spawnedItems; // ArrayList(block=2)<entRef, [creator]>
|
||||
ArrayList g_savedItems; // ArrayList<entRef>
|
||||
StringMap g_recentItems; // Key: model[128], value: RecentEntry
|
||||
|
||||
#include <hats/props/methods.sp>
|
||||
#include <hats/props/cmd.sp>
|
||||
#include <hats/props/menu_handlers.sp>
|
||||
#include <hats/props/menu_methods.sp>
|
63
scripting/include/hats/props/cmd.sp
Normal file
63
scripting/include/hats/props/cmd.sp
Normal file
|
@ -0,0 +1,63 @@
|
|||
Action Command_Props(int client, int args) {
|
||||
char arg[32];
|
||||
GetCmdArg(1, arg, sizeof(arg));
|
||||
if(args == 0 || StrEqual(arg, "help")) {
|
||||
PrintToChat(client, "See console for available sub-commands");
|
||||
PrintToConsole(client, "help - this");
|
||||
PrintToConsole(client, "search <search query>");
|
||||
PrintToConsole(client, "edit <last/#index>");
|
||||
PrintToConsole(client, "del <last/#index/tool>");
|
||||
PrintToConsole(client, "add <cursor/tool>");
|
||||
PrintToConsole(client, "controls - list all the controls");
|
||||
} else if(StrEqual(arg, "search")) {
|
||||
if(args == 1) {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Enter your search query:");
|
||||
g_PropData[client].isSearchActive = true;
|
||||
} else {
|
||||
char query[32];
|
||||
GetCmdArg(2, query, sizeof(query));
|
||||
DoSearch(client, query);
|
||||
}
|
||||
} else if(StrEqual(arg, "edit")) {
|
||||
char arg2[32];
|
||||
GetCmdArg(2, arg2, sizeof(arg2));
|
||||
int index;
|
||||
if(StrEqual(arg2, "last")) {
|
||||
// Get last one
|
||||
index = GetSpawnedIndex(client, -1);
|
||||
} else {
|
||||
index = StringToInt(arg2);
|
||||
}
|
||||
if(index >= 0 && index < g_spawnedItems.Length) {
|
||||
int entity = EntRefToEntIndex(g_spawnedItems.Get(index));
|
||||
Editor[client].Import(entity);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Editing entity \x05%d", entity);
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Invalid index, out of bounds. Enter a value between [0, %d]", g_spawnedItems.Length - 1);
|
||||
}
|
||||
} else if(StrEqual(arg, "del")) {
|
||||
char arg2[32];
|
||||
GetCmdArg(2, arg2, sizeof(arg2));
|
||||
int index;
|
||||
if(StrEqual(arg2, "last")) {
|
||||
// Get last one
|
||||
index = GetSpawnedIndex(client, -1);
|
||||
} else {
|
||||
index = StringToInt(arg2);
|
||||
}
|
||||
|
||||
if(index >= 0 && index < g_spawnedItems.Length) {
|
||||
int entity = EntRefToEntIndex(g_spawnedItems.Get(index));
|
||||
if(entity > 0 && IsValidEntity(entity)) {
|
||||
RemoveEntity(entity);
|
||||
}
|
||||
g_spawnedItems.Erase(index);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Deleted entity \x05%d", entity);
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Invalid index, out of bounds. Enter a value between [0, %d]", g_spawnedItems.Length - 1);
|
||||
}
|
||||
}else {
|
||||
PrintToChat(client, "\x05Not implemented");
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
239
scripting/include/hats/props/menu_handlers.sp
Normal file
239
scripting/include/hats/props/menu_handlers.sp
Normal file
|
@ -0,0 +1,239 @@
|
|||
TopMenuObject g_propSpawnerCategory;
|
||||
public void OnAdminMenuReady(Handle topMenuHandle) {
|
||||
TopMenu topMenu = TopMenu.FromHandle(topMenuHandle);
|
||||
if(g_topMenu != topMenuHandle) {
|
||||
g_propSpawnerCategory = topMenu.AddCategory("hats_editor", Category_Handler);
|
||||
if(g_propSpawnerCategory != INVALID_TOPMENUOBJECT) {
|
||||
topMenu.AddItem("editor_spawn", AdminMenu_Spawn, g_propSpawnerCategory, "sm_prop");
|
||||
topMenu.AddItem("editor_edit", AdminMenu_Edit, g_propSpawnerCategory, "sm_prop");
|
||||
topMenu.AddItem("editor_delete", AdminMenu_Delete, g_propSpawnerCategory, "sm_prop");
|
||||
topMenu.AddItem("editor_saveload", AdminMenu_SaveLoad, g_propSpawnerCategory, "sm_prop");
|
||||
}
|
||||
g_topMenu = topMenu;
|
||||
}
|
||||
}
|
||||
|
||||
/////////////
|
||||
// HANDLERS
|
||||
/////////////
|
||||
void Category_Handler(TopMenu topmenu, TopMenuAction action, TopMenuObject topobj_id, int param, char[] buffer, int maxlength) {
|
||||
if(action == TopMenuAction_DisplayTitle) {
|
||||
Format(buffer, maxlength, "Select a task:");
|
||||
} else if(action == TopMenuAction_DisplayOption) {
|
||||
Format(buffer, maxlength, "Spawn Props (Beta)");
|
||||
}
|
||||
}
|
||||
|
||||
void AdminMenu_Spawn(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) {
|
||||
if(action == TopMenuAction_DisplayOption) {
|
||||
Format(buffer, maxlength, "Spawn Props");
|
||||
} else if(action == TopMenuAction_SelectOption) {
|
||||
ConVar cheats = FindConVar("sm_cheats");
|
||||
if(cheats != null && !cheats.BoolValue) {
|
||||
CReplyToCommand(param, "\x04[Editor] \x01Set \x05sm_cheats\x01 to \x051\x01 to use the prop spawner");
|
||||
return;
|
||||
}
|
||||
ShowSpawnRoot(param);
|
||||
}
|
||||
}
|
||||
|
||||
int Spawn_RootHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char info[2];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
switch(info[0]) {
|
||||
case 'f': Spawn_ShowFavorites(client);
|
||||
case 'r': Spawn_ShowRecents(client);
|
||||
case 's': Spawn_ShowSearch(client);
|
||||
case 'n': ShowCategoryList(client);
|
||||
}
|
||||
// TODO: handle back (to top menu)
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
|
||||
}
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
void AdminMenu_Edit(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) {
|
||||
if(action == TopMenuAction_DisplayOption) {
|
||||
Format(buffer, maxlength, "Edit Props");
|
||||
} else if(action == TopMenuAction_SelectOption) {
|
||||
ShowEditList(param);
|
||||
}
|
||||
}
|
||||
void AdminMenu_Delete(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) {
|
||||
if(action == TopMenuAction_DisplayOption) {
|
||||
Format(buffer, maxlength, "Delete Props");
|
||||
} else if(action == TopMenuAction_SelectOption) {
|
||||
ShowDeleteList(param);
|
||||
}
|
||||
}
|
||||
|
||||
void AdminMenu_SaveLoad(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) {
|
||||
if(action == TopMenuAction_DisplayOption) {
|
||||
Format(buffer, maxlength, "Save / Load");
|
||||
} else if(action == TopMenuAction_SelectOption) {
|
||||
Menu menu = new Menu(SaveLoadHandler);
|
||||
menu.SetTitle("Save / Load");
|
||||
char name[64];
|
||||
menu.AddItem("", "[New Save]");
|
||||
ArrayList saves = LoadSaves();
|
||||
if(saves != null) {
|
||||
for(int i = 0; i < saves.Length; i++) {
|
||||
saves.GetString(i, name, sizeof(name));
|
||||
menu.AddItem(name, name);
|
||||
}
|
||||
delete saves;
|
||||
}
|
||||
menu.ExitBackButton = true;
|
||||
menu.ExitButton = true;
|
||||
menu.Display(param, MENU_TIME_FOREVER);
|
||||
}
|
||||
}
|
||||
|
||||
int SpawnCategoryHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char info[8];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
int index = StringToInt(info);
|
||||
PrintToServer("Item in category list selected: #%d", index);
|
||||
// Use g_categories, but if this is nested, then when a nested is selected, we need to use that list
|
||||
ShowItemMenu(client, index);
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
ShowSpawnRoot(client);
|
||||
}
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SaveLoadHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char saveName[64];
|
||||
menu.GetItem(param2, saveName, sizeof(saveName));
|
||||
if(saveName[0] == '\0') {
|
||||
// Save new
|
||||
FormatTime(saveName, sizeof(saveName), "%Y-%m-%d_%H-%I-%M");
|
||||
if(CreateSave(saveName)) {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Saved as \x05%s/%s.txt", g_currentMap, saveName);
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Error creating save file");
|
||||
}
|
||||
} else if(LoadSave(saveName, true)) {
|
||||
strcopy(g_pendingSaveName, sizeof(g_pendingSaveName), saveName);
|
||||
g_pendingSaveClient = client;
|
||||
PrintToChat(client, "\x04[Editor]\x01 Previewing save \x05%s", saveName);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Press \x05Shift + Middle Mouse\x01 to spawn, \x05Middle Mouse\x01 to cancel");
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Error loading save file");
|
||||
}
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
|
||||
}
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
int DeleteHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char info[8];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
int index = StringToInt(info);
|
||||
if(index == -1) {
|
||||
// Delete all (everyone)
|
||||
int count = DeleteAll();
|
||||
PrintToChat(client, "\x04[Editor]\x01 Deleted \x05%d\x01 items", count);
|
||||
ShowDeleteList(client);
|
||||
} else if(index == -2) {
|
||||
// Delete all (mine only)
|
||||
int count = DeleteAll(client);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Deleted \x05%d\x01 items", count);
|
||||
ShowDeleteList(client);
|
||||
} else if(index == -3) {
|
||||
if(g_PropData[client].markedProps != null) {
|
||||
EndDeleteTool(client, false);
|
||||
} else {
|
||||
g_PropData[client].markedProps = new ArrayList();
|
||||
PrintToChat(client, "\x04[Editor]\x01 Delete tool active. Press \x05E (Interact)\x01 to mark props.");
|
||||
}
|
||||
ShowDeleteList(client);
|
||||
} else {
|
||||
int ref = g_spawnedItems.Get(index);
|
||||
// TODO: add delete confirm
|
||||
if(IsValidEntity(ref)) {
|
||||
RemoveEntity(ref);
|
||||
}
|
||||
g_spawnedItems.Erase(index);
|
||||
if(index > 0) {
|
||||
index--;
|
||||
}
|
||||
ShowDeleteList(client, index);
|
||||
}
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
|
||||
}
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SpawnItemHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char info[132];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
char index[4];
|
||||
char model[128];
|
||||
int nameIndex = SplitString(info, "|", index, sizeof(index));
|
||||
nameIndex += SplitString(info[nameIndex], "|", model, sizeof(model));
|
||||
g_PropData[client].lastItemIndex = StringToInt(index);
|
||||
if(Editor[client].PreviewModel(model, g_PropData[client].classnameOverride)) {
|
||||
Editor[client].SetData(info[nameIndex]);
|
||||
PrintHintText(client, "%s\n%s", info[nameIndex], model);
|
||||
ShowHint(client);
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Error spawning preview \x01(%s)", model);
|
||||
}
|
||||
|
||||
ShowItemMenuAny(client, null); // Use last menu
|
||||
// ShowItemMenu(client, g_PropData[client].lastCategoryIndex);
|
||||
} else if(action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
ShowCategoryList(client, g_PropData[client].listBuffer);
|
||||
}
|
||||
g_PropData[client].CleanupBuffer();
|
||||
|
||||
} else if (action == MenuAction_End) {
|
||||
delete menu;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int EditHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
char info[8];
|
||||
menu.GetItem(param2, info, sizeof(info));
|
||||
int index = StringToInt(info);
|
||||
int ref = g_spawnedItems.Get(index);
|
||||
int entity = EntRefToEntIndex(ref);
|
||||
if(entity > 0) {
|
||||
Editor[client].Import(entity, false);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Editing entity \x05%d", entity);
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Entity disappeared.");
|
||||
g_spawnedItems.Erase(index);
|
||||
index--;
|
||||
}
|
||||
ShowEditList(client, index);
|
||||
} else if (action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
|
||||
}
|
||||
} else if (action == MenuAction_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
174
scripting/include/hats/props/menu_methods.sp
Normal file
174
scripting/include/hats/props/menu_methods.sp
Normal file
|
@ -0,0 +1,174 @@
|
|||
/////////////
|
||||
// METHODS
|
||||
/////////////
|
||||
void ShowSpawnRoot(int client) {
|
||||
Menu menu = new Menu(Spawn_RootHandler);
|
||||
menu.SetTitle("Choose list:");
|
||||
menu.AddItem("f", "Favorites (WIP)");
|
||||
menu.AddItem("r", "Recents");
|
||||
menu.AddItem("s", "Search");
|
||||
menu.AddItem("n", "Prop List");
|
||||
menu.ExitBackButton = true;
|
||||
menu.ExitButton = true;
|
||||
menu.Display(client, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
||||
void Spawn_ShowFavorites(int client) {
|
||||
PrintToChat(client, "In development");
|
||||
return;
|
||||
// Menu menu = new Menu(SpawnItemHandler);
|
||||
// char model[128];
|
||||
// for(int i = 0; i <= g_spawnedItems.Length; i++) {
|
||||
// int ref = g_spawnedItems.Get(i);
|
||||
// if(IsValidEntity(ref)) {
|
||||
// GetEntPropString(ref, Prop_Data, "m_ModelName", model, sizeof(model));
|
||||
// menu.AddItem(model, model);
|
||||
// }
|
||||
// }
|
||||
// menu.ExitBackButton = true;
|
||||
// menu.ExitButton = true;
|
||||
// menu.Display(client, MENU_TIME_FOREVER);
|
||||
}
|
||||
void Spawn_ShowRecents(int client) {
|
||||
CReplyToCommand(client, "\x04[Editor] \x01Disabled due to crash issues :D");
|
||||
return;
|
||||
if(g_recentItems == null) LoadRecents();
|
||||
ArrayList items = GetRecentsItemList();
|
||||
if(items.Length == 0) {
|
||||
CReplyToCommand(client, "\x04[Editor] \x01No recent props spawned.");
|
||||
return;
|
||||
}
|
||||
ShowItemMenuAny(client, items, "Recents", true);
|
||||
}
|
||||
void Spawn_ShowSearch(int client) {
|
||||
g_PropData[client].isSearchActive = true;
|
||||
CReplyToCommand(client, "\x04[Editor] \x01Please enter search query in chat:");
|
||||
}
|
||||
void ShowDeleteList(int client, int index = -3) {
|
||||
Menu menu = new Menu(DeleteHandler);
|
||||
menu.SetTitle("Delete Props");
|
||||
|
||||
menu.AddItem("-1", "Delete All");
|
||||
menu.AddItem("-2", "Delete All (Mine Only)");
|
||||
menu.AddItem("-3", "Delete Tool");
|
||||
// menu.AddItem("-4", "Delete Last Save");
|
||||
char info[8];
|
||||
char buffer[128];
|
||||
for(int i = 0; i < g_spawnedItems.Length; i++) {
|
||||
int ref = GetSpawnedItem(i);
|
||||
if(ref == -1) continue;
|
||||
IntToString(i, info, sizeof(info));
|
||||
GetEntPropString(ref, Prop_Data, "m_ModelName", buffer, sizeof(buffer));
|
||||
index = FindCharInString(buffer, '/', true);
|
||||
if(index != -1)
|
||||
menu.AddItem(info, buffer[index + 1]);
|
||||
}
|
||||
|
||||
menu.ExitBackButton = true;
|
||||
menu.ExitButton = true;
|
||||
// Add +3 to the index for the 3 "Delete ..." buttons
|
||||
// TODO: restore the delete index issue, use /7*7
|
||||
menu.DisplayAt(client, 0, MENU_TIME_FOREVER);
|
||||
}
|
||||
void ShowEditList(int client, int index = 0) {
|
||||
Menu menu = new Menu(EditHandler);
|
||||
menu.SetTitle("Edit Prop");
|
||||
|
||||
char info[8];
|
||||
char buffer[32];
|
||||
for(int i = 0; i < g_spawnedItems.Length; i++) {
|
||||
int ref = GetSpawnedItem(i);
|
||||
if(ref == -1) continue;
|
||||
IntToString(i, info, sizeof(info));
|
||||
GetEntPropString(ref, Prop_Data, "m_ModelName", buffer, sizeof(buffer));
|
||||
index = FindCharInString(buffer, '/', true);
|
||||
if(index != -1)
|
||||
menu.AddItem(info, buffer[index + 1]);
|
||||
}
|
||||
|
||||
menu.ExitBackButton = true;
|
||||
menu.ExitButton = true;
|
||||
// Add +2 to the index for the two "Delete ..." buttons
|
||||
menu.DisplayAt(client, index, MENU_TIME_FOREVER);
|
||||
}
|
||||
void ShowCategoryList(int client, ArrayList categoryList = null) {
|
||||
LoadCategories();
|
||||
Menu menu = new Menu(SpawnCategoryHandler);
|
||||
menu.SetTitle("Choose a category");
|
||||
CategoryData cat;
|
||||
char info[4];
|
||||
// No category list provided, use the global one.
|
||||
PrintToServer("ShowCategoryList (root = %b)", categoryList == null);
|
||||
if(categoryList == null) {
|
||||
categoryList = g_categories;
|
||||
}
|
||||
g_PropData[client].SetList(categoryList, false);
|
||||
for(int i = 0; i < categoryList.Length; i++) {
|
||||
categoryList.GetArray(i, cat);
|
||||
Format(info, sizeof(info), "%d", i);
|
||||
// TODO: maybe add > folder indicator
|
||||
menu.AddItem(info, cat.name);
|
||||
}
|
||||
menu.ExitBackButton = true;
|
||||
menu.ExitButton = true;
|
||||
// Round to page instead of index (int division)
|
||||
int index = g_PropData[client].lastCategoryIndex / 7 * 7;
|
||||
menu.DisplayAt(client, index, MENU_TIME_FOREVER);
|
||||
}
|
||||
void ShowItemMenuAny(int client, ArrayList items, const char[] title = "", bool clearArray = false, const char[] classnameOverride = "") {
|
||||
if(items == null) {
|
||||
items = g_PropData[client].listBuffer;
|
||||
if(items == null) {
|
||||
LogError("Items is null and listBuffer is null as well");
|
||||
}
|
||||
} else {
|
||||
g_PropData[client].SetList(items, clearArray);
|
||||
g_PropData[client].lastItemIndex = 0;
|
||||
strcopy(g_PropData[client].classnameOverride, 32, classnameOverride);
|
||||
}
|
||||
if(items.Length == 0) {
|
||||
PrintToChat(client, "\x04[Editor]\x01 No items to show.");
|
||||
return;
|
||||
}
|
||||
Menu itemMenu = new Menu(SpawnItemHandler);
|
||||
if(title[0] != '\0')
|
||||
itemMenu.SetTitle(title);
|
||||
ItemData item;
|
||||
char info[128+64+8];
|
||||
for(int i = 0; i < items.Length; i++) {
|
||||
items.GetArray(i, item);
|
||||
// Sadly need to duplicate item.name.
|
||||
Format(info, sizeof(info), "%d|%s|%s", i, item.model, item.name);
|
||||
itemMenu.AddItem(info, item.name);
|
||||
}
|
||||
itemMenu.ExitBackButton = true;
|
||||
itemMenu.ExitButton = true;
|
||||
// We don't want to start at the index but the page of the index
|
||||
int index = (g_PropData[client].lastItemIndex / 7) * 7;
|
||||
itemMenu.DisplayAt(client, index, MENU_TIME_FOREVER);
|
||||
}
|
||||
|
||||
// Calls ShowItemMenuAny with the correct category automatically
|
||||
bool ShowItemMenu(int client, int index) {
|
||||
if(g_PropData[client].lastCategoryIndex != index) {
|
||||
g_PropData[client].lastCategoryIndex = index;
|
||||
g_PropData[client].lastItemIndex = 0; //Reset
|
||||
}
|
||||
CategoryData category;
|
||||
// Use the list in the buffer
|
||||
g_PropData[client].listBuffer.GetArray(index, category);
|
||||
if(category.items == null) {
|
||||
LogError("Category %s has null items array (index=%d)", category.name, index);
|
||||
} else if(category.hasItems) {
|
||||
PrintToServer("Selected category has item entries, showing item menu");
|
||||
ShowItemMenuAny(client, category.items, category.name, false, category.classnameOverride);
|
||||
} else {
|
||||
PrintToServer("Selected category has nested categories, showing");
|
||||
// Has nested categories
|
||||
// Reset the category index for nested
|
||||
g_PropData[client].lastCategoryIndex = 0;
|
||||
g_PropData[client].SetList(category.items);
|
||||
ShowCategoryList(client, g_PropData[client].listBuffer);
|
||||
}
|
||||
return true;
|
||||
}
|
479
scripting/include/hats/props/methods.sp
Normal file
479
scripting/include/hats/props/methods.sp
Normal file
|
@ -0,0 +1,479 @@
|
|||
|
||||
ArrayList LoadSaves() {
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/saves/%s", g_currentMap);
|
||||
FileType fileType;
|
||||
DirectoryListing listing = OpenDirectory(path);
|
||||
if(listing == null) return null;
|
||||
char buffer[64];
|
||||
ArrayList saves = new ArrayList(ByteCountToCells(64));
|
||||
while(listing.GetNext(buffer, sizeof(buffer), fileType)) {
|
||||
if(buffer[0] == '.') continue;
|
||||
saves.PushString(buffer);
|
||||
}
|
||||
delete listing;
|
||||
return saves;
|
||||
}
|
||||
|
||||
ArrayList g_previewItems;
|
||||
|
||||
bool LoadSave(const char[] save, bool asPreview = false) {
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/saves/%s/%s", g_currentMap, save);
|
||||
// ArrayList savedItems = new ArrayList(sizeof(SaveData));
|
||||
File file = OpenFile(path, "r");
|
||||
if(file == null) return false;
|
||||
char buffer[256];
|
||||
if(asPreview) {
|
||||
// Kill any previous preview
|
||||
if(g_previewItems != null) ClearSavePreview();
|
||||
g_previewItems = new ArrayList();
|
||||
}
|
||||
SaveData data;
|
||||
while(file.ReadLine(buffer, sizeof(buffer))) {
|
||||
if(buffer[0] == '#') continue;
|
||||
data.Deserialize(buffer);
|
||||
int entity = -1;
|
||||
if(data.type == Build_Physics)
|
||||
entity = CreateEntityByName("prop_physics");
|
||||
else
|
||||
entity = CreateEntityByName("prop_dynamic");
|
||||
if(entity == -1) continue;
|
||||
PrecacheModel(data.model);
|
||||
DispatchKeyValue(entity, "model", data.model);
|
||||
DispatchKeyValue(entity, "targetname", "saved_prop");
|
||||
if(asPreview) {
|
||||
DispatchKeyValue(entity, "rendermode", "1");
|
||||
DispatchKeyValue(entity, "solid", "0");
|
||||
} else {
|
||||
DispatchKeyValue(entity, "solid", data.type == Build_NonSolid ? "0" : "6");
|
||||
}
|
||||
TeleportEntity(entity, data.origin, data.angles, NULL_VECTOR);
|
||||
if(!DispatchSpawn(entity)) continue;
|
||||
int alpha = asPreview ? 200 : data.color[3];
|
||||
SetEntityRenderColor(entity, data.color[0], data.color[1], data.color[2], alpha);
|
||||
|
||||
if(asPreview)
|
||||
g_savedItems.Push(EntIndexToEntRef(entity));
|
||||
else
|
||||
AddSpawnedItem(entity);
|
||||
}
|
||||
delete file;
|
||||
if(asPreview) {
|
||||
delete g_previewItems;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClearSavePreview() {
|
||||
if(g_previewItems != null) {
|
||||
for(int i = 0; i < g_previewItems.Length; i++) {
|
||||
int ref = g_previewItems.Get(i);
|
||||
if(IsValidEntity(ref)) {
|
||||
RemoveEntity(ref);
|
||||
}
|
||||
}
|
||||
delete g_previewItems;
|
||||
}
|
||||
g_pendingSaveClient = 0;
|
||||
}
|
||||
|
||||
void AddSpawnedItem(int entity, int client = 0) {
|
||||
int index = g_spawnedItems.Push(EntIndexToEntRef(entity));
|
||||
if(client == 0)
|
||||
g_spawnedItems.Set(index, 0, 1);
|
||||
else
|
||||
g_spawnedItems.Set(index, GetClientUserId(client), 1);
|
||||
}
|
||||
|
||||
bool CreateSave(const char[] name) {
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/saves/%s", g_currentMap);
|
||||
CreateDirectory(path, 509);
|
||||
Format(path, sizeof(path), "%s/%s.txt", path, name);
|
||||
File file = OpenFile(path, "w");
|
||||
if(file == null) {
|
||||
PrintToServer("[Editor] Could not save: %s", path);
|
||||
return false;
|
||||
}
|
||||
char buffer[132];
|
||||
SaveData data;
|
||||
for(int i = 0; i < g_spawnedItems.Length; i++) {
|
||||
int ref = g_spawnedItems.Get(i);
|
||||
if(IsValidEntity(ref)) {
|
||||
data.FromEntity(ref);
|
||||
data.Serialize(buffer, sizeof(buffer));
|
||||
file.WriteLine("%s", buffer);
|
||||
}
|
||||
}
|
||||
file.Flush();
|
||||
delete file;
|
||||
return true;
|
||||
}
|
||||
|
||||
void UnloadSave() {
|
||||
if(g_savedItems != null) {
|
||||
delete g_savedItems;
|
||||
}
|
||||
}
|
||||
|
||||
public void LoadCategories() {
|
||||
if(g_categories != null) return;
|
||||
g_categories = new ArrayList(sizeof(CategoryData));
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/models");
|
||||
LoadFolder(g_categories, path);
|
||||
g_categories.SortCustom(SortCategories);
|
||||
}
|
||||
int SortCategories(int index1, int index2, ArrayList array, Handle hndl) {
|
||||
CategoryData cat1;
|
||||
array.GetArray(index1, cat1);
|
||||
CategoryData cat2;
|
||||
array.GetArray(index2, cat2);
|
||||
return strcmp(cat1.name, cat2.name);
|
||||
}
|
||||
public void UnloadCategories() {
|
||||
if(g_categories == null) return;
|
||||
_UnloadCategories(g_categories);
|
||||
delete g_categories;
|
||||
}
|
||||
void _UnloadCategories(ArrayList list) {
|
||||
CategoryData cat;
|
||||
for(int i = 0; i < list.Length; i++) {
|
||||
list.GetArray(i, cat);
|
||||
_UnloadCategory(cat);
|
||||
}
|
||||
}
|
||||
void _UnloadCategory(CategoryData cat) {
|
||||
// Is a sub-category:
|
||||
if(!cat.hasItems) {
|
||||
_UnloadCategories(cat.items);
|
||||
}
|
||||
delete cat.items;
|
||||
}
|
||||
|
||||
void LoadFolder(ArrayList parent, const char[] rootPath) {
|
||||
char buffer[PLATFORM_MAX_PATH];
|
||||
FileType fileType;
|
||||
DirectoryListing listing = OpenDirectory(rootPath);
|
||||
if(listing == null) {
|
||||
LogError("Cannot open \"%s\"", rootPath);
|
||||
}
|
||||
while(listing.GetNext(buffer, sizeof(buffer), fileType)) {
|
||||
if(fileType == FileType_Directory) {
|
||||
// TODO: support subcategory
|
||||
if(buffer[0] == '.') continue;
|
||||
CategoryData data;
|
||||
Format(data.name, sizeof(data.name), "%s>>", buffer);
|
||||
data.items = new ArrayList(sizeof(CategoryData));
|
||||
|
||||
Format(buffer, sizeof(buffer), "%s/%s", rootPath, buffer);
|
||||
LoadFolder(data.items, buffer);
|
||||
parent.PushArray(data);
|
||||
} else if(fileType == FileType_File) {
|
||||
Format(buffer, sizeof(buffer), "%s/%s", rootPath, buffer);
|
||||
LoadProps(parent, buffer);
|
||||
}
|
||||
}
|
||||
delete listing;
|
||||
}
|
||||
|
||||
void LoadProps(ArrayList parent, const char[] filePath) {
|
||||
File file = OpenFile(filePath, "r");
|
||||
if(file == null) {
|
||||
PrintToServer("[Props] Cannot open file \"%s\"", filePath);
|
||||
return;
|
||||
}
|
||||
CategoryData category;
|
||||
category.items = new ArrayList(sizeof(ItemData));
|
||||
category.hasItems = true;
|
||||
char buffer[128];
|
||||
if(!file.ReadLine(buffer, sizeof(buffer))) {
|
||||
delete file;
|
||||
return;
|
||||
}
|
||||
ReplaceString(buffer, sizeof(buffer), "\n", "");
|
||||
ReplaceString(buffer, sizeof(buffer), "\r", "");
|
||||
Format(category.name, sizeof(category.name), "%s>", buffer);
|
||||
while(file.ReadLine(buffer, sizeof(buffer))) {
|
||||
if(buffer[0] == '#') continue;
|
||||
ReplaceString(buffer, sizeof(buffer), "\n", "");
|
||||
ReplaceString(buffer, sizeof(buffer), "\r", "");
|
||||
ItemData item;
|
||||
int index = SplitString(buffer, ":", item.model, sizeof(item.model));
|
||||
if(index == -1) {
|
||||
index = SplitString(buffer, " ", item.model, sizeof(item.model));
|
||||
if(index == -1) {
|
||||
// No name provided, use the model's filename
|
||||
index = FindCharInString(buffer, '/', true);
|
||||
strcopy(item.name, sizeof(item.name), item.model[index + 1]);
|
||||
} else {
|
||||
strcopy(item.name, sizeof(item.name), buffer[index]);
|
||||
}
|
||||
category.items.PushArray(item);
|
||||
} else if(StrEqual(item.model, "Classname")) {
|
||||
strcopy(category.classnameOverride, sizeof(category.classnameOverride), buffer[index]);
|
||||
} else if(StrEqual(item.model, "Type")) {
|
||||
Format(category.classnameOverride, sizeof(category.classnameOverride), "_%s", buffer[index]);
|
||||
}
|
||||
}
|
||||
parent.PushArray(category);
|
||||
delete file;
|
||||
}
|
||||
bool recentsChanged = false;
|
||||
bool SaveRecents() {
|
||||
if(!recentsChanged) return true; // Nothing to do, nothing changed
|
||||
if(g_recentItems == null) return false;
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/recents_cache.csv");
|
||||
File file = OpenFile(path, "w");
|
||||
if(file == null) {
|
||||
PrintToServer("[Editor] Could not write to %s", path);
|
||||
return false;
|
||||
}
|
||||
StringMapSnapshot snapshot = g_recentItems.Snapshot();
|
||||
char model[128];
|
||||
RecentEntry entry;
|
||||
for(int i = 0; i < snapshot.Length; i++) {
|
||||
snapshot.GetKey(i, model, sizeof(model));
|
||||
g_recentItems.GetArray(model, entry, sizeof(entry));
|
||||
file.WriteLine("%s,%s,%d", model, entry.name, entry.count);
|
||||
}
|
||||
file.Flush();
|
||||
delete file;
|
||||
delete snapshot;
|
||||
recentsChanged = false;
|
||||
return true;
|
||||
}
|
||||
bool LoadRecents() {
|
||||
return false;
|
||||
if(g_recentItems != null) delete g_recentItems;
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/recents_cache.csv");
|
||||
File file = OpenFile(path, "r");
|
||||
if(file == null) return false;
|
||||
g_recentItems = new StringMap();
|
||||
char buffer[128+64+16];
|
||||
char model[128];
|
||||
RecentEntry entry;
|
||||
while(file.ReadLine(buffer, sizeof(buffer))) {
|
||||
int index = SplitString(buffer, ",", model, sizeof(model));
|
||||
index += SplitString(buffer[index], ",", entry.name, sizeof(entry.name));
|
||||
entry.count = StringToInt(buffer[index]);
|
||||
g_recentItems.SetArray(model, entry, sizeof(entry));
|
||||
}
|
||||
delete file;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Returns an ArrayList<ItemData> of all the recents
|
||||
ArrayList GetRecentsItemList() {
|
||||
ArrayList items = new ArrayList(sizeof(ItemData));
|
||||
StringMapSnapshot snapshot = g_recentItems.Snapshot();
|
||||
char model[128];
|
||||
RecentEntry entry;
|
||||
ItemData item;
|
||||
for(int i = 0; i < snapshot.Length; i++) {
|
||||
snapshot.GetKey(i, model, sizeof(model));
|
||||
g_recentItems.GetArray(model, entry, sizeof(entry));
|
||||
strcopy(item.model, sizeof(item.model), model);
|
||||
strcopy(item.name, sizeof(item.name), entry.name);
|
||||
}
|
||||
// This is pretty expensive in terms of allocations but shrug
|
||||
items.SortCustom(SortRecents);
|
||||
delete snapshot;
|
||||
return items;
|
||||
}
|
||||
|
||||
int SortRecents(int index1, int index2, ArrayList array, Handle handle) {
|
||||
ItemData data1;
|
||||
array.GetArray(index1, data1);
|
||||
ItemData data2;
|
||||
array.GetArray(index2, data2);
|
||||
|
||||
int count1, count2;
|
||||
RecentEntry entry;
|
||||
if(g_recentItems.GetArray(data1.model, entry, sizeof(entry))) return 0; //skip if somehow no entry
|
||||
count1 = entry.count;
|
||||
if(g_recentItems.GetArray(data2.model, entry, sizeof(entry))) return 0; //skip if somehow no entry
|
||||
count2 = entry.count;
|
||||
return count2 - count1; // desc
|
||||
}
|
||||
|
||||
void AddRecent(const char[] model, const char[] name) {
|
||||
if(g_recentItems == null) {
|
||||
if(!LoadRecents()) return;
|
||||
}
|
||||
RecentEntry entry;
|
||||
if(!g_recentItems.GetArray(model, entry, sizeof(entry))) {
|
||||
entry.count = 0;
|
||||
strcopy(entry.name, sizeof(entry.name), name);
|
||||
}
|
||||
entry.count++;
|
||||
recentsChanged = true;
|
||||
g_recentItems.SetArray(model, entry, sizeof(entry));
|
||||
}
|
||||
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) {
|
||||
if(!g_PropData[client].isSearchActive) {
|
||||
return Plugin_Continue;
|
||||
}
|
||||
DoSearch(client, sArgs);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
void DoSearch(int client, const char[] query) {
|
||||
ArrayList results = SearchItems(query);
|
||||
if(results.Length == 0) {
|
||||
CPrintToChat(client, "\x04[Editor]\x01 No results found. :(");
|
||||
} else {
|
||||
ShowItemMenuAny(client, results, "", true);
|
||||
}
|
||||
g_PropData[client].isSearchActive = false;
|
||||
}
|
||||
// Gets the index of the spawned item, starting at index. negative to go from back
|
||||
int GetSpawnedIndex(int client, int index) {
|
||||
int userid = GetClientUserId(client);
|
||||
if(index >= 0) {
|
||||
for(int i = index; i < g_spawnedItems.Length; i++) {
|
||||
int spawnedBy = g_spawnedItems.Get(i, 1);
|
||||
if(spawnedBy == userid) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(int i = g_spawnedItems.Length + index; i >= 0; i--) {
|
||||
int spawnedBy = g_spawnedItems.Get(i, 1);
|
||||
if(spawnedBy == userid) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
#define MAX_SEARCH_RESULTS 10
|
||||
ArrayList SearchItems(const char[] query) {
|
||||
// We have to put it into SearchData enum struct, then convert it back to ItemResult
|
||||
LoadCategories();
|
||||
ArrayList results = new ArrayList(sizeof(SearchData));
|
||||
_searchCategory(results, g_categories, query);
|
||||
results.SortCustom(SortSearch);
|
||||
ArrayList items = new ArrayList(sizeof(ItemData));
|
||||
ItemData item;
|
||||
SearchData data;
|
||||
for(int i = 0; i < results.Length; i++) {
|
||||
results.GetArray(i, data);
|
||||
PrintToConsoleAll("%d | data=\"%s\"", i, data.model);
|
||||
item.FromSearchData(data);
|
||||
PrintToConsoleAll("%d | item=\"%s\"", i, item.model);
|
||||
items.PushArray(item);
|
||||
}
|
||||
delete results;
|
||||
return items;
|
||||
}
|
||||
|
||||
int SortSearch(int index1, int index2, ArrayList array, Handle handle) {
|
||||
SearchData data1;
|
||||
array.GetArray(index1, data1);
|
||||
SearchData data2;
|
||||
array.GetArray(index2, data2);
|
||||
return data1.index - data2.index;
|
||||
}
|
||||
|
||||
void _searchCategory(ArrayList results, ArrayList categories, const char[] query) {
|
||||
CategoryData cat;
|
||||
if(categories == null) return;
|
||||
for(int i = 0; i < categories.Length; i++) {
|
||||
categories.GetArray(i, cat);
|
||||
if(cat.hasItems) {
|
||||
//cat.items is of CatetoryData
|
||||
if(!_searchItems(results, cat.items, query)) return;
|
||||
} else {
|
||||
//cat.items is of ItemData
|
||||
_searchCategory(results, cat.items, query);
|
||||
}
|
||||
}
|
||||
}
|
||||
bool _searchItems(ArrayList results, ArrayList items, const char[] query) {
|
||||
ItemData item;
|
||||
SearchData search;
|
||||
for(int i = 0; i < items.Length; i++) {
|
||||
items.GetArray(i, item);
|
||||
int searchIndex = StrContains(item.name, query, false);
|
||||
if(searchIndex > -1) {
|
||||
search.FromItemData(item);
|
||||
search.index = searchIndex;
|
||||
results.PushArray(search);
|
||||
if(results.Length > MAX_SEARCH_RESULTS) return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
int GetSpawnedItem(int index) {
|
||||
if(index < 0 || index >= g_spawnedItems.Length) return -1;
|
||||
int ref = g_spawnedItems.Get(index);
|
||||
if(!IsValidEntity(ref)) {
|
||||
g_spawnedItems.Erase(index);
|
||||
return -1;
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
|
||||
bool RemoveSpawnedProp(int ref) {
|
||||
// int ref = EntIndexToEntRef(entity);
|
||||
int index = g_spawnedItems.FindValue(ref);
|
||||
if(index > -1) {
|
||||
g_spawnedItems.Erase(index);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void EndDeleteTool(int client, bool deleteEntities = false) {
|
||||
if(g_PropData[client].markedProps != null) {
|
||||
int count;
|
||||
for(int i = 0; i < g_PropData[client].markedProps.Length; i++) {
|
||||
int ref = g_PropData[client].markedProps.Get(i);
|
||||
if(IsValidEntity(ref)) {
|
||||
count++;
|
||||
if(deleteEntities) {
|
||||
RemoveSpawnedProp(ref);
|
||||
RemoveEntity(ref);
|
||||
}
|
||||
else L4D2_RemoveEntityGlow(EntRefToEntIndex(ref));
|
||||
}
|
||||
}
|
||||
delete g_PropData[client].markedProps;
|
||||
if(deleteEntities)
|
||||
PrintToChat(client, "\x04[Editor]\x01 \x05%d\x01 entities deleted", count);
|
||||
else
|
||||
PrintToChat(client, "\x04[Editor]\x01 Delete tool cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
int DeleteAll(int onlyPlayer = 0) {
|
||||
int userid = onlyPlayer > 0 ? GetClientUserId(onlyPlayer) : 0;
|
||||
int count;
|
||||
for(int i = 0; i < g_spawnedItems.Length; i++) {
|
||||
int ref = g_spawnedItems.Get(i);
|
||||
int spawnedBy = g_spawnedItems.Get(i, 1);
|
||||
// Skip if wishing to only delete certain items:
|
||||
if(onlyPlayer != 0 && spawnedBy != userid) continue;
|
||||
if(IsValidEntity(ref)) {
|
||||
RemoveEntity(ref);
|
||||
}
|
||||
g_spawnedItems.Erase(i);
|
||||
count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
#define SHOW_HINT_MIN_DURATION 600 // 600 s (10min)
|
||||
void ShowHint(int client) {
|
||||
int time = GetTime();
|
||||
if(time - g_PropData[client].lastShowedHint < SHOW_HINT_MIN_DURATION) return;
|
||||
PrintToChat(client, "\x05R: \x01Change Mode");
|
||||
PrintToChat(client, "\x05Middle Click: \x01Cancel Placement \x05Shift + Middle Click: \x01Place \x05Ctrl + Middle Click: \x01Change Type");
|
||||
PrintToChat(client, "\x05E: \x01Rotate (hold, use mouse) \x05Left Click: \x01Change Axis \x05Right Click: \x01Snap Angle");
|
||||
|
||||
g_PropData[client].lastShowedHint = time;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue