PDA

View Full Version : Spawn control points (trigger_capture_area)


Bugzy
11-04-2014, 19:10
I want to create control points in maps that don't have them. To explain, in order to have a proper-functioning control point in Team Fortress 2, you need these entities:


team_control_point_master
team_control_point
trigger_capture_area
prop_dynamic (optional)


I can spawn these entities using Stripper:Source (http://www.bailopan.net/stripper/), except for the trigger_capture_area which is a brush-based entity. Instead, I need to use this method (https://forums.alliedmods.net/showthread.php?t=129597) to spawn them. This set-up would work, however, the most important keyvalue "area_cap_point" doesn't register in-game.

For example, I set this keyvalue like so:

DispatchKeyValue(ent, "area_cap_point", strName);
And despite strName correctly referencing the target name of the relevant team_control_point, the game behaves as if this keyvalue was never set.

Is there any way to get around this? I've attached below the test script/map I've been using to try to get this working. The relevant code is inside the function called "AssignControlPoint".



#pragma semicolon 1

#include <sourcemod>
#include <sdktools>

#define MDL_NO_MODEL "models/error.mdl"

static Float:g_vOrigin[3] = {192.0, 64.0, 108.0},
Float:g_vDimensions[3] = {256.0, 256.0, 200.0};

public OnPluginStart()
{
HookEventEx("teamplay_round_start", round);
HookEventEx("teamplay_restart_round", round);
ServerCommand("sm_cvar mp_waitingforplayers_time 0");
}

public OnMapStart()
{
PrecacheModel(MDL_NO_MODEL, true);
}

public round(Handle:event, const String:name[], bool:dontBroadcast)
{
if (GetEntityCount() >= GetMaxEntities() - 64) {
PrintToServer("[SM] Entity limit is reached. Can't spawn anymore ents. Change maps.");
return;
}

new ent = CreateEntityByName("trigger_capture_area");
if (!IsValidEntity(ent)) {
PrintToServer("[SM] Could not spawn trigger_capture_area");
return;
}

DispatchKeyValue(ent, "spawnflags", "64");
DispatchKeyValue(ent, "wait", "0");
DispatchKeyValue(ent, "team_startcap_3", "2");
DispatchKeyValue(ent, "team_startcap_2", "2");
DispatchKeyValue(ent, "team_spawn_3", "0");
DispatchKeyValue(ent, "team_spawn_2", "0");
DispatchKeyValue(ent, "team_numcap_3", "1");
DispatchKeyValue(ent, "team_numcap_2", "1");
DispatchKeyValue(ent, "team_cancap_3", "1");
DispatchKeyValue(ent, "team_cancap_2", "1");
DispatchKeyValue(ent, "StartDisabled", "0");
DispatchKeyValue(ent, "area_time_to_cap", "5");

AssignControlPoint(ent, "control_point");

DispatchSpawn(ent);
ActivateEntity(ent);

// set datamap spawnflags to allow (only) clients
SetEntProp(ent, Prop_Data, "m_spawnflags", 1);

// move ent entity to the origin
TeleportEntity(ent, g_vOrigin, NULL_VECTOR, NULL_VECTOR);

SetEntityModel(ent, MDL_NO_MODEL);

// set mins and maxs for entity
decl Float:vecMins[3],
Float:vecMaxs[3];
vecMins[0] = -(g_vDimensions[0] / 2);
vecMins[1] = -(g_vDimensions[1] / 2);
vecMins[2] = -(g_vDimensions[2] / 2);
vecMaxs[0] = (g_vDimensions[0] / 2);
vecMaxs[1] = (g_vDimensions[1] / 2);
vecMaxs[2] = (g_vDimensions[2] / 2);
SetEntPropVector(ent, Prop_Send, "m_vecMins", vecMins);
SetEntPropVector(ent, Prop_Send, "m_vecMaxs", vecMaxs);

// enable touch functions and set it as non-solid for everything
SetEntProp(ent, Prop_Send, "m_usSolidFlags", 152);
SetEntProp(ent, Prop_Send, "m_CollisionGroup", 11);

// make the ent visible by removing EF_NODRAW flag
new m_fEffects = GetEntProp(ent, Prop_Send, "m_fEffects");
m_fEffects |= 0x020;
SetEntProp(ent, Prop_Send, "m_fEffects", m_fEffects);

// proof the entity can be touched
HookSingleEntityOutput(ent, "OnStartTouch", TouchCheck);
}

public TouchCheck(const String:output[], caller, activator, Float:delay)
{
PrintToChat(activator, "%s, %d, %d, %0.2f", output, caller, activator, delay);
}

stock AssignControlPoint(ent, const String:strName[])
{
// appears to work ...
DispatchKeyValue(ent, "area_cap_point", strName);

// and it will report it has changed ... but it still doesn't recognise the control point
decl String:strCheck[128];
GetEntPropString(ent, Prop_Data, "m_iszCapPointName", strCheck, sizeof(strCheck));
PrintToServer("[DEBUG] (AssignControlPoint) Entity: %d now refers to control point '%s'", ent, strCheck);
}

Powerlord
11-05-2014, 09:14
Have you tried dispatching this keyvalue before the control point is spawned (which is when DispatchSpawn is called on it)?

Bugzy
11-05-2014, 21:48
Have you tried dispatching this keyvalue before the control point is spawned (which is when DispatchSpawn is called on it)?

Wow, thanks a bunch, that did the trick!

For anyone interested, here's a working version:


#pragma semicolon 1

#include <sourcemod>
#include <sdktools>

#define MDL_NO_MODEL "models/error.mdl"

static Float:g_vOrigin[3] = {192.0, 64.0, 108.0},
Float:g_vDimensions[3] = {256.0, 256.0, 200.0};

public OnPluginStart()
{
ServerCommand("sm_cvar mp_waitingforplayers_time 0");
}

public OnMapStart()
{
PrecacheModel(MDL_NO_MODEL, true);
}

public OnEntityCreated(entity, const String:strClassName[])
{
if (!StrEqual("team_control_point", strClassName)) return;

if (GetEntityCount() >= GetMaxEntities() - 64) {
PrintToServer("[SM] Entity limit is reached. Can't spawn anymore ents. Change maps.");
return;
}

new ent = CreateEntityByName("trigger_capture_area");
if (!IsValidEntity(ent)) {
PrintToServer("[SM] Could not spawn trigger_capture_area");
return;
}

DispatchKeyValue(ent, "spawnflags", "64");
DispatchKeyValue(ent, "wait", "0");
DispatchKeyValue(ent, "team_startcap_3", "0");
DispatchKeyValue(ent, "team_startcap_2", "0");
DispatchKeyValue(ent, "team_spawn_3", "0");
DispatchKeyValue(ent, "team_spawn_2", "0");
DispatchKeyValue(ent, "team_numcap_3", "1");
DispatchKeyValue(ent, "team_numcap_2", "1");
DispatchKeyValue(ent, "team_cancap_3", "1");
DispatchKeyValue(ent, "team_cancap_2", "1");
DispatchKeyValue(ent, "StartDisabled", "0");
DispatchKeyValue(ent, "area_time_to_cap", "5");
DispatchKeyValue(ent, "area_cap_point", "control_point");

DispatchSpawn(ent);
ActivateEntity(ent);

// set datamap spawnflags to allow (only) clients
SetEntProp(ent, Prop_Data, "m_spawnflags", 1);

// move ent entity to the origin
TeleportEntity(ent, g_vOrigin, NULL_VECTOR, NULL_VECTOR);

SetEntityModel(ent, MDL_NO_MODEL);

// set mins and maxs for entity
decl Float:vecMins[3],
Float:vecMaxs[3];
vecMins[0] = -(g_vDimensions[0] / 2);
vecMins[1] = -(g_vDimensions[1] / 2);
vecMins[2] = -(g_vDimensions[2] / 2);
vecMaxs[0] = (g_vDimensions[0] / 2);
vecMaxs[1] = (g_vDimensions[1] / 2);
vecMaxs[2] = (g_vDimensions[2] / 2);
SetEntPropVector(ent, Prop_Send, "m_vecMins", vecMins);
SetEntPropVector(ent, Prop_Send, "m_vecMaxs", vecMaxs);

// enable touch functions and set it as non-solid for everything
SetEntProp(ent, Prop_Send, "m_usSolidFlags", 152);
SetEntProp(ent, Prop_Send, "m_CollisionGroup", 11);

// make the ent visible by removing EF_NODRAW flag
new m_fEffects = GetEntProp(ent, Prop_Send, "m_fEffects");
m_fEffects |= 0x020;
SetEntProp(ent, Prop_Send, "m_fEffects", m_fEffects);
}

Powerlord
11-06-2014, 10:59
As a side note, some keyvalues are OK to dispatch mid game, but apparently some aren't and will be ignored.

It might be based on whether these inputs are referenced by other entities.

Speaking of which, you may want to dispatch the "targetname" key, which the entity Input/Output system uses. I don't know if team_control_point_master uses those (and I have a teleconference in 3 minutes so I can't check now), but team_control_point_round does... one of its properties is a space-separate list of the targetnames of the control points in the current round.

friagram
11-06-2014, 11:40
Most keyvalues will work if you change the entity's state by sending a disable and then enable or turnoff turnon input back to back. Same with changing other netprops