mirror of
https://github.com/Jackzmc/sourcemod-plugins.git
synced 2025-05-05 20:33:20 +00:00
Working prop spawner
This commit is contained in:
parent
a15efc9cce
commit
5796ddd536
5 changed files with 1021 additions and 244 deletions
|
@ -328,7 +328,6 @@ Action Command_DoAHat(int client, int args) {
|
|||
// Use the new wall editor
|
||||
WallBuilder[client].Reset();
|
||||
WallBuilder[client].entity = EntIndexToEntRef(entity);
|
||||
WallBuilder[client].canScale = false;
|
||||
WallBuilder[client].SetMode(MOVE_ORIGIN);
|
||||
PrintToChat(client, "\x04[Hats] \x01Beta Prop Mover active for \x04%d", entity);
|
||||
} else {
|
||||
|
@ -353,7 +352,7 @@ Action Command_DoAHat(int client, int args) {
|
|||
} else if(entity == EntRefToEntIndex(WallBuilder[client].entity)) {
|
||||
// Prevent making an entity you editing a hat
|
||||
return Plugin_Handled;
|
||||
} else if(cvar_sm_hats_max_distance.FloatValue > 0.0 && entity >= MaxClients) {
|
||||
} else if(!isForced && cvar_sm_hats_max_distance.FloatValue > 0.0 && entity >= MaxClients) {
|
||||
float posP[3], posE[3];
|
||||
GetClientEyePosition(client, posP);
|
||||
GetEntPropVector(entity, Prop_Data, "m_vecOrigin", posE);
|
||||
|
@ -377,8 +376,8 @@ Action Command_DoAHat(int client, int args) {
|
|||
PrintToConsole(client, "[Hats] Selected a child entity, selecting parent (child %d -> parent %d)", entity, parent);
|
||||
entity = parent;
|
||||
} else if(entity <= MaxClients) { // Checks for hatting a player entity
|
||||
if(IsFakeClient(entity)) {
|
||||
PrintToChat(client, "[Hats] Cannot hat bots");
|
||||
if(IsFakeClient(entity) && L4D_GetIdlePlayerOfBot(entity) != -1) {
|
||||
PrintToChat(client, "[Hats] Cannot hat idle bots");
|
||||
return Plugin_Handled;
|
||||
} else if(GetClientTeam(entity) != 2 && ~cvar_sm_hats_flags.IntValue & view_as<int>(HatConfig_InfectedHats)) {
|
||||
PrintToChat(client, "[Hats] Cannot make enemy a hat... it's dangerous");
|
||||
|
@ -537,7 +536,7 @@ int HatConsentHandler(Menu menu, MenuAction action, int target, int param2) {
|
|||
}
|
||||
|
||||
bool IsHatsEnabled(int client) {
|
||||
return (cvar_sm_hats_enabled.IntValue == 1 && GetUserAdmin(client) != INVALID_ADMIN_ID) || cvar_sm_hats_enabled.IntValue == 2
|
||||
return (cvar_sm_hats_enabled.IntValue == 1 && GetUserAdmin(client) != INVALID_ADMIN_ID) || cvar_sm_hats_enabled.IntValue == 2
|
||||
}
|
||||
|
||||
void ClearHats() {
|
||||
|
|
|
@ -1,69 +1,644 @@
|
|||
TopMenuObject g_propSpawnerCategory;
|
||||
public void OnAdminMenuReady(Handle topMenuHandle) {
|
||||
TopMenu topMenu = TopMenu.FromHandle(topMenuHandle);
|
||||
if(topMenu != g_topMenu) {
|
||||
TopMenuObject propSpawner = topMenu.AddCategory("Prop Spawner (Alpha)", Category_Handler);
|
||||
if(propSpawner != INVALID_TOPMENUOBJECT) {
|
||||
topMenu.AddItem("Spawn Prop", AdminMenu_Spawn, propSpawner, "sm_prop");
|
||||
topMenu.AddItem("Edit Props", AdminMenu_Edit, propSpawner, "sm_prop");
|
||||
topMenu.AddItem("Delete Props", AdminMenu_Delete, propSpawner, "sm_prop");
|
||||
topMenu.AddItem("Save / Load", AdminMenu_SaveLoad, propSpawner, "sm_prop");
|
||||
|
||||
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;
|
||||
|
||||
}
|
||||
|
||||
|
||||
enum struct CategoryData {
|
||||
char name[64];
|
||||
bool hasItems;
|
||||
ArrayList items;
|
||||
}
|
||||
enum struct ItemData {
|
||||
char model[128];
|
||||
char name[64];
|
||||
}
|
||||
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[] output) {
|
||||
char buffer[32];
|
||||
int index = SplitString(output, ",", this.model, sizeof(this.model));
|
||||
index = SplitString(output[index], ",", buffer, sizeof(buffer));
|
||||
this.type = view_as<buildType>(StringToInt(buffer));
|
||||
for(int i = 0; i < 3; i++) {
|
||||
index = SplitString(output[index], ",", buffer, sizeof(buffer));
|
||||
this.origin[i] = StringToFloat(buffer);
|
||||
}
|
||||
for(int i = 0; i < 3; i++) {
|
||||
index = SplitString(output[index], ",", buffer, sizeof(buffer));
|
||||
this.angles[i] = StringToFloat(buffer);
|
||||
}
|
||||
for(int i = 0; i < 4; i++) {
|
||||
index = SplitString(output[index], ",", buffer, sizeof(buffer));
|
||||
this.color[i] = StringToInt(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
ArrayList g_categories;
|
||||
ArrayList g_spawnedItems;
|
||||
ArrayList g_savedItems;
|
||||
|
||||
bool LoadSaves(ArrayList saves) {
|
||||
saves = new ArrayList(ByteCountToCells(64));
|
||||
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 false;
|
||||
char buffer[64];
|
||||
while(listing.GetNext(buffer, sizeof(buffer), fileType)) {
|
||||
saves.PushString(buffer);
|
||||
}
|
||||
delete listing;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool LoadSave(const char[] save) {
|
||||
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];
|
||||
SaveData data;
|
||||
while(file.ReadLine(buffer, sizeof(buffer))) {
|
||||
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");
|
||||
DispatchKeyValue(entity, "solid", data.type == Build_NonSolid ? "0" : "6");
|
||||
TeleportEntity(entity, data.origin, data.angles, NULL_VECTOR);
|
||||
if(!DispatchSpawn(entity)) continue;
|
||||
// TODO: Setrendertype?
|
||||
SetEntityRenderColor(entity, data.color[0], data.color[1], data.color[2], data.color[3]);
|
||||
// TODO: previews?
|
||||
// g_savedItems.PushArray(data);
|
||||
}
|
||||
delete file;
|
||||
// delete savedItems;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CreateSave(const char[] name) {
|
||||
char path[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, path, sizeof(path), "data/prop_spawner/saves/%s/%s.txt", g_currentMap, name);
|
||||
File file = OpenFile(name, "w");
|
||||
if(file == null) return false;
|
||||
char buffer[132];
|
||||
SaveData data;
|
||||
for(int i = 0; i < g_spawnedItems.Length; i++) {
|
||||
int ref = g_spawnedItems.Get(i);
|
||||
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);
|
||||
}
|
||||
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();
|
||||
|
||||
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))) {
|
||||
ItemData item;
|
||||
int index = SplitString(buffer, " ", item.model, sizeof(item.model));
|
||||
if(index == -1) {
|
||||
strcopy(item.name, sizeof(item.name), buffer);
|
||||
} else {
|
||||
strcopy(item.name, sizeof(item.name), buffer[index]);
|
||||
}
|
||||
category.items.PushArray(item);
|
||||
}
|
||||
parent.PushArray(category);
|
||||
delete file;
|
||||
}
|
||||
public Action OnClientSayCommand(int client, const char[] command, const char[] sArgs) {
|
||||
if(!g_isSearchActive[client]) {
|
||||
return Plugin_Continue;
|
||||
}
|
||||
ArrayList results = SearchItems(sArgs);
|
||||
if(results.Length == 0) {
|
||||
CPrintToChat(client, "\x04[Editor]\x01 No results found. :(");
|
||||
} else {
|
||||
ShowItemMenuAny(client, results);
|
||||
}
|
||||
delete results;
|
||||
return Plugin_Handled;
|
||||
}
|
||||
#define MAX_SEARCH_RESULTS 30
|
||||
ArrayList SearchItems(const char[] query) {
|
||||
// TODO: search
|
||||
ArrayList results = new ArrayList(sizeof(ItemData));
|
||||
_searchCategory(results, g_categories, query);
|
||||
return results;
|
||||
}
|
||||
|
||||
void _searchCategory(ArrayList results, ArrayList categories, const char[] query) {
|
||||
CategoryData cat;
|
||||
for(int i = 0; i < categories.Length; i++) {
|
||||
categories.GetArray(i, cat);
|
||||
if(cat.hasItems) {
|
||||
_searchItems(results, cat.items, query);
|
||||
} else {
|
||||
_searchCategory(results, cat.items, query);
|
||||
}
|
||||
if(results.Length > MAX_SEARCH_RESULTS) return;
|
||||
}
|
||||
}
|
||||
void _searchItems(ArrayList results, ArrayList items, const char[] query) {
|
||||
ItemData item;
|
||||
for(int i = 0; i < items.Length; i++) {
|
||||
items.GetArray(i, item);
|
||||
if(StrContains(item.name, query, false)) {
|
||||
results.PushArray(item);
|
||||
}
|
||||
if(results.Length > MAX_SEARCH_RESULTS) return;
|
||||
}
|
||||
}
|
||||
|
||||
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");
|
||||
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_SelectOption) {
|
||||
if(!FindConVar("sv_cheats").BoolValue) {
|
||||
ReplyToCommand(param, "[Props] Enable cheats to use the prop spawner");
|
||||
if(action == TopMenuAction_DisplayOption) {
|
||||
Format(buffer, maxlength, "Spawn Props");
|
||||
} else if(action == TopMenuAction_SelectOption) {
|
||||
if(!FindConVar("sm_cheats").BoolValue) {
|
||||
CReplyToCommand(param, "\x04[Editor] \x01Set \x05sm_cheats\x01 to \x051\x01 to use the prop spawner");
|
||||
return;
|
||||
}
|
||||
// TODO:
|
||||
/*
|
||||
Flow:
|
||||
1. /admin -> Prop Spawner -> Spawn -> [category] -> [prop]
|
||||
2. ghost spawner active (press '?somekey?' to switch spawn mode)
|
||||
3. continue on place. press button to press?
|
||||
*/
|
||||
// Menu menu = new Menu(Handler_Spawn);
|
||||
// menu.SetTitle("Spawn Method:");
|
||||
|
||||
// menu.AddItem("p", "Physics");
|
||||
// menu.AddItem("s", "Solid");
|
||||
// menu.AddItem("n", "Non Solid");
|
||||
|
||||
// menu.ExitBackButton = true;
|
||||
// menu.ExitButton = true;
|
||||
// menu.Display(param, MENU_TIME_FOREVER);
|
||||
Menu menu = new Menu(Spawn_RootHandler);
|
||||
menu.SetTitle("Choose list:");
|
||||
menu.AddItem("f", "Favorites");
|
||||
menu.AddItem("r", "Recents");
|
||||
menu.AddItem("s", "Search");
|
||||
menu.AddItem("n", "Prop List");
|
||||
menu.ExitBackButton = true;
|
||||
menu.ExitButton = true;
|
||||
menu.Display(param, MENU_TIME_FOREVER);
|
||||
}
|
||||
}
|
||||
void AdminMenu_Edit(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) {
|
||||
|
||||
}
|
||||
void AdminMenu_Delete(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) {
|
||||
|
||||
}
|
||||
void AdminMenu_SaveLoad(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) {
|
||||
|
||||
}
|
||||
|
||||
int Handler_Spawn(Menu menu, MenuAction action, int client, int param2) {
|
||||
int Spawn_RootHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
if (action == MenuAction_Select) {
|
||||
static char info[2];
|
||||
if(info[0] == 'p') {
|
||||
|
||||
}
|
||||
|
||||
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_End)
|
||||
delete menu;
|
||||
return 0;
|
||||
}
|
||||
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);
|
||||
}
|
||||
Spawn_ShowRecents(int client) {
|
||||
Menu menu = new Menu(SpawnItemHandler);
|
||||
menu.SetTitle("Recent Props:");
|
||||
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);
|
||||
}
|
||||
Spawn_ShowSearch(int client) {
|
||||
g_isSearchActive[client] = true;
|
||||
CReplyToCommand(client, "\x04[Editor] \x01Please enter search query in chat:");
|
||||
}
|
||||
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 ShowDeleteList(int client, int index) {
|
||||
Menu menu = new Menu(DeleteHandler);
|
||||
menu.SetTitle("Delete Props");
|
||||
|
||||
menu.AddItem("-1", "Delete All");
|
||||
menu.AddItem("-2", "Delete All (Mine Only)");
|
||||
char info[8];
|
||||
char buffer[128];
|
||||
for(int i = 0; i < g_spawnedItems.Length; i++) {
|
||||
int ref = g_spawnedItems.Get(i);
|
||||
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 + 2, 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 = g_spawnedItems.Get(i);
|
||||
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 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, -2);
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
ArrayList saves;
|
||||
LoadSaves(saves);
|
||||
Menu menu = new Menu(SaveLoadHandler);
|
||||
menu.SetTitle("Save / Load");
|
||||
char name[64];
|
||||
menu.AddItem("", "[New Save]");
|
||||
for(int i = 0; i < saves.Length; i++) {
|
||||
saves.GetString(i, name, sizeof(name));
|
||||
menu.AddItem(name, name);
|
||||
}
|
||||
menu.ExitBackButton = true;
|
||||
menu.ExitButton = true;
|
||||
menu.Display(param, MENU_TIME_FOREVER);
|
||||
delete saves;
|
||||
}
|
||||
}
|
||||
|
||||
void ShowCategoryList(int client) {
|
||||
LoadCategories();
|
||||
Menu menu = new Menu(SpawnCategoryHandler);
|
||||
menu.SetTitle("Choose a category");
|
||||
CategoryData cat;
|
||||
char info[4];
|
||||
for(int i = 0; i < g_categories.Length; i++) {
|
||||
g_categories.GetArray(i, cat);
|
||||
Format(info, sizeof(info), "%d", i);
|
||||
// TODO: add support for nested
|
||||
if(cat.hasItems)
|
||||
menu.AddItem(info, cat.name);
|
||||
}
|
||||
menu.ExitBackButton = true;
|
||||
menu.ExitButton = true;
|
||||
menu.DisplayAt(client, g_lastCategoryIndex[client], 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);
|
||||
if(index > 0) {
|
||||
ShowItemMenu(client, index);
|
||||
}
|
||||
} 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 %X");
|
||||
if(CreateSave(saveName)) {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Created save \x05%s.txt", saveName);
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Error creating save file");
|
||||
}
|
||||
} else if(LoadSave(saveName)) {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Loaded save \x05%s", saveName);
|
||||
} 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, index);
|
||||
} 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, index);
|
||||
} 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;
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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) {
|
||||
WallBuilder[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;
|
||||
}
|
||||
|
||||
|
||||
void ShowItemMenuAny(int client, ArrayList items, const char[] title = "") {
|
||||
Menu itemMenu = new Menu(SpawnItemHandler);
|
||||
if(title[0] != '\0')
|
||||
itemMenu.SetTitle(title);
|
||||
ItemData item;
|
||||
char info[132];
|
||||
for(int i = 0; i < items.Length; i++) {
|
||||
items.GetArray(i, item);
|
||||
Format(info, sizeof(info), "%d|%s", i, item.model);
|
||||
itemMenu.AddItem(info, item.name);
|
||||
}
|
||||
itemMenu.ExitBackButton = true;
|
||||
itemMenu.ExitButton = true;
|
||||
itemMenu.DisplayAt(client, g_lastItemIndex[client], MENU_TIME_FOREVER);
|
||||
}
|
||||
|
||||
void ShowItemMenu(int client, int index) {
|
||||
if(g_lastCategoryIndex[client] != index) {
|
||||
g_lastCategoryIndex[client] = index;
|
||||
g_lastItemIndex[client] = 0; //Reset
|
||||
}
|
||||
CategoryData category;
|
||||
g_categories.GetArray(index, category);
|
||||
ShowItemMenuAny(client, category.items, category.name);
|
||||
}
|
||||
|
||||
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];
|
||||
int modelIndex = SplitString(info, "|", index, sizeof(index));
|
||||
g_lastItemIndex[client] = StringToInt(index);
|
||||
|
||||
if(WallBuilder[client].PreviewModel(info[modelIndex])) {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Spawning: \x04%s\x01", info[modelIndex+7]);
|
||||
ShowHint(client);
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Error spawning model \x01(%s)");
|
||||
}
|
||||
|
||||
ShowItemMenu(client, g_lastCategoryIndex[client]);
|
||||
} else if(action == MenuAction_Cancel) {
|
||||
if(param2 == MenuCancel_ExitBack) {
|
||||
ShowCategoryList(client);
|
||||
}
|
||||
} else if (action == MenuAction_End) {
|
||||
delete menu;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define SHOW_HINT_MIN_DURATION 600 // 600 s (10min)
|
||||
void ShowHint(int client) {
|
||||
int time = GetTime();
|
||||
if(time - g_lastShowedHint[client] < 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: \x01Rotate Axis \x05Right Click: \x01Snap Angle");
|
||||
|
||||
g_lastShowedHint[client] = time;
|
||||
}
|
||||
|
||||
Action Command_Props(int client, int args) {
|
||||
PrintToChat(client, "\x05Not implemented");
|
||||
return Plugin_Handled;
|
||||
}
|
|
@ -5,12 +5,43 @@ int GLOW_WHITE[4] = { 255, 255, 255, 255 };
|
|||
int GLOW_GREEN[4] = { 3, 252, 53 };
|
||||
float ORIGIN_SIZE[3] = { 2.0, 2.0, 2.0 };
|
||||
|
||||
enum wallMode {
|
||||
enum editMode {
|
||||
INACTIVE = 0,
|
||||
MOVE_ORIGIN,
|
||||
SCALE,
|
||||
FREELOOK
|
||||
COLOR,
|
||||
FREELOOK,
|
||||
}
|
||||
char MODE_NAME[5][] = {
|
||||
"Error",
|
||||
"Move & Rotate",
|
||||
"Scale",
|
||||
"Color",
|
||||
"Freelook"
|
||||
}
|
||||
|
||||
enum editFlag {
|
||||
Edit_None,
|
||||
Edit_Copy = 1,
|
||||
Edit_Preview = 2,
|
||||
Edit_WallCreator = 4
|
||||
}
|
||||
|
||||
enum buildType {
|
||||
Build_Solid,
|
||||
Build_Physics,
|
||||
Build_NonSolid,
|
||||
}
|
||||
|
||||
enum CompleteType {
|
||||
Complete_WallSuccess,
|
||||
Complete_WallError,
|
||||
Complete_PropSpawned,
|
||||
Complete_PropError,
|
||||
Complete_EditSuccess
|
||||
}
|
||||
|
||||
char COLOR_INDEX[4] = "RGBA";
|
||||
|
||||
ArrayList createdWalls;
|
||||
|
||||
|
@ -19,25 +50,35 @@ enum struct WallBuilderData {
|
|||
float mins[3];
|
||||
float angles[3];
|
||||
float size[3];
|
||||
wallMode mode;
|
||||
int color[4];
|
||||
int colorIndex;
|
||||
int axis;
|
||||
int snapAngle;
|
||||
int moveSpeed;
|
||||
float moveDistance;
|
||||
int entity;
|
||||
bool canScale;
|
||||
bool hasCollision;
|
||||
bool isCopy;
|
||||
|
||||
editMode mode;
|
||||
buildType buildType;
|
||||
editFlag flags;
|
||||
|
||||
void Reset(bool initial = false) {
|
||||
// Clear previews
|
||||
if(this.entity != INVALID_ENT_REFERENCE && this.flags & Edit_Preview) {
|
||||
if(IsValidEntity(this.entity))
|
||||
RemoveEntity(this.entity);
|
||||
}
|
||||
this.entity = INVALID_ENT_REFERENCE;
|
||||
this.isCopy = false;
|
||||
this.size[0] = this.size[1] = this.size[2] = 5.0;
|
||||
this.angles[0] = this.angles[1] = this.angles[2] = 0.0;
|
||||
this.color[0] = this.color[1] = this.color[2] = this.color[3] = 255;
|
||||
this.colorIndex = 0;
|
||||
this.axis = 1;
|
||||
this.canScale = true;
|
||||
this.moveDistance = 200.0;
|
||||
this.hasCollision = true;
|
||||
this.flags = Edit_None;
|
||||
this.buildType = Build_Solid;
|
||||
this.CalculateMins();
|
||||
this.SetMode(INACTIVE);
|
||||
if(initial) {
|
||||
|
@ -53,18 +94,27 @@ enum struct WallBuilderData {
|
|||
}
|
||||
|
||||
void Draw(int color[4], float lifetime, float amplitude = 0.1) {
|
||||
if(!this.canScale && this.entity != INVALID_ENT_REFERENCE) {
|
||||
TeleportEntity(this.entity, this.origin, this.angles, NULL_VECTOR);
|
||||
} else {
|
||||
if(this.flags & Edit_WallCreator || this.entity == INVALID_ENT_REFERENCE) {
|
||||
Effect_DrawBeamBoxRotatableToAll(this.origin, this.mins, this.size, this.angles, g_iLaserIndex, 0, 0, 30, lifetime, 0.4, 0.4, 0, amplitude, color, 0);
|
||||
} else {
|
||||
TeleportEntity(this.entity, this.origin, this.angles, NULL_VECTOR);
|
||||
}
|
||||
Effect_DrawAxisOfRotationToAll(this.origin, this.angles, ORIGIN_SIZE, g_iLaserIndex, 0, 0, 30, 0.2, 0.1, 0.1, 0, 0.0, 0);
|
||||
}
|
||||
|
||||
void UpdateEntity() {
|
||||
int alpha = this.color[3];
|
||||
// Keep previews transparent
|
||||
if(this.flags & Edit_Preview) {
|
||||
alpha = 200;
|
||||
}
|
||||
SetEntityRenderColor(this.entity, this.color[0], this.color[1], this.color[2], alpha);
|
||||
}
|
||||
|
||||
bool CheckEntity(int client) {
|
||||
if(this.entity != INVALID_ENT_REFERENCE) {
|
||||
if(!IsValidEntity(this.entity)) {
|
||||
PrintToChat(client, "\x04[Hats]\x01 Entity has vanished, editing cancelled.");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Entity has vanished, editing cancelled.");
|
||||
this.Reset();
|
||||
return false;
|
||||
}
|
||||
|
@ -76,7 +126,7 @@ enum struct WallBuilderData {
|
|||
return this.mode != INACTIVE;
|
||||
}
|
||||
|
||||
void SetMode(wallMode mode) {
|
||||
void SetMode(editMode mode) {
|
||||
this.mode = mode;
|
||||
}
|
||||
|
||||
|
@ -91,34 +141,36 @@ enum struct WallBuilderData {
|
|||
// - SCALE
|
||||
// - FREECAM
|
||||
case MOVE_ORIGIN: {
|
||||
if(this.canScale) {
|
||||
if(this.flags & Edit_WallCreator) {
|
||||
this.mode = SCALE;
|
||||
PrintToChat(client, "\x04[Hats]\x01 Mode: \x05Scale\x01 (Press \x04RELOAD\x01 to change mode)");
|
||||
} else if(this.flags & Edit_Preview) {
|
||||
this.mode = COLOR;
|
||||
} else {
|
||||
this.mode = FREELOOK;
|
||||
PrintToChat(client, "\x04[Hats]\x01 Mode: \x05Freelook\x01 (Press \x04RELOAD\x01 to change mode)");
|
||||
}
|
||||
}
|
||||
case SCALE: {
|
||||
this.mode = FREELOOK;
|
||||
PrintToChat(client, "\x04[Hats]\x01 Mode: \x05Freelook\x01 (Press \x04RELOAD\x01 to change mode)");
|
||||
}
|
||||
case COLOR: {
|
||||
this.mode = FREELOOK;
|
||||
}
|
||||
case FREELOOK: {
|
||||
this.mode = MOVE_ORIGIN;
|
||||
PrintToChat(client, "\x04[Hats]\x01 Mode: \x05Move & Rotate\x01 (Press \x04RELOAD\x01 to change mode)");
|
||||
// PrintToChat(client, "Hold \x04USE (E)\x01 to rotate, \x04WALK (SHIFT)\x01 to change speed");
|
||||
}
|
||||
}
|
||||
PrintToChat(client, "\x04[Editor]\x01 Mode: \x05%s\x01 (Press \x04RELOAD\x01 to change mode)", MODE_NAME[this.mode]);
|
||||
cmdThrottle[client] = tick;
|
||||
}
|
||||
|
||||
void ToggleCollision(int client, float tick) {
|
||||
if(tick - cmdThrottle[client] <= 0.15) return;
|
||||
if(tick - cmdThrottle[client] <= 0.25) return;
|
||||
this.hasCollision = !this.hasCollision
|
||||
if(this.hasCollision)
|
||||
PrintToChat(client, "\x04[Hats]\x01 Collision: \x05ON\x01");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Collision: \x05ON\x01");
|
||||
else
|
||||
PrintToChat(client, "\x04[Hats]\x01 Collision: \x04OFF\x01");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Collision: \x04OFF\x01");
|
||||
cmdThrottle[client] = tick;
|
||||
}
|
||||
|
||||
|
@ -126,13 +178,13 @@ enum struct WallBuilderData {
|
|||
if(tick - cmdThrottle[client] <= 0.15) return;
|
||||
if(this.axis == 0) {
|
||||
this.axis = 1;
|
||||
PrintToChat(client, "\x04[Hats]\x01 Rotate Axis: \x05HEADING (Y)\x01");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Rotate Axis: \x05HEADING (Y)\x01");
|
||||
} else if(this.axis == 1) {
|
||||
this.axis = 2;
|
||||
PrintToChat(client, "\x04[Hats]\x01 Rotate Axis: \x05PITCH (X)\x01");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Rotate Axis: \x05PITCH (X)\x01");
|
||||
} else {
|
||||
this.axis = 0;
|
||||
PrintToChat(client, "\x04[Hats]\x01 Rotate Axis: \x05ROLL (Z)\x01");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Rotate Axis: \x05ROLL (Z)\x01");
|
||||
}
|
||||
cmdThrottle[client] = tick;
|
||||
}
|
||||
|
@ -152,9 +204,9 @@ enum struct WallBuilderData {
|
|||
this.angles[2] = SnapTo(this.angles[2], float(this.snapAngle));
|
||||
|
||||
if(this.snapAngle == 1)
|
||||
PrintToChat(client, "\x04[Hats]\x01 Rotate Snap Degrees: \x04(OFF)\x01", this.snapAngle);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Rotate Snap Degrees: \x04(OFF)\x01", this.snapAngle);
|
||||
else
|
||||
PrintToChat(client, "\x04[Hats]\x01 Rotate Snap Degrees: \x05%d\x01", this.snapAngle);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Rotate Snap Degrees: \x05%d\x01", this.snapAngle);
|
||||
cmdThrottle[client] = tick;
|
||||
}
|
||||
|
||||
|
@ -162,21 +214,50 @@ enum struct WallBuilderData {
|
|||
if(tick - cmdThrottle[client] <= 0.25) return;
|
||||
this.moveSpeed++;
|
||||
if(this.moveSpeed > 10) this.moveSpeed = 1;
|
||||
PrintToChat(client, "\x04[Hats]\x01 Scale Speed: \x05%d\x01", this.moveSpeed);
|
||||
// if(this.movetype == 0) {
|
||||
// this.movetype = 1;
|
||||
// PrintToChat(client, "\x04[SM]\x01 Move Type: \x05HEADING (Y)\x01");
|
||||
// } else {
|
||||
// this.movetype = 0;
|
||||
// PrintToChat(client, "\x04[SM]\x01 Rotate Axis: \x05PITCH (X)\x01");
|
||||
// }
|
||||
PrintToChat(client, "\x04[Editor]\x01 Scale Speed: \x05%d\x01", this.moveSpeed);
|
||||
cmdThrottle[client] = tick;
|
||||
}
|
||||
|
||||
int Build() {
|
||||
if(!this.canScale) {
|
||||
void CycleBuildType(int client) {
|
||||
// No tick needed, is handled externally
|
||||
if(this.buildType == Build_Physics) {
|
||||
this.buildType = Build_Solid;
|
||||
PrintToChat(client, "\x04[Editor]\x01 Spawn as: \x05Solid\x01");
|
||||
} else if(this.buildType == Build_Solid) {
|
||||
this.buildType = Build_Physics;
|
||||
PrintToChat(client, "\x04[Editor]\x01 Spawn as: \x05Physics\x01");
|
||||
} else {
|
||||
this.buildType = Build_NonSolid;
|
||||
PrintToChat(client, "\x04[Editor]\x01 Spawn as: \x05Non Solid\x01");
|
||||
}
|
||||
}
|
||||
|
||||
void CycleColorComponent(int client, float tick) {
|
||||
if(tick - cmdThrottle[client] <= 0.25) return;
|
||||
this.colorIndex++;
|
||||
if(this.colorIndex > 3) this.colorIndex = 0;
|
||||
PrintToChat(client, "\x04[Editor]\x01 Color Component: \x05%c\x01", COLOR_INDEX[this.colorIndex]);
|
||||
cmdThrottle[client] = tick;
|
||||
}
|
||||
|
||||
|
||||
CompleteType Create(int& entity) {
|
||||
if(this.flags & Edit_WallCreator) {
|
||||
return this._FinishWall(entity) ? Complete_WallSuccess : Complete_WallError;
|
||||
} else if(this.flags & Edit_Preview) {
|
||||
return this._FinishPreview(entity) ? Complete_PropSpawned : Complete_PropError;
|
||||
} else {
|
||||
// Is edit, do nothing, just reset
|
||||
this.Reset();
|
||||
return -3;
|
||||
entity = 0;
|
||||
return Complete_EditSuccess;
|
||||
}
|
||||
}
|
||||
|
||||
bool _FinishWall(int& id) {
|
||||
if(~this.flags & Edit_WallCreator) {
|
||||
this.Reset();
|
||||
return false;
|
||||
}
|
||||
// Don't need to build a new one if we editing:
|
||||
int blocker = this.entity;
|
||||
|
@ -186,7 +267,7 @@ enum struct WallBuilderData {
|
|||
isEdit = true;
|
||||
}
|
||||
blocker = CreateEntityByName("func_brush");
|
||||
if(blocker == -1) return -1;
|
||||
if(blocker == -1) return false;
|
||||
DispatchKeyValueVector(blocker, "mins", this.mins);
|
||||
DispatchKeyValueVector(blocker, "maxs", this.size);
|
||||
DispatchKeyValueVector(blocker, "boxmins", this.mins);
|
||||
|
@ -203,7 +284,7 @@ enum struct WallBuilderData {
|
|||
DispatchKeyValue(blocker, "targetname", name);
|
||||
// DispatchKeyValue(blocker, "excludednpc", "player");
|
||||
TeleportEntity(blocker, this.origin, this.angles, NULL_VECTOR);
|
||||
if(!DispatchSpawn(blocker)) return -1;
|
||||
if(!DispatchSpawn(blocker)) return false;
|
||||
SetEntPropVector(blocker, Prop_Send, "m_vecMins", this.mins);
|
||||
SetEntPropVector(blocker, Prop_Send, "m_vecMaxs", this.size);
|
||||
SetEntProp(blocker, Prop_Send, "m_nSolidType", 2);
|
||||
|
@ -215,7 +296,42 @@ enum struct WallBuilderData {
|
|||
|
||||
this.Draw(GLOW_GREEN, 5.0, 1.0);
|
||||
this.Reset();
|
||||
return isEdit ? -2 : createdWalls.Push(EntIndexToEntRef(blocker));
|
||||
if(!isEdit) {
|
||||
id = createdWalls.Push(EntIndexToEntRef(blocker));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _FinishPreview(int& entity) {
|
||||
entity = -1;
|
||||
if(this.buildType == Build_Physics)
|
||||
entity = CreateEntityByName("prop_physics");
|
||||
else
|
||||
entity = CreateEntityByName("prop_dynamic");
|
||||
if(entity == -1) return false;
|
||||
|
||||
char model[128];
|
||||
GetEntPropString(this.entity, Prop_Data, "m_ModelName", model, sizeof(model));
|
||||
DispatchKeyValue(entity, "model", model);
|
||||
DispatchKeyValue(entity, "targetname", "prop_preview");
|
||||
if(this.buildType == Build_NonSolid)
|
||||
DispatchKeyValue(entity, "solid", "0");
|
||||
else
|
||||
DispatchKeyValue(entity, "solid", "6");
|
||||
TeleportEntity(entity, this.origin, this.angles, NULL_VECTOR);
|
||||
if(!DispatchSpawn(entity)) {
|
||||
return false;
|
||||
}
|
||||
SetEntityRenderColor(entity, this.color[0], this.color[1], this.color[2], this.color[3]);
|
||||
SetEntityRenderColor(this.entity, 255, 128, 255, 200); // reset ghost
|
||||
GlowEntity(entity, 1.4)
|
||||
|
||||
if(this.mode == FREELOOK)
|
||||
this.SetMode(MOVE_ORIGIN);
|
||||
|
||||
|
||||
// Don't kill preview until cancel
|
||||
return true;
|
||||
}
|
||||
|
||||
int Copy() {
|
||||
|
@ -239,11 +355,38 @@ enum struct WallBuilderData {
|
|||
// SetEntProp(entity, Prop_Send, "m_nSolidType", 6);
|
||||
TeleportEntity(entity, this.origin, this.angles, NULL_VECTOR);
|
||||
this.entity = entity;
|
||||
this.isCopy = true;
|
||||
this.flags |= Edit_Copy;
|
||||
return entity;
|
||||
}
|
||||
|
||||
void Import(int entity, bool makeCopy = false, wallMode mode = SCALE) {
|
||||
void StartWall() {
|
||||
this.Reset();
|
||||
this.flags |= Edit_WallCreator;
|
||||
}
|
||||
|
||||
bool PreviewModel(const char[] model) {
|
||||
// If last entity was preview, kill it
|
||||
PrecacheModel(model);
|
||||
this.Reset();
|
||||
int entity = CreateEntityByName("prop_dynamic");
|
||||
if(entity == -1) return false;
|
||||
DispatchKeyValue(entity, "model", model);
|
||||
DispatchKeyValue(entity, "targetname", "prop_preview");
|
||||
DispatchKeyValue(entity, "solid", "0");
|
||||
DispatchKeyValue(entity, "rendercolor", "255 128 255");
|
||||
DispatchKeyValue(entity, "renderamt", "200");
|
||||
DispatchKeyValue(entity, "rendermode", "1");
|
||||
if(!DispatchSpawn(entity)) {
|
||||
return false;
|
||||
}
|
||||
this.entity = entity;
|
||||
this.flags |= (Edit_Copy | Edit_Preview);
|
||||
this.SetMode(MOVE_ORIGIN);
|
||||
// Seems some entities fail here:
|
||||
return IsValidEntity(entity);
|
||||
}
|
||||
|
||||
void Import(int entity, bool makeCopy = false, editMode mode = SCALE) {
|
||||
this.Reset();
|
||||
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", this.origin);
|
||||
GetEntPropVector(entity, Prop_Send, "m_angRotation", this.angles);
|
||||
|
@ -257,13 +400,65 @@ enum struct WallBuilderData {
|
|||
|
||||
void Cancel() {
|
||||
// Delete any copies:
|
||||
if(this.isCopy) {
|
||||
if(this.flags & Edit_Copy || this.flags & Edit_Preview) {
|
||||
RemoveEntity(this.entity);
|
||||
}
|
||||
this.SetMode(INACTIVE);
|
||||
}
|
||||
|
||||
// void OpenSettings(int client) {
|
||||
// Menu menu = new Menu(SettingsHandler);
|
||||
// menu.AddItem("color", "Change Color");
|
||||
// menu.AddItem("type", "Change Spawn Type");
|
||||
// // if(this.flags & Edit_Scale)
|
||||
// menu.ExitButton = true;
|
||||
// // Only show back if we are for a preview
|
||||
// menu.ExitBackButton = (this.flags & Edit_Preview) != 0;
|
||||
// menu.Display(client, MENU_TIME_FOREVER);
|
||||
// }
|
||||
}
|
||||
|
||||
WallBuilderData WallBuilder[MAXPLAYERS+1];
|
||||
|
||||
// int SettingsHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
// if (action == MenuAction_Select) {
|
||||
// char info[8];
|
||||
// menu.GetItem(param2, info, sizeof(info));
|
||||
// if(StrEqual(info, "color")) {
|
||||
// Menu newMenu = new Menu(ColorHandler);
|
||||
// newMenu.AddItem()
|
||||
// } else if(StrEqual(info, "type")) {
|
||||
|
||||
// } else {
|
||||
// CPrintToChat(client, "\x04[Editor]\x01 Error: Unknown setting \x05%s", info);
|
||||
// }
|
||||
|
||||
// // Re-open category list when done editing setting
|
||||
// if(WallBuilder[client].flags & Edit_Preview) {
|
||||
// ShowItemMenu(client, g_lastCategoryIndex[client]);
|
||||
// }
|
||||
// } else if(action == MenuAction_Cancel) {
|
||||
// if(WallBuilder[client].flags & Edit_Preview) {
|
||||
// ShowItemMenu(client, g_lastCategoryIndex[client]);
|
||||
// }
|
||||
// } else if (action == MenuAction_End)
|
||||
// delete menu;
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
// int ColorHandler(Menu menu, MenuAction action, int client, int param2) {
|
||||
// if (action == MenuAction_Select) {
|
||||
// char info[8];
|
||||
|
||||
// } else if(action == MenuAction_Cancel) {
|
||||
// if(WallBuilder[client].flags & Edit_Preview) {
|
||||
// ShowItemMenu(client, g_lastCategoryIndex[client]);
|
||||
// }
|
||||
// } else if (action == MenuAction_End)
|
||||
// delete menu;
|
||||
// return 0;
|
||||
// }
|
||||
|
||||
Action OnWallClicked(int entity, int activator, int caller, UseType type, float value) {
|
||||
int wallId = FindWallId(entity);
|
||||
if(wallId > 0) {
|
||||
|
@ -275,15 +470,14 @@ Action OnWallClicked(int entity, int activator, int caller, UseType type, float
|
|||
return Plugin_Continue;
|
||||
}
|
||||
|
||||
WallBuilderData WallBuilder[MAXPLAYERS+1];
|
||||
|
||||
|
||||
// TODO: Stacker, copy tool, new command?
|
||||
public Action Command_MakeWall(int client, int args) {
|
||||
if(WallBuilder[client].IsActive()) {
|
||||
ReplyToCommand(client, "\x04[Hats]\x01 You are currently editing an entity. Finish editing your current entity with with \x05/edit done\x01 or cancel with \x04/edit cancel\x01");
|
||||
ReplyToCommand(client, "\x04[Editor]\x01 You are currently editing an entity. Finish editing your current entity with with \x05/edit done\x01 or cancel with \x04/edit cancel\x01");
|
||||
} else {
|
||||
WallBuilder[client].Reset();
|
||||
WallBuilder[client].StartWall();
|
||||
if(args > 0) {
|
||||
// Get values for X, Y and Z axis (defaulting to 1.0):
|
||||
char arg2[8];
|
||||
|
@ -311,15 +505,15 @@ public Action Command_MakeWall(int client, int args) {
|
|||
|
||||
WallBuilder[client].SetMode(SCALE);
|
||||
GetCursorLimited(client, 100.0, WallBuilder[client].origin, Filter_IgnorePlayer);
|
||||
PrintToChat(client, "\x04[Hats]\x01 New Wall Started. End with \x05/wall build\x01 or \x04/wall cancel\x01");
|
||||
PrintToChat(client, "\x04[Hats]\x01 Mode: \x05Scale\x01");
|
||||
PrintToChat(client, "\x04[Editor]\x01 New Wall Started. End with \x05/wall build\x01 or \x04/wall cancel\x01");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Mode: \x05Scale\x01");
|
||||
}
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
public Action Command_ManageWalls(int client, int args) {
|
||||
if(args == 0) {
|
||||
PrintToChat(client, "\x04[Hats]\x01 Created Walls: \x05%d\x01", createdWalls.Length);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Created Walls: \x05%d\x01", createdWalls.Length);
|
||||
for(int i = 1; i <= createdWalls.Length; i++) {
|
||||
GlowWall(i, GLOW_WHITE, 20.0);
|
||||
}
|
||||
|
@ -332,22 +526,36 @@ public Action Command_ManageWalls(int client, int args) {
|
|||
// Remove frozen flag from user, as some modes use this
|
||||
int flags = GetEntityFlags(client) & ~FL_FROZEN;
|
||||
SetEntityFlags(client, flags);
|
||||
|
||||
int id = WallBuilder[client].Build();
|
||||
if(id == -1) {
|
||||
PrintToChat(client, "\x04[Hats]\x01 Wall Creation: \x04Error\x01");
|
||||
} else if(id == -2) {
|
||||
PrintToChat(client, "\x04[Hats]\x01 Wall Edit: \x04Complete\x01");
|
||||
} else if(id == -3) {
|
||||
PrintToChat(client, "\x04[Hats]\x01 Entity Edit: \x04Complete\x01");
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Hats]\x01 Wall Creation: \x05Wall #%d Created\x01", id + 1);
|
||||
|
||||
int entity;
|
||||
CompleteType result = WallBuilder[client].Create(entity);
|
||||
switch(result) {
|
||||
case Complete_WallSuccess: {
|
||||
if(entity > 0)
|
||||
PrintToChat(client, "\x04[Editor]\x01 Wall Creation: \x05Wall #%d Created\x01", entity + 1);
|
||||
else
|
||||
PrintToChat(client, "\x04[Editor]\x01 Wall Edit: \x04Complete\x01");
|
||||
}
|
||||
case Complete_PropSpawned:
|
||||
PrintToChat(client, "\x04[Editor]\x01 Prop Spawned: \x04%d\x01", entity);
|
||||
|
||||
case Complete_EditSuccess:
|
||||
PrintToChat(client, "\x04[Editor]\x01 Entity Edited: \x04%d\x01", entity);
|
||||
|
||||
default:
|
||||
PrintToChat(client, "\x04[Editor]\x01 Unknown result");
|
||||
}
|
||||
} else if(StrEqual(arg1, "cancel")) {
|
||||
int flags = GetEntityFlags(client) & ~FL_FROZEN;
|
||||
SetEntityFlags(client, flags);
|
||||
WallBuilder[client].Cancel();
|
||||
PrintToChat(client, "\x04[Hats]\x01 Wall Creation: \x04Cancelled\x01");
|
||||
if(WallBuilder[client].flags & Edit_Preview)
|
||||
PrintToChat(client, "\x04[Editor]\x01 Prop Spawer: \x04Done\x01");
|
||||
else if(WallBuilder[client].flags & Edit_WallCreator) {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Wall Creation: \x04Cancelled\x01");
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Editor]\x01 Entity Edit: \x04Cancelled\x01");
|
||||
}
|
||||
} else if(StrEqual(arg1, "export")) {
|
||||
// TODO: support exp #id
|
||||
float origin[3], angles[3], size[3];
|
||||
|
@ -372,29 +580,29 @@ public Action Command_ManageWalls(int client, int args) {
|
|||
if(WallBuilder[client].IsActive() && args == 1) {
|
||||
int entity = WallBuilder[client].entity;
|
||||
if(IsValidEntity(entity)) {
|
||||
PrintToChat(client, "\x04[Hats]\x01 You are not editing any existing entity, use \x05/wall cancel\x01 to stop or \x05/wall delete <id/all>");
|
||||
PrintToChat(client, "\x04[Editor]\x01 You are not editing any existing entity, use \x05/wall cancel\x01 to stop or \x05/wall delete <id/all>");
|
||||
} else if(entity > MaxClients) {
|
||||
RemoveEntity(entity);
|
||||
WallBuilder[client].Reset();
|
||||
PrintToChat(client, "\x04[Hats]\x01 Deleted current entity");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Deleted current entity");
|
||||
} else {
|
||||
PrintToChat(client, "\x04[Hats]\x01 Cannot delete player entities.");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Cannot delete player entities.");
|
||||
}
|
||||
} else if(StrEqual(arg2, "all")) {
|
||||
int walls = createdWalls.Length;
|
||||
for(int i = 1; i <= createdWalls.Length; i++) {
|
||||
DeleteWall(i);
|
||||
}
|
||||
PrintToChat(client, "\x04[Hats]\x01 Deleted \x05%d\x01 Walls", walls);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Deleted \x05%d\x01 Walls", walls);
|
||||
} else {
|
||||
int id = GetWallId(client, arg2);
|
||||
if(id > -1) {
|
||||
DeleteWall(id);
|
||||
PrintToChat(client, "\x04[Hats]\x01 Deleted Wall: \x05#%d\x01", id);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Deleted Wall: \x05#%d\x01", id);
|
||||
}
|
||||
}
|
||||
} else if(StrEqual(arg1, "create")) {
|
||||
ReplyToCommand(client, "\x04[Hats]\x01 Syntax: /mkwall [size x] [size y] [size z]");
|
||||
ReplyToCommand(client, "\x04[Editor]\x01 Syntax: /mkwall [size x] [size y] [size z]");
|
||||
} else if(StrEqual(arg1, "toggle")) {
|
||||
if(StrEqual(arg2, "all")) {
|
||||
int walls = createdWalls.Length;
|
||||
|
@ -403,20 +611,20 @@ public Action Command_ManageWalls(int client, int args) {
|
|||
AcceptEntityInput(entity, "Toggle");
|
||||
GlowWall(i, GLOW_BLUE);
|
||||
}
|
||||
PrintToChat(client, "\x04[Hats]\x01 Toggled \x05%d\x01 walls", walls);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Toggled \x05%d\x01 walls", walls);
|
||||
} else {
|
||||
int id = GetWallId(client, arg2);
|
||||
if(id > -1) {
|
||||
int entity = GetWallEntity(id);
|
||||
AcceptEntityInput(entity, "Toggle");
|
||||
GlowWall(id, GLOW_BLUE);
|
||||
PrintToChat(client, "\x04[Hats]\x01 Toggled Wall: \x05#%d\x01", id);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Toggled Wall: \x05#%d\x01", id);
|
||||
}
|
||||
}
|
||||
} else if(StrEqual(arg1, "filter")) {
|
||||
if(args < 3) {
|
||||
ReplyToCommand(client, "\x04[Hats]\x01 Syntax: \x05/walls filter <id/all> <filter type>\x04");
|
||||
ReplyToCommand(client, "\x04[Hats]\x01 Valid filters: \x05player");
|
||||
ReplyToCommand(client, "\x04[Editor]\x01 Syntax: \x05/walls filter <id/all> <filter type>\x04");
|
||||
ReplyToCommand(client, "\x04[Editor]\x01 Valid filters: \x05player");
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
|
@ -430,13 +638,13 @@ public Action Command_ManageWalls(int client, int args) {
|
|||
int entity = GetWallEntity(i);
|
||||
AcceptEntityInput(entity, "SetExcluded");
|
||||
}
|
||||
PrintToChat(client, "\x04[Hats]\x01 Set %d walls' filter to \x05%s\x01", walls, arg3);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Set %d walls' filter to \x05%s\x01", walls, arg3);
|
||||
} else {
|
||||
int id = GetWallId(client, arg2);
|
||||
if(id > -1) {
|
||||
int entity = GetWallEntity(id);
|
||||
AcceptEntityInput(entity, "SetExcluded");
|
||||
PrintToChat(client, "\x04[Hats]\x01 Set wall #%d filter to \x05%s\x01", id, arg3);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Set wall #%d filter to \x05%s\x01", id, arg3);
|
||||
}
|
||||
}
|
||||
} else if(StrEqual(arg1, "edit")) {
|
||||
|
@ -444,31 +652,30 @@ public Action Command_ManageWalls(int client, int args) {
|
|||
if(id > -1) {
|
||||
int entity = GetWallEntity(id);
|
||||
WallBuilder[client].Import(entity);
|
||||
PrintToChat(client, "\x04[Hats]\x01 Editing wall \x05%d\x01. End with \x05/wall done\x01 or \x04/wall cancel\x01", id);
|
||||
PrintToChat(client, "\x04[Hats]\x01 Mode: \x05Scale\x01");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Editing wall \x05%d\x01. End with \x05/wall done\x01 or \x04/wall cancel\x01", id);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Mode: \x05Scale\x01");
|
||||
}
|
||||
} else if(StrEqual(arg1, "edite") || (arg1[0] == 'c' && arg1[1] == 'u')) {
|
||||
int index = GetLookingEntity(client, Filter_ValidHats); //GetClientAimTarget(client, false);
|
||||
if(index > 0) {
|
||||
WallBuilder[client].Import(index, false, MOVE_ORIGIN);
|
||||
WallBuilder[client].canScale = false;
|
||||
char classname[32];
|
||||
char targetname[32];
|
||||
GetEntityClassname(index, classname, sizeof(classname));
|
||||
GetEntPropString(index, Prop_Data, "m_target", targetname, sizeof(targetname));
|
||||
PrintToChat(client, "\x04[Hats]\x01 Editing entity \x05%d (%s) [%s]\x01. End with \x05/wall done\x01", index, classname, targetname);
|
||||
PrintToChat(client, "\x04[Hats]\x01 Mode: \x05Move & Rotate\x01");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Editing entity \x05%d (%s) [%s]\x01. End with \x05/wall done\x01", index, classname, targetname);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Mode: \x05Move & Rotate\x01");
|
||||
} else {
|
||||
ReplyToCommand(client, "\x04[Hats]\x01 Invalid or non existent entity");
|
||||
ReplyToCommand(client, "\x04[Editor]\x01 Invalid or non existent entity");
|
||||
}
|
||||
} else if(StrEqual(arg1, "copy")) {
|
||||
if(WallBuilder[client].IsActive()) {
|
||||
int oldEntity = WallBuilder[client].entity;
|
||||
if(oldEntity == INVALID_ENT_REFERENCE) {
|
||||
PrintToChat(client, "\x04[Hats]\x01 Finish editing your wall first: \x05/wall done\x01 or \x04/wall cancel\x01");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Finish editing your wall first: \x05/wall done\x01 or \x04/wall cancel\x01");
|
||||
} else {
|
||||
int entity = WallBuilder[client].Copy();
|
||||
PrintToChat(client, "\x04[Hats]\x01 Editing copy \x05%d\x01 of entity \x05%d\x01. End with \x05/edit done\x01 or \x04/edit cancel\x01", entity, oldEntity);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Editing copy \x05%d\x01 of entity \x05%d\x01. End with \x05/edit done\x01 or \x04/edit cancel\x01", entity, oldEntity);
|
||||
}
|
||||
} else {
|
||||
int id = GetWallId(client, arg2);
|
||||
|
@ -476,8 +683,8 @@ public Action Command_ManageWalls(int client, int args) {
|
|||
int entity = GetWallEntity(id);
|
||||
WallBuilder[client].Import(entity, true);
|
||||
GetCursorLimited(client, 100.0, WallBuilder[client].origin, Filter_IgnorePlayer);
|
||||
PrintToChat(client, "\x04[Hats]\x01 Editing copy of wall \x05%d\x01. End with \x05/wall build\x01 or \x04/wall cancel\x01", id);
|
||||
PrintToChat(client, "\x04[Hats]\x01 Mode: \x05Scale\x01");
|
||||
PrintToChat(client, "\x04[Editor]\x01 Editing copy of wall \x05%d\x01. End with \x05/wall build\x01 or \x04/wall cancel\x01", id);
|
||||
PrintToChat(client, "\x04[Editor]\x01 Mode: \x05Scale\x01");
|
||||
}
|
||||
}
|
||||
} else if(StrEqual(arg1, "list")) {
|
||||
|
@ -486,7 +693,7 @@ public Action Command_ManageWalls(int client, int args) {
|
|||
ReplyToCommand(client, "Wall #%d - EntIndex: %d", i, EntRefToEntIndex(entity));
|
||||
}
|
||||
} else {
|
||||
ReplyToCommand(client, "\x04[Hats]\x01 See console for list of commands");
|
||||
ReplyToCommand(client, "\x04[Editor]\x01 See console for list of commands");
|
||||
GetCmdArg(0, arg1, sizeof(arg1));
|
||||
PrintToConsole(client, "%s done / build - Finishes editing, creates wall if making wall", arg1);
|
||||
PrintToConsole(client, "%s cancel - Cancels editing (for entity edits is same as done)", arg1);
|
||||
|
@ -506,13 +713,13 @@ int GetWallId(int client, const char[] arg) {
|
|||
if(StringToIntEx(arg, id) > 0 && id > 0 && id <= createdWalls.Length) {
|
||||
int entity = GetWallEntity(id);
|
||||
if(!IsValidEntity(entity)) {
|
||||
ReplyToCommand(client, "\x04[Hats]\x01 The wall with specified id no longer exists.");
|
||||
ReplyToCommand(client, "\x04[Editor]\x01 The wall with specified id no longer exists.");
|
||||
createdWalls.Erase(id - 1);
|
||||
return -2;
|
||||
}
|
||||
return id;
|
||||
} else {
|
||||
ReplyToCommand(client, "\x04[Hats]\x01 Invalid wall id, must be between 0 - %d", createdWalls.Length - 1 );
|
||||
ReplyToCommand(client, "\x04[Editor]\x01 Invalid wall id, must be between 0 - %d", createdWalls.Length - 1 );
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
@ -567,7 +774,7 @@ void DeleteWall(int id) {
|
|||
BuildPath(Path_SM, sPath, sizeof(sPath), "data/exports/%s.cfg", currentMap);
|
||||
File file = OpenFile(sPath, "w");
|
||||
if(file == null) {
|
||||
PrintToServer("[Hats] Export: Cannot open \"%s\", cant write", sPath);
|
||||
PrintToServer("[Editor] Export: Cannot open \"%s\", cant write", sPath);
|
||||
}
|
||||
|
||||
PrintWriteLine(client, file, "{");
|
||||
|
@ -600,59 +807,4 @@ void PrintWriteLine(int client, File file, const char[] format, any ...) {
|
|||
if(file != null)
|
||||
file.WriteLine(line);
|
||||
PrintToChat(client, line);
|
||||
}
|
||||
|
||||
enum struct WallModelSizeEntry {
|
||||
char name[32];
|
||||
char model[64];
|
||||
}
|
||||
enum struct WallModelEntry {
|
||||
char name[32];
|
||||
|
||||
WallModelSizeEntry size1;
|
||||
WallModelSizeEntry size2;
|
||||
WallModelSizeEntry size3;
|
||||
}
|
||||
ArrayList wallModels;
|
||||
|
||||
void LoadModels() {
|
||||
if(wallModels != null) delete wallModels;
|
||||
wallModels = new ArrayList(sizeof(WallModelEntry));
|
||||
KeyValues kv = new KeyValues("WallData");
|
||||
|
||||
char sPath[PLATFORM_MAX_PATH];
|
||||
BuildPath(Path_SM, sPath, sizeof(sPath), "data/walls_data.cfg");
|
||||
|
||||
if(!FileExists(sPath) || !kv.ImportFromFile(sPath)) {
|
||||
delete kv;
|
||||
PrintToServer("[FTT] Could not load phrase list from data/walls_data.cfg");
|
||||
return;
|
||||
}
|
||||
// TODO: implement models to spawn
|
||||
// char name[32];
|
||||
// Go through all the words:
|
||||
// kv.GotoFirstSubKey();
|
||||
// int i = 0;
|
||||
// char buffer[4];
|
||||
// do {
|
||||
// kv.GetSectionName(name, sizeof(name));
|
||||
// for(;;) {
|
||||
// IntToString(++i, buffer, sizeof(buffer));
|
||||
// kv.GetString(buffer, phrase, MAX_PHRASE_LENGTH, "_null");
|
||||
// if(strcmp(phrase, "_null") == 0) break;
|
||||
// phrases.PushString(phrase);
|
||||
// }
|
||||
// i = 0;
|
||||
// if(StrEqual(word, "_full message phrases")) {
|
||||
// fullMessagePhraseList = phrases.Clone();
|
||||
// continue;
|
||||
// }
|
||||
// #if defined DEBUG_PHRASE_LOAD
|
||||
// PrintToServer("Loaded %d phrases for word \"%s\"", phrases.Length, word);
|
||||
// #endif
|
||||
// REPLACEMENT_PHRASES.SetValue(word, phrases.Clone(), true);
|
||||
// } while (kv.GotoNextKey(false));
|
||||
|
||||
delete kv;
|
||||
}
|
||||
|
||||
}
|
|
@ -913,8 +913,8 @@ stock void GlowPoint(const float pos[3], float lifetime = 5.0) {
|
|||
CreateTimer(lifetime, Timer_KillEntity, entity);
|
||||
}
|
||||
|
||||
stock void GlowEntity(int entity, float lifetime = 10.0) {
|
||||
L4D2_SetEntityGlow(entity, L4D2Glow_Constant, 10000, 0, _glowColor, false);
|
||||
stock void GlowEntity(int entity, float lifetime = 10.0, int glowColor[3] = _glowColor) {
|
||||
L4D2_SetEntityGlow(entity, L4D2Glow_Constant, 10000, 0, glowColor, false);
|
||||
CreateTimer(lifetime, Timer_ClearGlow, EntIndexToEntRef(entity));
|
||||
}
|
||||
|
||||
|
|
|
@ -38,6 +38,13 @@ ConVar cvar_sm_hats_max_distance;
|
|||
|
||||
TopMenu g_topMenu;
|
||||
|
||||
int g_lastCategoryIndex[MAXPLAYERS+1];
|
||||
int g_lastItemIndex[MAXPLAYERS+1];
|
||||
int g_lastShowedHint[MAXPLAYERS+1];
|
||||
bool g_isSearchActive[MAXPLAYERS+1];
|
||||
|
||||
char g_currentMap[64];
|
||||
|
||||
#include <hats/walls.sp>
|
||||
#include <hats/hats.sp>
|
||||
#include <hats/hat_presets.sp>
|
||||
|
@ -62,6 +69,7 @@ public void OnPluginStart() {
|
|||
}
|
||||
|
||||
createdWalls = new ArrayList();
|
||||
g_spawnedItems = new ArrayList(2);
|
||||
|
||||
LoadTranslations("common.phrases");
|
||||
HookEvent("player_entered_checkpoint", OnEnterSaferoom);
|
||||
|
@ -75,6 +83,7 @@ public void OnPluginStart() {
|
|||
RegAdminCmd("sm_mkwall", Command_MakeWall, ADMFLAG_CHEATS);
|
||||
RegAdminCmd("sm_walls", Command_ManageWalls, ADMFLAG_CHEATS);
|
||||
RegAdminCmd("sm_wall", Command_ManageWalls, ADMFLAG_CHEATS);
|
||||
RegAdminCmd("sm_prop", Command_Props, ADMFLAG_CHEATS);
|
||||
RegConsoleCmd("sm_hatp", Command_DoAHatPreset);
|
||||
|
||||
cvar_sm_hats_blacklist_enabled = CreateConVar("sm_hats_blacklist_enabled", "1", "Is the prop blacklist enabled", FCVAR_NONE, true, 0.0, true, 1.0);
|
||||
|
@ -106,6 +115,11 @@ public void OnPluginStart() {
|
|||
}
|
||||
|
||||
LoadPresets();
|
||||
|
||||
TopMenu topMenu;
|
||||
if (LibraryExists("adminmenu") && ((topMenu = GetAdminTopMenu()) != null)) {
|
||||
OnAdminMenuReady(topMenu);
|
||||
}
|
||||
}
|
||||
|
||||
public void OnLibraryRemoved(const char[] name) {
|
||||
|
@ -116,23 +130,6 @@ public void OnLibraryRemoved(const char[] name) {
|
|||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void Event_ItemPickup(Event event, const char[] name, bool dontBroadcast) {
|
||||
int client = GetClientOfUserId(event.GetInt("userid"));
|
||||
// Check if an item picked up a user's hat and do nothing...
|
||||
// for(int slot = 0; slot <= 5; slot++) {
|
||||
// int wpn = GetPlayerWeaponSlot(client, slot);
|
||||
// for(int i = 1; i <= MaxClients; i++) {
|
||||
// if(i != client && IsClientConnected(i) && IsClientInGame(i) && !IsFakeClient(i)) {
|
||||
// int hat = GetHat(i);
|
||||
// if(hat == wpn) {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
|
||||
public void OnEnterSaferoom(Event event, const char[] name, bool dontBroadcast) {
|
||||
int userid = event.GetInt("userid");
|
||||
int client = GetClientOfUserId(userid);
|
||||
|
@ -172,12 +169,6 @@ Action Timer_PlaceHat(Handle h, int userid) {
|
|||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
Action Timer_Kill(Handle h, int entity) {
|
||||
if(IsValidEntity(entity))
|
||||
RemoveEntity(entity);
|
||||
return Plugin_Handled;
|
||||
}
|
||||
|
||||
// Tries to find a valid location at user's cursor, avoiding placing into solid walls (such as invisible walls) or objects
|
||||
stock bool GetSmartCursorLocation(int client, float outPos[3]) {
|
||||
float start[3], angle[3], ceilPos[3], wallPos[3], normal[3];
|
||||
|
@ -199,7 +190,7 @@ stock bool GetSmartCursorLocation(int client, float outPos[3]) {
|
|||
bool ceilCollided = TR_DidHit();
|
||||
bool ceilOK = !TR_AllSolid();
|
||||
TR_GetEndPosition(ceilPos);
|
||||
float distCeil = GetVectorDistance(outPos, ceilPos, true);
|
||||
// float distCeil = GetVectorDistance(outPos, ceilPos, true);
|
||||
|
||||
// Find a suitable position backwards
|
||||
angle[0] = 70.0;
|
||||
|
@ -334,7 +325,7 @@ void CheckKill(int ref, int client) {
|
|||
Action Timer_PropYeetEnd(Handle h, DataPack pack) {
|
||||
pack.Reset();
|
||||
int realEnt = EntRefToEntIndex(pack.ReadCell());
|
||||
int visibleEnt = EntRefToEntIndex(pack.ReadCell());
|
||||
// int visibleEnt = EntRefToEntIndex(pack.ReadCell());
|
||||
// if(IsValidEntity(visibleEnt)) {
|
||||
// float pos[3], ang[3];
|
||||
// GetEntPropVector(visibleEnt, Prop_Send, "m_vecOrigin", pos);
|
||||
|
@ -488,7 +479,7 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
ClearParent(entity);
|
||||
|
||||
// If hat is not a player, we teleport them to the void (0, 0, 0)
|
||||
// Otherwise, we just simply dismount the player while hatter is on ladder
|
||||
// Ostherwise, we just simply dismount the player while hatter is on ladder
|
||||
if(entity >= MaxClients)
|
||||
TeleportEntity(entity, EMPTY_ANG, NULL_VECTOR, NULL_VECTOR);
|
||||
if(visibleEntity > 0) {
|
||||
|
@ -584,30 +575,35 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
bool allowMove = true;
|
||||
switch(WallBuilder[client].mode) {
|
||||
case MOVE_ORIGIN: {
|
||||
|
||||
SetWeaponDelay(client, 0.5);
|
||||
|
||||
bool isRotate;
|
||||
int flags = GetEntityFlags(client);
|
||||
if(buttons & IN_USE) {
|
||||
PrintCenterText(client, "%.1f %.1f %.1f", WallBuilder[client].angles[0], WallBuilder[client].angles[1], WallBuilder[client].angles[2]);
|
||||
isRotate = true;
|
||||
SetEntityFlags(client, flags |= FL_FROZEN);
|
||||
if(buttons & IN_ATTACK) WallBuilder[client].CycleAxis(client, tick);
|
||||
else if(buttons & IN_ATTACK2) WallBuilder[client].CycleSnapAngle(client, tick);
|
||||
|
||||
// Rotation control:
|
||||
if(tick - cmdThrottle[client] > 0.20) {
|
||||
if(WallBuilder[client].axis == 0) {
|
||||
if(mouse[1] > 10) WallBuilder[client].angles[0] += WallBuilder[client].snapAngle;
|
||||
else if(mouse[1] < -10) WallBuilder[client].angles[0] -= WallBuilder[client].snapAngle;
|
||||
} else if(WallBuilder[client].axis == 1) {
|
||||
if(mouse[0] > 10) WallBuilder[client].angles[1] += WallBuilder[client].snapAngle;
|
||||
else if(mouse[0] < -10) WallBuilder[client].angles[1] -= WallBuilder[client].snapAngle;
|
||||
} else {
|
||||
if(mouse[1] > 10) WallBuilder[client].angles[2] += WallBuilder[client].snapAngle;
|
||||
else if(mouse[1] < -10) WallBuilder[client].angles[2] -= WallBuilder[client].snapAngle;
|
||||
if(buttons & IN_USE && ~buttons & IN_ZOOM) {
|
||||
if(buttons & IN_SPEED) {
|
||||
WallBuilder[client].ToggleCollision(client, tick);
|
||||
} else {
|
||||
PrintCenterText(client, "%.1f %.1f %.1f", WallBuilder[client].angles[0], WallBuilder[client].angles[1], WallBuilder[client].angles[2]);
|
||||
isRotate = true;
|
||||
SetEntityFlags(client, flags |= FL_FROZEN);
|
||||
if(buttons & IN_ATTACK) WallBuilder[client].CycleAxis(client, tick);
|
||||
else if(buttons & IN_ATTACK2) WallBuilder[client].CycleSnapAngle(client, tick);
|
||||
|
||||
// Rotation control:
|
||||
if(tick - cmdThrottle[client] > 0.20) {
|
||||
if(WallBuilder[client].axis == 0) {
|
||||
if(mouse[1] > 10) WallBuilder[client].angles[0] += WallBuilder[client].snapAngle;
|
||||
else if(mouse[1] < -10) WallBuilder[client].angles[0] -= WallBuilder[client].snapAngle;
|
||||
} else if(WallBuilder[client].axis == 1) {
|
||||
if(mouse[0] > 10) WallBuilder[client].angles[1] += WallBuilder[client].snapAngle;
|
||||
else if(mouse[0] < -10) WallBuilder[client].angles[1] -= WallBuilder[client].snapAngle;
|
||||
} else {
|
||||
if(mouse[1] > 10) WallBuilder[client].angles[2] += WallBuilder[client].snapAngle;
|
||||
else if(mouse[1] < -10) WallBuilder[client].angles[2] -= WallBuilder[client].snapAngle;
|
||||
}
|
||||
cmdThrottle[client] = tick;
|
||||
}
|
||||
cmdThrottle[client] = tick;
|
||||
}
|
||||
} else {
|
||||
// Move position
|
||||
|
@ -620,9 +616,6 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
flags = flags & ~FL_FROZEN;
|
||||
SetEntityFlags(client, flags);
|
||||
}
|
||||
if(buttons & IN_SPEED) {
|
||||
WallBuilder[client].ToggleCollision(client, tick);
|
||||
}
|
||||
|
||||
GetCursorLimited2(client, WallBuilder[client].moveDistance, WallBuilder[client].origin, Filter_IgnorePlayerAndWall, WallBuilder[client].hasCollision);
|
||||
}
|
||||
|
@ -659,10 +652,44 @@ public Action OnPlayerRunCmd(int client, int& buttons, int& impulse, float vel[3
|
|||
WallBuilder[client].CalculateMins();
|
||||
}
|
||||
}
|
||||
case COLOR: {
|
||||
SetWeaponDelay(client, 0.5);
|
||||
PrintCenterText(client, "%d %d %d %d", WallBuilder[client].color[0], WallBuilder[client].color[1], WallBuilder[client].color[2], WallBuilder[client].color[3]);
|
||||
if(buttons & IN_USE) {
|
||||
WallBuilder[client].CycleColorComponent(client, tick);
|
||||
} else if(buttons & IN_ATTACK) {
|
||||
WallBuilder[client].color[WallBuilder[client].colorIndex]--;
|
||||
if(WallBuilder[client].color[WallBuilder[client].colorIndex] < 0) {
|
||||
WallBuilder[client].color[WallBuilder[client].colorIndex] = 0;
|
||||
}
|
||||
WallBuilder[client].UpdateEntity();
|
||||
allowMove = false;
|
||||
} else if(buttons & IN_ATTACK2) {
|
||||
WallBuilder[client].color[WallBuilder[client].colorIndex]++;
|
||||
if(WallBuilder[client].color[WallBuilder[client].colorIndex] > 255) {
|
||||
WallBuilder[client].color[WallBuilder[client].colorIndex] = 255;
|
||||
}
|
||||
WallBuilder[client].UpdateEntity();
|
||||
allowMove = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch(buttons) {
|
||||
case IN_RELOAD: WallBuilder[client].CycleMode(client, tick); // R: Cycle forward
|
||||
if(buttons & IN_RELOAD)
|
||||
WallBuilder[client].CycleMode(client, tick); // R: Cycle forward
|
||||
else if(WallBuilder[client].flags & Edit_Preview && tick - cmdThrottle[client] >= 0.25 && buttons & IN_ZOOM) {
|
||||
if(buttons & IN_SPEED) {
|
||||
int entity;
|
||||
WallBuilder[client].Create(entity);
|
||||
int index = g_spawnedItems.Push(EntIndexToEntRef(entity));
|
||||
g_spawnedItems.Set(index, GetClientUserId(client), 1);
|
||||
} else if(buttons & IN_DUCK) {
|
||||
WallBuilder[client].CycleBuildType(client);
|
||||
} else {
|
||||
WallBuilder[client].Cancel();
|
||||
CPrintToChat(client, "\x04[Editor]\x01 Cancelled.");
|
||||
}
|
||||
cmdThrottle[client] = tick;
|
||||
}
|
||||
|
||||
WallBuilder[client].Draw(BUILDER_COLOR, 0.1, 0.1);
|
||||
|
@ -723,6 +750,10 @@ public void Event_PlayerSpawn(Event event, const char[] name, bool dontBroadcast
|
|||
public void OnClientDisconnect(int client) {
|
||||
tempGod[client] = false;
|
||||
WallBuilder[client].Reset();
|
||||
g_isSearchActive[client] = false;
|
||||
g_lastCategoryIndex[client] = 0;
|
||||
g_lastItemIndex[client] = 0;
|
||||
g_lastShowedHint[client] = 0;
|
||||
hatData[client].yeetGroundTimer = null;
|
||||
ClearHat(client, true);
|
||||
}
|
||||
|
@ -747,12 +778,14 @@ public void OnMapStart() {
|
|||
cmdThrottle[i] = 0.0;
|
||||
tempGod[i] = false;
|
||||
}
|
||||
GetCurrentMap(g_currentMap, sizeof(g_currentMap));
|
||||
NavAreas = GetSpawnLocations();
|
||||
}
|
||||
|
||||
|
||||
public void OnMapEnd() {
|
||||
delete NavAreas;
|
||||
g_spawnedItems.Clear();
|
||||
for(int i = 1; i <= createdWalls.Length; i++) {
|
||||
if(hatData[i].yeetGroundTimer != null) {
|
||||
delete hatData[i].yeetGroundTimer;
|
||||
|
@ -762,6 +795,8 @@ public void OnMapEnd() {
|
|||
}
|
||||
createdWalls.Clear();
|
||||
ClearHats();
|
||||
UnloadCategories();
|
||||
UnloadSave();
|
||||
}
|
||||
public void OnPluginEnd() {
|
||||
ClearHats();
|
||||
|
@ -771,6 +806,14 @@ public void OnPluginEnd() {
|
|||
SetEntityFlags(i, flags);
|
||||
}
|
||||
}
|
||||
if(g_spawnedItems != null) {
|
||||
for(int i = 0; i < g_spawnedItems.Length; i++) {
|
||||
int ref = g_spawnedItems.Get(i);
|
||||
RemoveEntity(ref);
|
||||
}
|
||||
delete g_spawnedItems;
|
||||
}
|
||||
TriggerInput("prop_preview", "Kill");
|
||||
}
|
||||
|
||||
public bool TraceEntityFilterPlayer(int entity, int contentsMask, any data) {
|
||||
|
@ -780,7 +823,6 @@ public bool TraceEntityFilterPlayer(int entity, int contentsMask, any data) {
|
|||
return entity != data;
|
||||
}
|
||||
|
||||
|
||||
int GetLookingEntity(int client, TraceEntityFilter filter) {
|
||||
static float pos[3], ang[3];
|
||||
GetClientEyePosition(client, pos);
|
||||
|
@ -844,7 +886,16 @@ bool CheckBlacklist(int entity) {
|
|||
|
||||
////////////////////////////////
|
||||
|
||||
|
||||
stock void TriggerInput(const char[] targetName, const char[] input) {
|
||||
int entity = -1;
|
||||
char _targetName[32];
|
||||
while((entity = FindEntityByClassname(entity, "*")) != INVALID_ENT_REFERENCE) {
|
||||
GetEntPropString(entity, Prop_Data, "m_iName", _targetName, sizeof(_targetName));
|
||||
if(StrEqual(_targetName, targetName)) {
|
||||
AcceptEntityInput(entity, input);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
stock bool FindGround(const float start[3], float end[3]) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue