This commit is contained in:
Jackzie 2024-07-13 21:27:08 -05:00
parent fd2367f41f
commit 79d37bdd34
45 changed files with 5587 additions and 3877 deletions

View file

@ -50,7 +50,9 @@ stock void EntFire(const char[] name, const char[] input) {
}
}
void CreateCoinEntity(float pos[3]) {
// int ent = CreateProp("prop_dynamic", "")
}
void SetupEntities(bool blockers = true, bool props = true, bool portals = true) {
#if defined DEBUG_BLOCKERS

View file

@ -125,6 +125,12 @@ methodmap GuessWhoGame < BaseGame {
}
}
property int TargetCoinCount {
public get() {
return 8;
}
}
public void Start() {
}
@ -301,6 +307,14 @@ methodmap GuessWhoGame < BaseGame {
SDKUnhook(client, SDKHook_OnTakeDamageAlive, OnTakeDamageAlive);
SDKUnhook(client, SDKHook_WeaponEquip, OnWeaponEquip);
}
public void PopulateCoins() {
float pos[3];
for(int i = 0; i < this.TargetCoinCount; i++) {
movePoints.GetRandomPoint(pos);
}
}
}
stock bool ArePlayersJoining() {

View file

@ -13,13 +13,18 @@ Action Timer_RecordPoints(Handle h, int i) {
vecLastLocation[i] = meta.pos;
}
}
Game.MapTime++;
PrintHintText(i, "Points: %d / %d", movePoints.Length, MAX_VALID_LOCATIONS);
return Plugin_Continue;
}
bool firstCheckDone = false;
Action Timer_WaitForPlayers(Handle h) {
if(!isEnabled) return Plugin_Stop;
if(!isEnabled) {
waitTimer = null;
return Plugin_Stop;
}
if(!ArePlayersJoining()) {
Game.Debug("No players pending, ready to go");
if(!firstCheckDone) {
@ -28,6 +33,7 @@ Action Timer_WaitForPlayers(Handle h) {
} else {
firstCheckDone = false;
InitGamemode();
waitTimer = null;
return Plugin_Stop;
}
}

View file

@ -1 +0,0 @@
native bool SpawnSchematic(const char name[32], const float pos[3], const float angles[3] = NULL_VECTOR);

View file

@ -1,7 +1,6 @@
int BUILDER_COLOR[4] = { 0, 255, 0, 235 };
int GLOW_BLUE[4] = { 3, 148, 252 };
int GLOW_RED_ALPHA[4] = { 255, 0, 0, 235 };
int GLOW_RED[3] = { 255, 0, 0};
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 };
@ -27,26 +26,21 @@ char MODE_NAME[5][] = {
"Freelook"
}
enum editFlag {
enum {
Edit_None,
Edit_Copy = 1,
Edit_Preview = 2,
Edit_WallCreator = 4
Edit_WallCreator = 4,
Edit_Manager = 8
}
enum buildType {
Build_Solid,
Build_Physics,
Build_NonSolid,
// TODO: Build_Weapon (spawn as weapon?)
}
enum CompleteType {
Complete_WallSuccess,
Complete_WallError,
Complete_PropSpawned,
Complete_PropError,
Complete_EditSuccess
}
enum StackerDirection {
Stack_Off,
@ -88,6 +82,7 @@ enum struct EditorData {
int colorIndex;
int axis;
int snapAngle;
float rotateSpeed;
int moveSpeed;
float moveDistance;
int entity;
@ -97,11 +92,14 @@ enum struct EditorData {
editMode mode;
buildType buildType;
editFlag flags;
int flags;
PrivateForward callback;
bool isEditCallback;
void Reset(bool initial = false) {
// Clear preview entity
if(this.entity != INVALID_ENT_REFERENCE && this.flags & Edit_Preview && IsValidEntity(this.entity)) {
if(this.entity != INVALID_ENT_REFERENCE && (this.flags & Edit_Preview) && IsValidEntity(this.entity)) {
RemoveEntity(this.entity);
}
this.stackerDirection = Stack_Off;
@ -111,12 +109,13 @@ enum struct EditorData {
this.size[0] = this.size[1] = this.size[2] = 5.0;
this.angles[0] = this.angles[1] = this.angles[2] = 0.0;
this.colorIndex = 0;
this.axis = 1;
this.axis = 0;
this.moveDistance = 200.0;
this.flags = Edit_None;
this.classname[0] = '\0';
this.CalculateMins();
this.SetMode(INACTIVE);
this.rotateSpeed = 0.1;
// Settings that don't get reset on new spawns:
if(initial) {
this.color[0] = this.color[1] = this.color[2] = this.color[3] = 255;
@ -138,6 +137,12 @@ enum struct EditorData {
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 {
if(this.snapAngle != 1) {
this.angles[0] = RoundToNearestInterval(this.angles[0], this.snapAngle);
this.angles[1] = RoundToNearestInterval(this.angles[1], this.snapAngle);
this.angles[2] = RoundToNearestInterval(this.angles[2], this.snapAngle);
}
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);
@ -147,9 +152,6 @@ enum struct EditorData {
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);
}
@ -178,6 +180,10 @@ enum struct EditorData {
void SetName(const char[] name) {
strcopy(this.name, sizeof(this.name), name);
}
void SetCallback(PrivateForward callback, bool isEditCallback) {
this.callback = callback;
this.isEditCallback = isEditCallback;
}
void CycleMode() {
// Remove frozen state when cycling
@ -210,43 +216,43 @@ enum struct EditorData {
PrintToChat(this.client, "\x04[Editor]\x01 Mode: \x05%s\x01 (Press \x04RELOAD\x01 to change)", MODE_NAME[this.mode]);
}
void CycleStacker(float tick) {
if(tick - cmdThrottle[this.client] <= 0.10) return;
void CycleStacker() {
int newDirection = view_as<int>(this.stackerDirection) + 1;
if(newDirection == view_as<int>(Stack_Down)) newDirection = 0;
this.stackerDirection = view_as<StackerDirection>(newDirection);
PrintToChat(this.client, "\x04[Editor]\x01 Stacker: %s\x01", STACK_DIRECTION_NAME[this.stackerDirection]);
cmdThrottle[this.client] = tick;
}
void ToggleCollision(float tick) {
if(tick - cmdThrottle[this.client] <= 0.25) return;
void ToggleCollision() {
this.hasCollision = !this.hasCollision
PrintToChat(this.client, "\x04[Editor]\x01 Collision: %s", ON_OFF_STRING[view_as<int>(this.hasCollision)]);
cmdThrottle[this.client] = tick;
}
void ToggleCollisionRotate(float tick) {
if(tick - cmdThrottle[this.client] <= 0.20) return;
void ToggleCollisionRotate() {
this.hasCollisionRotate = !this.hasCollisionRotate
PrintToChat(this.client, "\x04[Editor]\x01 Rotate with Collision: %s", ON_OFF_STRING[view_as<int>(this.hasCollisionRotate)]);
cmdThrottle[this.client] = tick;
}
void CycleAxis(float tick) {
if(tick - cmdThrottle[this.client] <= 0.1) return;
void CycleAxis() {
// if(tick - cmdThrottle[this.client] <= 0.1) return;
if(this.axis == 0) {
this.axis = 1;
PrintToChat(this.client, "\x04[Editor]\x01 Rotate Axis: \x05HEADING (Y)\x01");
} else if(this.axis == 1) {
this.axis = 2;
PrintToChat(this.client, "\x04[Editor]\x01 Rotate Axis: \x05PITCH (X)\x01");
PrintToChat(this.client, "\x04[Editor]\x01 Rotate Axis: \x05ROLL (Z)\x01");
} else {
this.axis = 0;
PrintToChat(this.client, "\x04[Editor]\x01 Rotate Axis: \x05ROLL (Z)\x01");
PrintToChat(this.client, "\x04[Editor]\x01 Rotate Axis: \x05PITCH AND HEADING (X, Y)\x01");
}
// cmdThrottle[this.client] = tick;
}
void IncrementAxis(int axis, int mouse) {
if(this.snapAngle == 1) {
this.angles[axis] += mouse * this.rotateSpeed;
} else {
if(mouse > 0) this.angles[axis] += this.snapAngle;
else if(mouse < 0) this.angles[axis] -= this.snapAngle;
}
cmdThrottle[this.client] = tick;
}
void CycleSnapAngle(float tick) {
@ -328,18 +334,38 @@ enum struct EditorData {
// Complete the edit, wall creation, or spawning
CompleteType Done(int& entity) {
CompleteType type;
if(this.flags & Edit_WallCreator) {
return this._FinishWall(entity) ? Complete_WallSuccess : Complete_WallError;
type = this._FinishWall(entity) ? Complete_WallSuccess : Complete_WallError;
} else if(this.flags & Edit_Preview) {
return this._FinishPreview(entity) ? Complete_PropSpawned : Complete_PropError;
type = this._FinishPreview(entity) ? Complete_PropSpawned : Complete_PropError;
} else {
// Is edit, do nothing, just reset
PrintHintText(this.client, "Edit Complete");
this.Reset();
entity = 0;
return Complete_EditSuccess;
type = Complete_EditSuccess;
}
if(this.callback) {
Call_StartForward(this.callback);
Call_PushCell(this.client);
Call_PushCell(entity);
Call_PushCell(type);
bool result;
Call_Finish(result);
// Cancel menu:
if(this.isEditCallback) delete this.callback;
if(this.isEditCallback || !result) {
// No native way to close a menu, so open a dummy menu and close it:
// Handler doesn't matter, no options are added
Menu menu = new Menu(Spawn_RootHandler);
menu.Display(this.client, 1);
} else {
delete this.callback;
}
}
return type;
}
bool _FinishWall(int& id) {
@ -569,7 +595,7 @@ enum struct EditorData {
DispatchKeyValue(entity, "targetname", "prop_preview");
DispatchKeyValue(entity, "solid", "0");
DispatchKeyValue(entity, "rendercolor", "255 128 255");
DispatchKeyValue(entity, "renderamt", "200");
DispatchKeyValue(entity, "renderamt", "255");
DispatchKeyValue(entity, "rendermode", "1");
TeleportEntity(entity, this.origin, NULL_VECTOR, NULL_VECTOR);
if(!DispatchSpawn(entity)) {
@ -583,8 +609,11 @@ enum struct EditorData {
return IsValidEntity(entity);
}
// Adds an existing entity to the editor, to move it.
// asWallCopy: to instead copy the wall's size and position (walls only)
/**
* Adds an existing entity to the editor, to move it.
* asWallCopy: to instead copy the wall's size and position (walls only)
* @deprecated
*/
void Import(int entity, bool asWallCopy = false, editMode mode = SCALE) {
this.Reset();
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", this.origin);
@ -599,6 +628,22 @@ enum struct EditorData {
this.SetMode(mode);
}
/**
* Imports an entity
*/
void ImportEntity(int entity, int flags = 0, editMode mode = SCALE) {
this.Reset();
this.flags = flags;
GetEntPropVector(entity, Prop_Send, "m_vecOrigin", this.origin);
GetEntPropVector(entity, Prop_Send, "m_angRotation", this.angles);
this.prevOrigin = this.origin;
this.prevAngles = this.angles;
GetEntPropVector(entity, Prop_Send, "m_vecMins", this.mins);
GetEntPropVector(entity, Prop_Send, "m_vecMaxs", this.size);
this.entity = entity;
this.SetMode(mode);
}
// Cancels the current placement. If the edit is a copy/preview, the entity is also deleted
// If entity is not a wall, it will be returned
void Cancel() {
@ -611,9 +656,22 @@ enum struct EditorData {
}
this.SetMode(INACTIVE);
PrintHintText(this.client, "Cancelled");
if(this.callback) {
delete this.callback;
}
// CPrintToChat(this.client, "\x04[Editor]\x01 Cancelled.");
}
}
void SendEditorMessage(int client, const char[] format, any ...) {
char message[256];
VFormat(message, sizeof(message), format, 3);
CPrintToChat(client, "\x04`[Editor]\x01 %s", message);
}
stock float RoundToNearestInterval(float value, int interval) {
return float(RoundFloat(value / float(interval)) * interval);
}
EditorData Editor[MAXPLAYERS+1];
Action OnWallClicked(int entity, int activator, int caller, UseType type, float value) {

View file

@ -43,7 +43,7 @@ int lastHatRequestTime[MAXPLAYERS+1];
HatInstance hatData[MAXPLAYERS+1];
StringMap g_HatPresets;
#define MAX_FORBIDDEN_CLASSNAMES 14
#define MAX_FORBIDDEN_CLASSNAMES 15
char FORBIDDEN_CLASSNAMES[MAX_FORBIDDEN_CLASSNAMES][] = {
"prop_door_rotating_checkpoint",
"env_physics_blocker",
@ -59,7 +59,8 @@ char FORBIDDEN_CLASSNAMES[MAX_FORBIDDEN_CLASSNAMES][] = {
// "infected",
"func_lod",
"func_door",
"prop_ragdoll"
"prop_ragdoll",
"move_rope"
};
#define MAX_FORBIDDEN_MODELS 2
@ -73,7 +74,7 @@ char FORBIDDEN_MODELS[MAX_FORBIDDEN_MODELS][] = {
// Classnames that should automatically trigger reverse infected
static char REVERSE_CLASSNAMES[MAX_REVERSE_CLASSNAMES][] = {
"infected",
"func_movelinear"
"func_movelinear",
};
Action Command_DoAHat(int client, int args) {

View file

@ -0,0 +1,122 @@
int Native_StartEdit(Handle plugin, int numParams) {
int client = GetNativeCell(1);
int entity = GetNativeCell(2);
Editor[client].Import(entity, false);
PrivateForward fwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell);
fwd.AddFunction(INVALID_HANDLE, GetNativeFunction(3));
Editor[client].SetCallback(fwd, true);
return 0;
}
int Native_StartSpawner(Handle plugin, int numParams) {
int client = GetNativeCell(1);
g_PropData[client].Selector.Cancel();
PrivateForward fwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell, Param_Cell);
fwd.AddFunction(INVALID_HANDLE, GetNativeFunction(2));
Editor[client].SetCallback(fwd, false);
ShowCategoryList(client, ROOT_CATEGORY);
return 0;
}
int Native_CancelEdit(Handle plugin, int numParams) {
int client = GetNativeCell(1);
Editor[client].Cancel();
return 0;
}
int Native_IsEditorActive(Handle plugin, int numParams) {
int client = GetNativeCell(1);
Editor[client].IsActive();
return 0;
}
int Native_StartSelector(Handle plugin, int numParams) {
int client = GetNativeCell(1);
int color[3] = { 0, 255, 0 };
PrivateForward fwd = new PrivateForward(ET_Single, Param_Cell, Param_Cell);
fwd.AddFunction(plugin, GetNativeFunction(2));
GetNativeArray(3, color, 3);
int limit = GetNativeCell(4);
g_PropData[client].Selector.Start(color, 0, limit);
g_PropData[client].Selector.SetOnEnd(fwd);
return 0;
}
int Native_CancelSelector(Handle plugin, int numParams) {
int client = GetNativeCell(1);
g_PropData[client].Selector.Cancel();
return 0;
}
int Native_IsSelectorActive(Handle plugin, int numParams) {
int client = GetNativeCell(1);
g_PropData[client].Selector.IsActive();
return 0;
}
int Native_Selector_Start(Handle plugin, int numParams) {
int client = GetNativeCell(1);
int color[3] = { 0, 255, 0 };
GetNativeArray(2, color, 3);
int flags = GetNativeCell(3);
int limit = GetNativeCell(4);
g_PropData[client].Selector.Start(color, flags, limit);
return 0;
}
int Native_Selector_GetCount(Handle plugin, int numParams) {
int client = GetNativeCell(1);
if(!g_PropData[client].Selector.IsActive()) {
return -1;
} else {
return g_PropData[client].Selector.list.Length;
}
}
int Native_Selector_GetActive(Handle plugin, int numParams) {
int client = GetNativeCell(1);
return g_PropData[client].Selector.IsActive();
}
int Native_Selector_SetOnEnd(Handle plugin, int numParams) {
int client = GetNativeCell(1);
PrivateForward fwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell);
fwd.AddFunction(plugin, GetNativeFunction(2));
g_PropData[client].Selector.SetOnEnd(fwd);
return 0;
}
int Native_Selector_SetOnPreSelect(Handle plugin, int numParams) {
int client = GetNativeCell(1);
PrivateForward fwd = new PrivateForward(ET_Single, Param_Cell, Param_Cell);
if(!fwd.AddFunction(plugin, GetNativeFunction(2))) return 0;
g_PropData[client].Selector.SetOnPreSelect(fwd);
return 1;
}
int Native_Selector_SetOnPostSelect(Handle plugin, int numParams) {
int client = GetNativeCell(1);
PrivateForward fwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell);
if(!fwd.AddFunction(plugin, GetNativeFunction(2))) return 0;
g_PropData[client].Selector.SetOnPostSelect(fwd);
return 1;
}
int Native_Selector_SetOnUnselect(Handle plugin, int numParams) {
int client = GetNativeCell(1);
PrivateForward fwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell);
if(!fwd.AddFunction(plugin, GetNativeFunction(2))) return 0;
g_PropData[client].Selector.SetOnUnselect(fwd);
return 1;
}
int Native_Selector_AddEntity(Handle plugin, int numParams) {
int client = GetNativeCell(1);
int entity = GetNativeCell(2);
g_PropData[client].Selector.AddEntity(entity, false);
return 0;
}
int Native_Selector_RemoveEntity(Handle plugin, int numParams) {
int client = GetNativeCell(1);
int entity = GetNativeCell(2);
g_PropData[client].Selector.RemoveEntity(entity);
return 0;
}
int Native_Selector_Cancel(Handle plugin, int numParams) {
int client = GetNativeCell(1);
g_PropData[client].Selector.Cancel();
return 0;
}
int Native_Selector_End(Handle plugin, int numParams) {
int client = GetNativeCell(1);
g_PropData[client].Selector.End();
return 0;
}

View file

@ -25,6 +25,8 @@ enum SaveType {
Save_Schematic
}
int GLOW_MANAGER[3] = { 52, 174, 235 };
enum struct Schematic {
char name[64];
char creatorSteamid[32];
@ -134,6 +136,197 @@ public any Native_SpawnSchematic(Handle plugin, int numParams) {
delete list;
return true;
}
enum struct PropSelectorIterator {
ArrayList _list;
int _index;
int Entity;
void _Init(ArrayList list) {
this._list = list;
this._index = -1;
}
bool Next() {
this._index++;
return this._index + 1 < this._list.Length;
}
}
enum struct PropSelector {
int selectColor[3];
int limit;
ArrayList list;
PrivateForward endCallback;
PrivateForward selectPreCallback;
PrivateForward selectPostCallback;
PrivateForward unSelectCallback;
int _client;
PropSelectorIterator Iter() {
PropSelectorIterator iter;
iter._Init(this.list);
return iter;
}
void Reset() {
if(this.endCallback) delete this.endCallback;
if(this.selectPreCallback) delete this.selectPreCallback;
if(this.selectPostCallback) delete this.selectPostCallback;
if(this.unSelectCallback) delete this.unSelectCallback;
if(this.list) delete this.list;
}
void Start(int color[3], int flags = 0, int limit = 0) {
this.selectColor = color;
this.limit = 0;
this.list = new ArrayList();
SendEditorMessage(this._client, "Left click to select, right click to unselect");
SendEditorMessage(this._client, "Press WALK+USE to confirm, DUCK+USE to cancel");
}
void SetOnEnd(PrivateForward callback) {
this.endCallback = callback;
}
void SetOnPreSelect(PrivateForward callback) {
this.selectPreCallback = callback;
}
void SetOnPostSelect(PrivateForward callback) {
this.selectPostCallback = callback;
}
void SetOnUnselect(PrivateForward callback) {
this.unSelectCallback = callback;
}
void StartDirect(int color[3], SelectDoneCallback callback, int limit = 0) {
PrivateForward fwd = new PrivateForward(ET_Ignore, Param_Cell, Param_Cell);
fwd.AddFunction(INVALID_HANDLE, callback);
this.Start(color, 0, limit);
this.SetOnEnd(fwd);
}
bool IsActive() {
return this.list != null;
}
void End() {
if(this.list == null) return;
SendEditorMessage(this._client, "Selection completed");
// Reset glows, remove selection from our spawned props
for(int i = 0; i < this.list.Length; i++) {
int ref = this.list.Get(i);
if(IsValidEntity(ref)) {
L4D2_RemoveEntityGlow(ref);
RemoveSpawnedProp(ref);
}
}
if(this.endCallback) {
if(GetForwardFunctionCount(this.endCallback) == 0) {
PrintToServer("[Editor] Warn: Selector.End(): callback has no functions assigned to it.");
}
Call_StartForward(this.endCallback);
Call_PushCell(this._client);
Call_PushCell(this.list.Clone());
int result = Call_Finish();
if(result != SP_ERROR_NONE) {
PrintToServer("[Editor] Warn: Selector.End() forward error: %d", result);
}
} else {
PrintToServer("[Editor] Warn: Selector.End() called but no callback assigned, voiding list");
}
this.Reset();
}
void Cancel() {
if(this.endCallback) {
Call_StartForward(this.endCallback);
Call_PushCell(this._client);
Call_PushCell(INVALID_HANDLE);
Call_Finish();
}
if(this.list) {
for(int i = 0; i < this.list.Length; i++) {
int ref = this.list.Get(i);
L4D2_RemoveEntityGlow(ref);
}
}
PrintToChat(this._client, "\x04[Editor]\x01 Selection cancelled.");
this.Reset();
}
int GetEntityRefIndex(int ref) {
int index = this.list.FindValue(ref);
if(index > -1) {
return index;
}
return -1;
}
/** Removes entity from list
* @return returns entity ref of entity removed
*/
int RemoveEntity(int entity) {
if(this.list == null) return -2;
L4D2_RemoveEntityGlow(entity);
int ref = EntIndexToEntRef(entity);
int index = this.GetEntityRefIndex(ref);
if(index > -1) {
this.list.Erase(index);
if(this.unSelectCallback != null) {
Call_StartForward(this.unSelectCallback)
Call_PushCell(this._client);
Call_PushCell(EntRefToEntIndex(ref));
Call_Finish();
}
return ref;
}
return INVALID_ENT_REFERENCE;
}
/**
* Adds entity to list
* @return index into list of entity
* @return -1 if already added
* @return -2 if callback rejected
*/
int AddEntity(int entity, bool useCallback = true) {
if(this.list == null) return -2;
int ref = EntIndexToEntRef(entity);
if(this.GetEntityRefIndex(ref) == -1) {
PrintToServer("Selector.AddEntity: PRE CALLBACK");
// FIXME: crashes server, sourcemod bug
/*if(this.selectPreCallback != null && useCallback) {
Call_StartForward(this.selectPreCallback)
Call_PushCell(this._client);
Call_PushCell(entity);
bool allowed = true;
PrintToServer("Selector.AddEntity: PRE CALLBACK pre finish");
Call_Finish(allowed);
PrintToServer("Selector.AddEntity: PRE CALLBACK pre result %b", allowed);
if(!allowed) return -2;
}*/
L4D2_SetEntityGlow(entity, L4D2Glow_Constant, 10000, 0, this.selectColor, false);
int index = this.list.Push(ref);
PrintToServer("Selector.AddEntity: post CALLBACK pre");
//FIXME: crashes server, sourcemod bug
/*if(this.selectPostCallback != null && useCallback) {
Call_StartForward(this.selectPostCallback)
Call_PushCell(this._client);
Call_PushCell(entity);
//Call_PushCell(index);
Call_Finish();
}*/
PrintToServer("Selector.AddEntity: post CALLBACK post");
return index;
}
return -1;
}
}
enum struct PlayerPropData {
ArrayList categoryStack;
ArrayList itemBuffer;
@ -144,14 +337,19 @@ enum struct PlayerPropData {
int lastActiveTime;
char classnameOverride[64];
ChatPrompt chatPrompt;
ArrayList markedProps;
PropSelector Selector;
SaveType pendingSaveType;
Schematic schematic;
int highlightedEntityRef;
int managerEntityRef;
void Init(int client) {
this.Selector._client = client;
}
// Called on PlayerDisconnect
void Reset() {
if(this.markedProps != null) delete this.markedProps;
if(this.Selector.IsActive()) this.Selector.Cancel();
this.chatPrompt = Prompt_None;
this.clearListBuffer = false;
this.lastCategoryIndex = 0;
@ -161,6 +359,19 @@ enum struct PlayerPropData {
this.CleanupBuffers();
this.pendingSaveType = Save_None;
this.schematic.Reset();
this.managerEntityRef = INVALID_ENT_REFERENCE;
this.StopHighlight();
}
void StartHighlight(int entity) {
this.highlightedEntityRef = EntIndexToEntRef(entity);
L4D2_SetEntityGlow(entity, L4D2Glow_Constant, 10000, 0, GLOW_MANAGER, false);
}
void StopHighlight() {
if(IsValidEntity(this.highlightedEntityRef)) {
L4D2_RemoveEntityGlow(this.highlightedEntityRef);
}
this.highlightedEntityRef = INVALID_ENT_REFERENCE;
}
void StartSchematic(int client, const char[] name) {

View file

@ -8,6 +8,8 @@ public void OnAdminMenuReady(Handle topMenuHandle) {
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");
topMenu.AddItem("editor_manager", AdminMenu_Manager, g_propSpawnerCategory, "sm_prop");
topMenu.AddItem("editor_selector", AdminMenu_Selector, g_propSpawnerCategory, "sm_prop");
}
g_topMenu = topMenu;
}
@ -24,6 +26,15 @@ void Category_Handler(TopMenu topmenu, TopMenuAction action, TopMenuObject topob
}
}
void AdminMenu_Selector(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) {
if(action == TopMenuAction_DisplayOption) {
Format(buffer, maxlength, "Selector");
} else if(action == TopMenuAction_SelectOption) {
ShowManagerSelectorMenu(param);
}
}
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");
@ -79,6 +90,14 @@ void AdminMenu_SaveLoad(TopMenu topmenu, TopMenuAction action, TopMenuObject obj
}
}
void AdminMenu_Manager(TopMenu topmenu, TopMenuAction action, TopMenuObject object_id, int param, char[] buffer, int maxlength) {
if(action == TopMenuAction_DisplayOption) {
Format(buffer, maxlength, "Manager (ALPHA)");
} else if(action == TopMenuAction_SelectOption) {
Spawn_ShowManagerMainMenu(param);
}
}
int SaveLoadMainMenuHandler(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
char info[2];
@ -87,7 +106,7 @@ int SaveLoadMainMenuHandler(Menu menu, MenuAction action, int client, int param2
ShowSaves(client, type);
} else if (action == MenuAction_Cancel) {
if(param2 == MenuCancel_ExitBack) {
Spawn_ShowSaveLoadMainMenu(client);
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
}
} else if (action == MenuAction_End)
delete menu;
@ -127,6 +146,7 @@ int SaveLoadSceneHandler(Menu menu, MenuAction action, int client, int param2) {
return 0;
}
int SaveLoadSchematicHandler(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
char saveName[64];
@ -189,40 +209,160 @@ int SaveLoadConfirmHandler(Menu menu, MenuAction action, int client, int param2)
delete menu;
return 0;
}
int DeleteHandler(Menu menu, MenuAction action, int client, int param2) {
int ManagerHandler(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) {
if(info[0] != '\0') {
int index = StringToInt(info);
int ref = g_spawnedItems.Get(index);
// TODO: add delete confirm
if(!IsValidEntity(ref)) {
SendEditorMessage(client, "Entity has disappeared");
} else {
int entity = EntRefToEntIndex(ref);
g_PropData[client].managerEntityRef = ref;
g_PropData[client].StartHighlight(entity);
ShowManagerEntityMenu(client, entity);
}
}
} else if (action == MenuAction_Cancel) {
if(param2 == MenuCancel_ExitBack) {
Spawn_ShowSaveLoadMainMenu(client);
}
} else if (action == MenuAction_End)
delete menu;
return 0;
}
int ManagerEntityHandler(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
g_PropData[client].StopHighlight();
char info[32];
menu.GetItem(param2, info, sizeof(info));
int ref = g_PropData[client].managerEntityRef;
if(!IsValidEntity(ref)) {
SendEditorMessage(client, "Entity disappeared");
return 0;
}
if(StrEqual(info, "edit")) {
Editor[client].ImportEntity(EntRefToEntIndex(ref), Edit_Manager);
Spawn_ShowManagerMainMenu(client);
} else if(StrEqual(info, "delete")) {
for(int i = 0; i < g_spawnedItems.Length; i++) {
int spawnedRef = g_spawnedItems.Get(i);
if(spawnedRef == ref) {
g_spawnedItems.Erase(i);
break;
}
}
if(IsValidEntity(ref)) {
RemoveEntity(ref);
}
Spawn_ShowManagerMainMenu(client);
} else if(StrEqual(info, "view")) {
ReplyToCommand(client, "Maybe soon.");
} else if(StrEqual(info, "select")) {
ShowManagerSelectorMenu(client);
int entity = EntRefToEntIndex(ref);
g_PropData[client].Selector.AddEntity(entity);
} else {
SendEditorMessage(client, "Unknown option / not implemented");
}
} else if (action == MenuAction_Cancel) {
g_PropData[client].StopHighlight();
if(param2 == MenuCancel_ExitBack) {
Spawn_ShowManagerMainMenu(client);
}
} else if (action == MenuAction_End)
delete menu;
return 0;
}
int ManagerSelectorMainMenuHandler(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
if(!EntitySelector.FromClient(client).Active) {
return 0;
}
char info[32];
menu.GetItem(param2, info, sizeof(info));
if(StrEqual(info, "list")) {
SendEditorMessage(client, "Not implemented");
} else if(StrEqual(info, "actions")) {
ShowManagerSelectorActionsMenu(client);
} else if(StrEqual(info, "cancel")) {
g_PropData[client].Selector.Cancel();
}
} else if (action == MenuAction_Cancel) {
g_PropData[client].Selector.Cancel();
} else if (action == MenuAction_End)
delete menu;
return 0;
}
int ManagerSelectorActionHandler(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
if(!g_PropData[client].Selector.IsActive()) {
return 0;
}
char info[32];
menu.GetItem(param2, info, sizeof(info));
if(StrEqual(info, "delete")) {
for(int i = 0; i < g_PropData[client].Selector.list.Length; i++) {
int ref = g_PropData[client].Selector.list.Get(i);
if(IsValidEntity(ref)) {
RemoveEntity(ref);
}
}
g_PropData[client].Selector.End();
Spawn_ShowManagerMainMenu(client);
} else if(StrEqual(info, "save")) {
// TODO: implement
SendEditorMessage(client, "Not implemented");
} else {
SendEditorMessage(client, "Unknown option / not implemented");
}
} else if (action == MenuAction_Cancel) {
if(param2 == MenuCancel_ExitBack) {
Spawn_ShowSaveLoadMainMenu(client);
}
} else if (action == MenuAction_End)
delete menu;
return 0;
}
int COLOR_DELETE[3] = { 255, 0, 0 }
int DeleteHandler(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
char info[128];
menu.GetItem(param2, info, sizeof(info));
int ref = StringToInt(info[2]);
int option = StringToInt(info);
if(option == -1) {
// Delete all (everyone)
int count = DeleteAll();
PrintToChat(client, "\x04[Editor]\x01 Deleted \x05%d\x01 items", count);
ShowDeleteList(client);
} else if(index == -2) {
} else if(option == -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 if(option == -3) {
if(g_PropData[client].Selector.IsActive()) {
g_PropData[client].Selector.End();
PrintToChat(client, "\x04[Editor]\x01 Delete tool cancelled");
} else {
g_PropData[client].markedProps = new ArrayList();
g_PropData[client].Selector.StartDirect(COLOR_DELETE, OnDeleteToolEnd);
PrintToChat(client, "\x04[Editor]\x01 Delete tool active. Press \x05Left Mouse\x01 to mark props, \x05Right Mouse\x01 to undo. SHIFT+USE to spawn, CTRL+USE to cancel");
}
ShowDeleteList(client);
} else {
int ref = g_spawnedItems.Get(index);
// TODO: add delete confirm
int index = g_spawnedItems.FindValue(ref);
if(IsValidEntity(ref)) {
RemoveEntity(ref);
}
g_spawnedItems.Erase(index);
if(index > 0) {
if(index > -1) {
g_spawnedItems.Erase(index);
index--;
}
} else { index = 0; }
ShowDeleteList(client, index);
}
} else if (action == MenuAction_Cancel) {
@ -317,16 +457,18 @@ 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 ref = StringToInt(info);
int index = g_spawnedItems.FindValue(ref);
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--;
if(index > -1) {
g_spawnedItems.Erase(index);
index--;
} else { index = 0; }
}
ShowEditList(client, index);
} else if (action == MenuAction_Cancel) {

View file

@ -3,11 +3,11 @@
/////////////
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.SetTitle("Choose spawn list:");
menu.AddItem("f", "Favorites (Broken :D)");
menu.AddItem("r", "Recently Spawned Props");
menu.AddItem("s", "Search for Props");
menu.AddItem("n", "Browse Props");
menu.ExitBackButton = true;
menu.ExitButton = true;
menu.Display(client, MENU_TIME_FOREVER);
@ -17,6 +17,7 @@ void Spawn_ShowRecents(int client) {
ArrayList items = GetRecentsItemList();
if(items.Length == 0) {
CReplyToCommand(client, "\x04[Editor] \x01No recent props spawned.");
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
return;
}
ShowTempItemMenu(client, items, "Recents");
@ -26,6 +27,11 @@ void Spawn_ShowSearch(int client) {
CReplyToCommand(client, "\x04[Editor] \x01Please enter search query in chat:");
}
void ShowDeleteList(int client, int index = -3) {
if(g_spawnedItems.Length == 0) {
SendEditorMessage(client, "No spawned items to delete");
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
return;
}
Menu menu = new Menu(DeleteHandler);
menu.SetTitle("Delete Props");
@ -38,7 +44,7 @@ void ShowDeleteList(int client, int index = -3) {
for(int i = 0; i < g_spawnedItems.Length; i++) {
int ref = GetSpawnedItem(i);
if(ref == -1) continue;
IntToString(i, info, sizeof(info));
Format(info, sizeof(info), "0|%d", ref);
GetEntPropString(ref, Prop_Data, "m_ModelName", buffer, sizeof(buffer));
index = FindCharInString(buffer, '/', true);
if(index != -1)
@ -52,6 +58,11 @@ void ShowDeleteList(int client, int index = -3) {
menu.DisplayAt(client, 0, MENU_TIME_FOREVER);
}
void ShowEditList(int client, int index = 0) {
if(g_spawnedItems.Length == 0) {
SendEditorMessage(client, "No spawned items to edit");
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
return;
}
Menu menu = new Menu(EditHandler);
menu.SetTitle("Edit Prop");
@ -60,7 +71,7 @@ void ShowEditList(int client, int index = 0) {
for(int i = 0; i < g_spawnedItems.Length; i++) {
int ref = GetSpawnedItem(i);
if(ref == -1) continue;
IntToString(i, info, sizeof(info));
Format(info, sizeof(info), "%d", ref);
GetEntPropString(ref, Prop_Data, "m_ModelName", buffer, sizeof(buffer));
index = FindCharInString(buffer, '/', true);
if(index != -1)
@ -104,6 +115,8 @@ void _showItemMenu(int client, ArrayList items, const char[] title = "", bool cl
items = g_PropData[client].itemBuffer;
if(items == null) {
LogError("Previous list does not exist and no new list was provided ShowItemMenu(%N)", client);
PrintToChat(client, "\x04[Editor]\x01 An error occurred (no list)");
return;
}
} else {
// Populate the buffer with this list
@ -194,6 +207,81 @@ void Spawn_ShowSaveLoadMainMenu(int client) {
menu.Display(client, MENU_TIME_FOREVER);
}
void Spawn_ShowManagerMainMenu(int client, int index = 0) {
if(g_spawnedItems.Length == 0) {
SendEditorMessage(client, "No spawned items to manage");
DisplayTopMenuCategory(g_topMenu, g_propSpawnerCategory, client);
return;
}
Menu menu = new Menu(ManagerHandler);
menu.SetTitle("Manager");
// Id is SaveType
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;
menu.DisplayAt(client, index, MENU_TIME_FOREVER);
}
void ShowManagerEntityMenu(int client, int entity) {
if(!IsValidEntity(entity)) {
SendEditorMessage(client, "Item has vanished");
Spawn_ShowManagerMainMenu(client);
return;
}
Menu menu = new Menu(ManagerEntityHandler);
menu.SetTitle("Manage %d", entity);
menu.AddItem("edit", "Edit");
menu.AddItem("delete", "Delete");
menu.AddItem("select", "Select");
menu.AddItem("view", "View");
menu.ExitBackButton = true;
menu.ExitButton = true;
menu.Display(client, MENU_TIME_FOREVER);
}
void ShowManagerSelectorMenu(int client) {
EntitySelector sel = EntitySelector.FromClient(client);
if(!sel.Active) {
sel.Start(GLOW_MANAGER);
sel.SetOnEnd(OnManagerSelectorEnd);
sel.SetOnPostSelect(OnManagerSelectorSelect);
sel.SetOnUnselect(OnManagerSelectorSelect);
}
Menu menu = new Menu(ManagerSelectorMainMenuHandler);
menu.SetTitle("Selector");
menu.AddItem("list", "> List Entities");
menu.AddItem("actions", "> Actions");
menu.AddItem("add-self", "Add All Self-Spawned");
menu.AddItem("add-all", "Add All Spawned");
menu.ExitBackButton = false;
menu.ExitButton = true;
menu.Display(client, MENU_TIME_FOREVER);
}
void ShowManagerSelectorActionsMenu(int client) {
Menu menu = new Menu(ManagerSelectorActionHandler);
menu.SetTitle("Selector: Select action");
char display[32];
Format(display, sizeof(display), "Entities: %d", g_PropData[client].Selector.list.Length);
menu.AddItem("", display, ITEMDRAW_DISABLED);
// menu.AddItem("edit", "Edit");
menu.AddItem("delete", "Delete");
// menu.AddItem("select", "Select");
menu.AddItem("save", "Save");
menu.ExitBackButton = true;
menu.ExitButton = true;
menu.Display(client, MENU_TIME_FOREVER);
}
void ShowSaves(int client, SaveType type) {
ArrayList saves;
Menu newMenu;

View file

@ -378,9 +378,7 @@ ArrayList SearchItems(const char[] query) {
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;
@ -446,26 +444,28 @@ bool RemoveSpawnedProp(int ref) {
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));
}
void OnDeleteToolEnd(int client, ArrayList entities) {
int count;
for(int i = 0; i < entities.Length; i++) {
int ref = entities.Get(i);
if(IsValidEntity(ref)) {
count++;
RemoveSpawnedProp(ref);
RemoveEntity(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");
}
delete entities;
PrintToChat(client, "\x04[Editor]\x01 \x05%d\x01 entities deleted", count);
}
void OnManagerSelectorEnd(int client, ArrayList entities) {
// TODO: implement manager selector cb
ReplyToCommand(client, "Not Implemented");
delete entities;
}
void OnManagerSelectorSelect(int client, int entity) {
// update entity count
ShowManagerSelectorMenu(client);
}
int DeleteAll(int onlyPlayer = 0) {

View file

@ -0,0 +1,155 @@
#if defined _editor_included_
#endinput
#endif
#define _editor_included_
public SharedPlugin __pl_editor_ = {
name = "editor",
file = "hats.smx",
#if defined REQUIRE_PLUGIN
required = 1,
#else
required = 0,
#endif
};
#if !defined REQUIRE_PLUGIN
public void __pl_editor__SetNTVOptional()
{
MarkNativeAsOptional("SpawnSchematic");
MarkNativeAsOptional("StartEdit");
MarkNativeAsOptional("StartSpawner");
MarkNativeAsOptional("CancelEdit");
MarkNativeAsOptional("IsEditorActive");
MarkNativeAsOptional("StartSelector");
MarkNativeAsOptional("CancelSelector");
MarkNativeAsOptional("IsSelectorActive");
MarkNativeAsOptional("Selector.Count.get");
MarkNativeAsOptional("Selector.Active.get");
MarkNativeAsOptional("Selector.Start");
MarkNativeAsOptional("Selector.SetOnEnd");
MarkNativeAsOptional("Selector.SetOnPreSelect");
MarkNativeAsOptional("Selector.SetOnPostSelect");
MarkNativeAsOptional("Selector.SetOnUnselect");
MarkNativeAsOptional("Selector.AddEntity");
MarkNativeAsOptional("Selector.RemoveEntity");
MarkNativeAsOptional("Selector.Cancel");
MarkNativeAsOptional("Selector.End");
}
#endif
native bool SpawnSchematic(const char name[32], const float pos[3], const float angles[3] = NULL_VECTOR);
/** Called when edit is done or cancelled
* @param client - client doing the edit
* @param entity - The entity edited
* @param result - Result of the edit, or cancelled
* @return boolean - only for StartSpawner, true to continue, false to end spawning
*/
typeset EditorDoneCallback {
function void (int client, int entity, CompleteType result);
function bool (int client, int entity, CompleteType result);
}
/** Called when an item is to be selected.
* @return boolean - TRUE to allow item to be selected, FALSE to reject
*/
typedef SelectPreAddCallback = function bool (int client, int entity);
/** Called when an item has been selected */
typedef SelectPostAddCallback = function void (int client, int entity);
/** Called when an item is to be unselected. */
typedef SelectRemoveCallback = function void (int client, int entity);
/** Called when a user is done selecting items
* @param client - client doing the selection
* @param entities - if null, selection was cancelled. if not null, contains list of entity references, must be deleted.
*/
typedef SelectDoneCallback = function void (int client, ArrayList entities);
/** Starts editing an entity
* @param client - The client that is editing
* @param entity - The entity to edit
* @param doneCallback - Called when edit is done
*/
native void StartEdit(int client, int entity, EditorDoneCallback doneCallback);
/** Let client pick prop(s) to spawn
* @param client - The client that is editing
* @param entity - The entity to edit
* @param doneCallback - Called when edit is done
*/
native void StartSpawner(int client, EditorDoneCallback doneCallback);
native void CancelEdit(int client);
// Includes non-plugin started edits
native bool IsEditorActive(int client);
/** Starts a selection, where the client can click on entities to select or deselect them.
* @param client - the client that can select
* @param callback - called when user is done seleting or cancelled
* @param highlightColor - the color to highlight selected items, default solid green
* @param maxEntities - the max number of selections, 0 for infinite
*/
native void StartSelector(int client, SelectDoneCallback callback, int highlightColor[3] = { 0, 255, 0 }, int maxEntities = 0);
methodmap EntitySelector {
public EntitySelector(int client) {
return view_as<EntitySelector>(client);
}
public static EntitySelector FromClient(int client) {
return view_as<EntitySelector>(client);
}
/** Starts a new selector for client
* @param highlightColor - the color to highlight selected items, default solid green
* @param flags - not used.
* @param maxEntities - the max number of selections, 0 for infinite
*/
public native EntitySelector Start(int highlightColor[3], int flags = 0, int maxEntities = 0);
property int Count {
/** Returns the number of entities in selector. Returns -1 if not active */
public native get();
}
property bool Active {
public native get();
}
/** Sets the callback for when the selector is ended (or cancelled) */
public native void SetOnEnd(SelectDoneCallback callback);
/** Sets the callback for when an item is to be added to the selector. */
public native void SetOnPreSelect(SelectPreAddCallback callback);
/** Sets the callback for when an item has been added to the selector. */
public native void SetOnPostSelect(SelectPostAddCallback callback);
/** Sets the callback for when an item is removed from selector. */
public native void SetOnUnselect(SelectRemoveCallback callback);
/** Adds an entity to selection. Does not call SelectAddCallback */
public native void AddEntity(int entity);
/** Removes an entity from selection. Does not call SelectAddCallback */
public native void RemoveEntity(int entity);
public native void Cancel();
public native void End();
}
native void CancelSelector(int client);
native bool IsSelectorActive(int client);
enum CompleteType {
Complete_WallSuccess,
Complete_WallError,
Complete_PropSpawned,
Complete_PropError,
Complete_EditSuccess
}

View file

@ -2,21 +2,50 @@
#endinput
#endif
#define _overlay_included
#include <ripext>
native bool SendTempUI(int client, const char[] id, int lifetime, JSONObject element);
public SharedPlugin __pl_overlay = {
name = "overlay",
file = "overlay.smx",
#if defined REQUIRE_PLUGIN
required = 1,
#else
required = 0,
#endif
};
native bool ShowUI(int client, const char[] elemNamespace, const char[] elemId, JSONObject variables);
#define ACTION_ARG_LENGTH 128 // The length each arg (separated by space) can be
native bool HideUI(int client, const char[] elemNamespace, const char[] elemId);
// typedef ActionFallbackHandlerCallback = function void (const char[] actionName, const char[][] args, int numArgs);
// typedef ActionHandlerCallback = function void (const char[][] args, int numArgs);
typedef ActionFallbackHandlerCallback = function void (const char[] actionName, UIActionEvent event, int client);
typedef ActionHandlerCallback = function void (UIActionEvent event, int client);
native bool PlayAudio(int client, const char[] url);
native bool IsOverlayConnected();
forward void OnUIAction(const char[] elemNamespace, const char[] elemId, const char[] action);
// myplugin:action_name
// Handles any action for actionNamespace and actionName
native void RegisterActionHandler(const char[] actionNamespace, const char[] actionName, ActionFallbackHandlerCallback cb);
// Handles all actions for namespace that were not caught by RegisterActionHandler
native void RegisterActionAnyHandler(const char[] actionNamespace, ActionHandlerCallback cb);
typedef UIActionCallback = function void (const char[][] args, int numArgs);
methodmap UIActionEvent {
public UIActionEvent(ArrayList list) {
return view_as<UIActionEvent>(list);
}
public void GetArg(int argNum, char[] output, int maxlen) {
view_as<ArrayList>(this).GetString(argNum, output, maxlen);
}
public void _Delete() {
delete view_as<ArrayList>(this);
}
property int Args {
public get() { return view_as<ArrayList>(this).Length; }
}
}
methodmap UIElement < JSONObject {
public UIElement(const char[] elemNamespace, const char[] elemId) {
@ -24,6 +53,7 @@ methodmap UIElement < JSONObject {
obj.SetString("namespace", elemNamespace);
obj.SetString("elem_id", elemId);
obj.SetBool("visibility", false);
obj.Set("steamids", new JSONArray());
obj.Set("variables", new JSONObject());
return view_as<UIElement>(obj);
@ -35,16 +65,6 @@ methodmap UIElement < JSONObject {
}
public set(bool value) {
view_as<JSONObject>(this).SetBool("visibility", value);
this.Send();
}
}
/** Is the UI element globally sent to all connected players?
* Specify players with .AddClient() or clear with .ClearClients()
*/
property bool Global {
public get() {
return !view_as<JSONObject>(this).HasKey("steamids")
}
}
@ -68,35 +88,13 @@ methodmap UIElement < JSONObject {
view_as<JSONObject>(this).SetBool(id, value);
}
public void SetActionCallback(UIActionCallback callback) {}
public void AddClient(const char[] steamid) {
// if(!IsClientInGame(client) || steamidCache[client][0] == '\0') ThrowError("Client %d is not connected, ingame, or authorized");
JSONObject obj = view_as<JSONObject>(this);
JSONArray steamids = view_as<JSONArray>(obj.Get("steamids"));
if(steamids == null) {
steamids = new JSONArray();
obj.Set("steamids", steamids)
public native bool SendAll();
public native bool SendTo(int client);
public bool SendToMultiple(int[] clientIds, int numClients) {
for(int i = 0; i < numClients; i++) {
this.SendTo(clientIds[i]);
}
steamids.PushString(steamid);
}
public void ClearClients() {
view_as<JSONObject>(this).Remove("steamids");
}
public void Clear() {
view_as<JSONObject>(this).Clear();
}
public void Hide() {
this.Visibility = false;
}
public void Show() {
this.Visibility = true;
}
public native bool Send();
}
methodmap UIPosition < JSONObject {
@ -118,6 +116,25 @@ methodmap UIPosition < JSONObject {
}
}
methodmap UISize < JSONObject {
public UISize(int width, int height) {
JSONObject obj = new JSONObject();
obj.SetInt("width", width);
obj.SetInt("height", height);
return view_as<UISize>(obj);
}
property int Width {
public get() { return view_as<JSONObject>(this).GetInt("width"); }
public set(int value) { view_as<JSONObject>(this).SetInt("height", value); }
}
property int Height {
public get() { return view_as<JSONObject>(this).GetInt("height"); }
public set(int value) { view_as<JSONObject>(this).SetInt("height", value); }
}
}
methodmap UIColor < JSONObject {
/// Creates a new UIColor with RGB between 0-255, alpha is normalized 0.0-1.0
public UIColor(int r = 255, int g = 255, int b = 255) {
@ -168,11 +185,15 @@ methodmap TempUIElementDefaults < JSONObject {
}
property UIPosition Position {
public get() { return view_as<UIPosition>(view_as<JSONObject>(this).Get("position")); }
public set(UIPosition pos) { view_as<JSONObject>(this).Set("position", view_as<JSON>(pos)); }
// public set(UIPosition pos) { view_as<JSONObject>(this).Set("position", view_as<JSON>(pos)); }
}
property UIColor BackgroundColor {
public get() { return view_as<UIColor>(view_as<JSONObject>(this).Get("bgColor")); }
public set(UIColor color) { view_as<JSONObject>(this).Set("bgColor", view_as<JSON>(color)); }
// public set(UIColor color) { view_as<JSONObject>(this).Set("bgColor", view_as<JSON>(color)); }
}
property UISize Size {
public get() { return view_as<UISize>(view_as<JSONObject>(this).Get("size")); }
// public set(UISize size) { view_as<JSONObject>(this).Set("size", view_as<JSON>(size)); }
}
/// Returns or sets opacity, -1 is not set
property int Opacity {
@ -203,6 +224,7 @@ enum UIType {
Element_Unknown = -1,
Element_Text,
Element_List,
Element_Audio
}
enum UIFlags {
Element_None
@ -287,27 +309,29 @@ methodmap TempUI {
public TempUI(const char[] elemId, const char[] type, int lifetime = 0) {
JSONObject obj = new JSONObject();
obj.SetString("elem_id", elemId);
obj.Set("steamids", new JSONArray());
obj.SetInt("expires_seconds", 0);
TempUIElement element = new TempUIElement(type);
obj.Set("element", element);
return view_as<TempUI>(obj);
}
/// How long the temp UI lasts, 0 for never.
property int Duration {
public get() {
return view_as<JSONObject>(this).GetInt("expires_seconds");
}
public set(int value) {
view_as<JSONObject>(this).SetInt("expires_seconds", value);
}
}
property bool Visible {
public get() {
return view_as<JSONObject>(this).GetBool("visibility");
}
public set(bool value) {
view_as<JSONObject>(this).SetBool("visibility", value);
this.Send();
}
}
/** Is the UI element globally sent to all connected players?
* Specify players with .AddClient() or clear with .ClearClients()
*/
property bool Global {
public get() {
return !view_as<JSONObject>(this).HasKey("steamids")
}
}
@ -316,38 +340,127 @@ methodmap TempUI {
return view_as<TempUIElement>(view_as<JSONObject>(this).Get("element"));
}
public set(TempUIElement newElement) {
// Delete old element
JSON elem = view_as<JSONObject>(this).Get("element");
if(elem != null) delete elem;
view_as<JSONObject>(this).Set("element", view_as<JSON>(newElement));
}
}
public void SetActionCallback(UIActionCallback callback) {}
public void AddClient(const char[] steamid) {
// if(!IsClientInGame(client) || steamidCache[client][0] == '\0') ThrowError("Client %d is not connected, ingame, or authorized");
JSONObject obj = view_as<JSONObject>(this);
JSONArray steamids = view_as<JSONArray>(obj.Get("steamids"));
if(steamids == null) {
steamids = new JSONArray();
obj.Set("steamids", steamids)
}
steamids.PushString(steamid);
}
public void ClearClients() {
view_as<JSONObject>(this).Remove("steamids");
}
public void Clear() {
view_as<JSONObject>(this).Clear();
}
public void Hide() {
this.Visibility = false;
public void Hide() {
this.Visible = false;
}
public void Show() {
this.Visibility = true;
this.Visible = true;
}
public native bool Send();
public native bool SendAll();
public native bool SendTo(int client);
public bool SendToMultiple(int[] clientIds, int numClients) {
for(int i = 0; i < numClients; i++) {
this.SendTo(clientIds[i]);
}
}
}
}
enum AudioState {
// Audio stopped, reset to startTime
Audio_Stopped,
// Pauses audio at current time
Audio_Paused,
Audio_Play
}
methodmap ClientList < JSONArray {
public ClientList() {
return view_as<ClientList>(new JSONArray());
}
property int Length {
public get() { return view_as<JSONArray>(this).Length; }
}
public native void AddClient(int client);
public native bool HasClient(int client);
public void Clear() {
view_as<JSONArray>(this).Clear();
}
}
methodmap AudioResource < JSONObject {
public AudioResource(const char[] url, float volume = 0.5) {
JSONObject obj = new JSONObject();
obj.SetString("source", url);
obj.SetFloat("volume", volume);
obj.SetInt("state", 0);
obj.Set("steamids", new JSONArray());
obj.SetBool("repeat", false)
return view_as<AudioResource>(obj);
}
property AudioState State {
public get() {
return view_as<AudioState>(view_as<JSONObject>(this).GetInt("state"));
}
public set(AudioState state) {
view_as<JSONObject>(this).SetInt("state", view_as<int>(state));
}
}
property float Volume {
public get() {
return view_as<JSONObject>(this).GetFloat("volume");
}
public set(float volume) {
view_as<JSONObject>(this).SetFloat("volume", volume);
}
}
property bool Repeat {
public get() {
return view_as<JSONObject>(this).GetBool("repeat");
}
public set(bool repeat) {
view_as<JSONObject>(this).SetBool("repeat", repeat);
}
}
property ClientList Clients {
public get() {
return view_as<ClientList>(view_as<JSONObject>(this).Get("steamids"));
}
}
/// Plays or resumes playing
public native void Play();
/// Stops playing audio, clients will reset to beginning
public native void Stop();
/// Pauses audio, resuming to current play duration
public native void Pause();
public void Clear() {
view_as<JSONObject>(this).Clear();
}
}
#if !defined REQUIRE_PLUGIN
public void __pl_overlay_SetNTVOptional() {
MarkNativeAsOptional("IsOverlayConnected");
MarkNativeAsOptional("RegisterActionAnyHandler");
MarkNativeAsOptional("RegisterActionHandler");
MarkNativeAsOptional("UIElement.SendAll");
MarkNativeAsOptional("UIElement.SendTo");
MarkNativeAsOptional("TempUI.SendAll");
MarkNativeAsOptional("TempUI.SendTo");
MarkNativeAsOptional("AudioResource.Play");
MarkNativeAsOptional("AudioResource.Stop");
MarkNativeAsOptional("AudioResource.Pause");
}
#endif

View file

@ -0,0 +1,135 @@
/// MENUS
public void OpenMainMenu(int client) {
Menu menu = new Menu(BuilderHandler_MainMenu);
menu.SetTitle("Randomizer Builder");
if(g_builder.mapData == null) {
menu.AddItem("load", "Load Map Data");
menu.AddItem("new", "New Map Data");
} else {
menu.AddItem("save", "Save Map Data");
menu.AddItem("selector", "Start Selector");
menu.AddItem("spawner", "Start Spawner");
menu.AddItem("cursor", "Add Entity At Cursor");
menu.AddItem("scenes", "Scenes");
}
menu.Display(client, 0);
}
void OpenScenesMenu(int client) {
Menu menu = new Menu(BuilderHandler_ScenesMenu);
menu.SetTitle("Select a scene");
char id[64], display[32];
JSONObjectKeys iterator = g_builder.mapData.Keys();
while(iterator.ReadKey(id, sizeof(id))) {
if(StrEqual(id, g_builder.selectedSceneId)) {
Format(display, sizeof(display), "%s (selected)", id);
} else {
Format(display, sizeof(display), "%s", id);
}
menu.AddItem(id, display);
}
menu.Display(client, 0);
}
void OpenVariantsMenu(int client) {
Menu menu = new Menu(BuilderHandler_VariantsMenu);
menu.SetTitle("%s > Variants", g_builder.selectedSceneId);
char id[8], display[32];
menu.AddItem("new", "New");
menu.AddItem("-1", "None (Shared Scene)");
JSONArray variants = view_as<JSONArray>(g_builder.selectedSceneData.Get("variants"));
JSONObject varObj;
JSONArray entities;
for(int i = 0; i < variants.Length; i++) {
varObj = view_as<JSONObject>(variants.Get(i));
entities = view_as<JSONArray>(varObj.Get("entities"));
if(i == g_builder.selectedVariantIndex) {
Format(display, sizeof(display), "%d entities (selected)", entities.Length);
} else {
Format(display, sizeof(display), "%d entities", entities.Length);
}
IntToString(i, id, sizeof(id));
menu.AddItem(id, display);
}
menu.Display(client, 0);
}
/// HANDLERS
int BuilderHandler_MainMenu(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
char info[32];
menu.GetItem(param2, info, sizeof(info));
if(StrEqual(info, "new")) {
JSONObject temp = LoadMapJson(currentMap);
GetCmdArg(2, info, sizeof(info));
if(temp != null) {
Menu nMenu = new Menu(BuilderHandler_MainMenu);
nMenu.SetTitle("Existing map data exists");
nMenu.AddItem("new_confirm", "Overwrite");
nMenu.Display(client, 0);
delete temp;
return 0;
} else {
FakeClientCommand(client, "sm_rbuild new");
}
} else if(StrEqual(info, "new_confirm")) {
FakeClientCommand(client, "sm_rbuild new confirm");
} else if(StrEqual(info, "scenes")) {
OpenScenesMenu(client);
return 0;
} else {
FakeClientCommand(client, "sm_rbuild %s", info);
} /*else if(StrEqual(info, "cursor")) {
Menu menu = new Menu(BuilderHandler_)
}*/
OpenMainMenu(client);
} else if(action == MenuAction_Cancel) {
if(param2 == MenuCancel_ExitBack) {
}
} else if (action == MenuAction_End) {
delete menu;
}
return 0;
}
int BuilderHandler_ScenesMenu(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
char info[64];
menu.GetItem(param2, info, sizeof(info));
if(StrEqual(info, "new")) {
FakeClientCommand(client, "sm_rbuild scenes new");
OpenScenesMenu(client);
} else {
FakeClientCommand(client, "sm_rbuild scenes select %s", info);
OpenVariantsMenu(client);
}
} else if(action == MenuAction_Cancel) {
if(param2 == MenuCancel_ExitBack) {
}
} else if (action == MenuAction_End) {
delete menu;
}
return 0;
}
int BuilderHandler_VariantsMenu(Menu menu, MenuAction action, int client, int param2) {
if (action == MenuAction_Select) {
char info[64];
menu.GetItem(param2, info, sizeof(info));
if(StrEqual(info, "new")) {
FakeClientCommand(client, "sm_rbuild scenes variants new");
} else {
FakeClientCommand(client, "sm_rbuild scenes variants select %s", info);
}
OpenVariantsMenu(client);
} else if(action == MenuAction_Cancel) {
if(param2 == MenuCancel_ExitBack) {
}
} else if (action == MenuAction_End) {
delete menu;
}
return 0;
}