OK lets say there can be more then one entity of the same class in the game, when one of these entities is touched and I remove that entity in the ontouch function, will the hook still be availlable for other entities of the same class but with a diffrent index? Will it only remove its own hook when ALL entities of the same class are destroyed ?
- Not removing a parameter, but only the "const", "String" and Float tags. Optional or not allowed?
Thanks for all youre help so far ajr1234 && others, I'm gonna finish the code soon and post it here for revision, maybe this thread could be used for a small tutorial on how to code entities for source.
__________________
Working on:
[CSGO/CSS] Mmorpg - an extensive XP/level modulair platform
Progress: [♣♣♣♣♣♣♣|♣♣♣]
The hook only affects the entity-- not all entities of the classname. You can still hook other entities of the same class. Also, you can hook more than one entity, i.e.:
PHP Code:
// hook entities to a particular callback
HookSingleEntityOutput(entity1, "OnStartTouch", ontouch);
HookSingleEntityOutput(entity2, "OnStartTouch", ontouch);
HookSingleEntityOutput(entity3, "OnStartTouch", ontouch);
HookSingleEntityOutput(entity4, "OnStartTouch", someothercallback);
// let's say some player touches entity1. The following callback is fired
public ontouch(const String:output[], caller, activator, Float:delay)
{
if (IsValidEdict(caller)) RemoveEdict(caller);
// hook is removed for the destroyed caller (entity1), but remain for other hooked
// entities (i.e. entity2 and entity3) that are not destroyed yet.
// if the player then touches entity2, then entity2 is removed but entity3 is still hooked.
}
// fired for entity4
public someothercallback(const String:output[], caller, activator, Float:delay)
{
// do something
}
As for your second question, no, you cannot remove the the declarations and data types; otherwise, the data being passed will be assumed to be integers, and that is not the case here.
Ok thanks, i think im starting to get it,
now i have a question about timers:
is there a way to group a bunch of active timers so that when you have multiple timers running and you wanna use KillTimer on only specifik timers, not all.
how or what would be the best way to do this?
__________________
Working on:
[CSGO/CSS] Mmorpg - an extensive XP/level modulair platform
Progress: [♣♣♣♣♣♣♣|♣♣♣]
Ok so this is what i have so far, could anyone revise this code?
I can compile it without warnings but i would like to know if its coded correctly and efficient.
All i need now is a way to assign each created entity timers and be able to remove them separatly while multiple timers are running. and offcourse a model for the entity, working on my own model but its going slow.
include <sourcemod> #include <sdktools> new LaserSprite, Halosprite; new bool:g_bTouchedIt[MAXPLAYERS+1]; new Float:g_FlameTime = 5.0; public Plugin:MyInfo = { name = "CBase entity?", author = "Sky-High", description = "My first SM entity plugin", version = "1.0", url = "** AM Spam-Blocker V3.6 **" };
public OnPluginStart() {
LoadTranslations("common.phrases");
HookEvent("player_death", Event_PlayerDeath);
//AutoExecConfig(true, "plugin_testplugin"); //autoexec a cfg file if there isnt already one } public OnMapStart() { //Precache LaserSprite = PrecacheModel("materials/sprites/bluelaser1.vmt"); Halosprite = PrecacheModel("materials/sprites/halo01.vmt"); } public Event_PlayerDeath(Handle:event, const String:name[], bool:dontBroadcast) { new victim_id = GetEventInt(event, "userid"); //new attacker_id = GetEventInt(event, "attacker");
new victim = GetClientOfUserId(victim_id); //new attacker = GetClientOfUserId(attacker_id); new Float:Origin[3];
} } public SpawnEntity(entity) { if( IsValidEntity(entity) ) { if (DispatchSpawn(entity)) { // if you can't find OnStartTouch output, using SDKHooks // http://hg.alliedmods.net/sourcemod-central/file/tip/plugins/include/sdkhooks.inc //SDKHook(entity, SDKHook_StartTouch, Entity_OnStartTouch); HookSingleEntityOutput(entity, "OnStartTouch", Entity_OnStartTouch);
// Set the entity on fire as a last effect IgniteEntity(entity, Float:g_FlameTime, bool:1); } } } public Entity_OnStartTouch(const String:output[], caller, activator, Float:delay) { if( IsPlayerAlive(activator) ) { //Can i use this to store in the clientindex of the player touched it? //SetEntProp(entity, Prop_Data, "PropField_Integer", client); g_bTouchedIt[activator] = true;
CreateTimer(...) returns a handle. You have to store this handle someplace along with the corresponding specific information you will use to identify it. Handles become invalidated when the timer fires its callback, or when repeating timers return Plugin_Stop. Accessing any stored handles after this event will cause problems. So be sure to clear any stored handles in your callback.
As a generic case, you can use an array to store the handles.
Spoiler
PHP Code:
new Handle:g_Array = CreateArray(2);
/* Create Entity And Timer */ { new Entity = CreateEntityByName(); new Handle:hTimer = CreateTimer(..., TimerFunc, Entity);
new array_index; if( (array_index = PushArrayCell(g_Array,Entity)) == INVALID_HANDLE) return;
CreateTimer returns a handle to the timer object. You can use this to store the timer. Just create another global variable. As for setting a model, use SetEntityModel.
I'm a little confused about what you are trying to do.
PHP Code:
stock CreateSomeEntity(client, Float:Origin[3])
You pass the client index from the death callback, but then you don't use it.
woops, forgot to take that part out.
Quote:
Originally Posted by happs
PHP Code:
new entity = CreateEntityByName("my_entity");
What entity type are you trying to create?
I'm trying to make a very basic NPC entity that does not move, only rotate (not sure how to do this just yet but my model isnt finished yet and neighter is the anim).
Quote:
Originally Posted by happs
PHP Code:
HookEvent("player_spawn", Event_PlayerSpawn);
public Event_PlayerSpawn(Handle:event, const String:name[], bool:dontBroadcast) { g_bTouchedIt[activator] = false; }
You should initialize your global variable. I'm guessing you want to only track who has touched these entities between lives.
yeah I know its just the entity coding that needs revising, the rest of the plguin isnt written yet, I first need my model finished.
Spoiler
Quote:
As far as multiple-timers, I'm guessing you want these entities to disappear after a certain time if they were not triggered?
CreateTimer(...) returns a handle. You have to store this handle someplace along with the corresponding specific information you will use to identify it. Handles become invalidated when the timer fires its callback, or when repeating timers return Plugin_Stop. Accessing any stored handles after this event will cause problems. So be sure to clear any stored handles in your callback.
As a generic case, you can use an array to store the handles.
Spot on! and also a timer to change the renderingmode en fix to visually show to ppl its gonna go away (so 2 timers per entitiy).
But since a whole series of entities can spawn, alot of timers will start.
So i want to find the corresponding timer linked to a entities index.
The problem with that is that my array for the timer handle would be waay to big since entities can have indexes of high numers right(100K+)?
its not that i can do like MAXPLAYERS or for Assign it an insanely high number to it? that would be way to intensive for the plugin
This uses AddOutput and I/O chain
[/quote]
This will take some getting familiar to, all these inputs :s. I still dont understand the setvariantstring after reading it 5 times, idem for acceptentityinput.
Are all datamap-dump inputs applyable on my type of entities?
and what exactly is the diffrence between FireUser1 to 4(FireUser4)
Quote:
PHP Code:
new Handle:g_Array = CreateArray(2);
/* Create Entity And Timer */ { new Entity = CreateEntityByName(); new Handle:hTimer = CreateTimer(..., TimerFunc, Entity);
new array_index; if( (array_index = PushArrayCell(g_Array,Entity)) == INVALID_HANDLE) return;
SetArrayCell(g_Array, array_index, hTimer, 1 /* block1 => save blocks for timer handles? */) }
I have never coded an Array on such level, Could you pls explain someparts of it?
- In this case our array is like this: Array[X][2], What is the refenence key/value (or whatever its called) in X, the number of enty stored in the order they spawned? Block 1 will contain the entity indexes and block 2 the timerhandles?
- Can you explain what exactly is happening here pls?
PHP Code:
new array_index; if( (array_index = PushArrayCell(g_Array,Entity)) == INVALID_HANDLE) return;
- in FindIndexOfTimer and FindIndexOfEntity, exactly what index are we looking for and when/where would we need it?
__________________
Working on:
[CSGO/CSS] Mmorpg - an extensive XP/level modulair platform
Progress: [♣♣♣♣♣♣♣|♣♣♣]
its not that i can do like MAXPLAYERS or for Assign it an insanely high number to it? that would be way to intensive for the plugin
Actually, you can. The engine has a limit to the number of edicts that it can create. You can essentially use a static array and get rid of the overhead of using a dynamically allocated container. Moreover, since you are looking to create some sort of NPC plugin, I bet you will need a method to store data. Unfortunately, SourcePawn is not object oriented. The closest you can do is use an array with enumerators, as I show below. The nice thing about this is that you can easily expand the enumerator with more properties (e.g. destruction time, NPC status, health, mission, etc.) using getters and setters. Plus, it is more efficient than using a dynamic array and constantly pushing/popping elements. Using a larger array just allocates more bytes during load, and a few thousand more bytes in memory is absolutely no problem at all.
// Resets an element of the array
stock ResetNPCVars(entity)
{
g_Touch[entity][TOUCH_DATA:ACTIVATOR] = NO_ACTIVATOR;
g_Touch[entity][TOUCH_DATA:TOUCH_FLAG] = FALSE;
}
// Returns true if an entity was touched by a client
stock bool:WasNPCTouchedByClient(entity, client)
{
return (g_Touch[entity][TOUCH_DATA:ACTIVATOR] == client);
}
// Returns the last activator to touch the entity
stock GetNPCActivator(entity)
{
return g_Touch[entity][TOUCH_DATA:ACTIVATOR];
}
// Returns true if the NPC was touched by a client at all in all of its touches
stock WasNPCTouchedAtAll(entity)
{
return (g_Touch[entity][TOUCH_DATA:ACTIVATOR] || g_Touch[entity][TOUCH_DATA:TOUCH_FLAG]);
}
// Sets entity touch data (see usage under Plugin Code section)
stock SetNPCTouchVars(entity, TOUCH_DATA:data, value)
{
g_Touch[entity][data] = value;
}
if (IsValidEntity(entity))
{
// Remove edict when touched
HookSingleEntityOutput(entity, "OnStartTouch", Entity_OnStartTouch);
// Change rendermode in 20.0 seconds
CreateTimer(20.0, Timer_SetRenderGlow, entity);
IgniteEntity(entity, FLAME_TIME, true);
}
}
public Entity_OnStartTouch(const String:output[], caller, activator, Float:delay)
{
// Something touched this entity
if (caller > 0)
SetNPCTouchVars(caller, ACTIVATOR, activator); // caller was touched by an ACTIVATOR of index: activator
// If you're going to use RemoveEdict, then you need to make sure that the edict is valid.
// In this case, the edict will be valid, but get into the habit of checking if an edict is valid before removing it.
//
// Secondly, sometimes the activator won't always be a player. Try throwing a prop_physics onto your NPC and see
// what happens. This callback will be fired, but IsPlayerAlive() will receive an index that does not belong
// to a player. Therefore, you need to check that the index belongs to a player.
if (activator >= 1 && activator <= MaxClients)
{
if (IsPlayerAlive(activator) && IsValidEdict(caller))
{
// This entity was touched by a client (alive player)
SetNPCTouchVars(caller, TOUCH_FLAG, TRUE);
RemoveEdict(caller);
}
}
}
public Action:Timer_SetRenderGlow(Handle:timer, any:entity)
{
if (IsValidEntity(entity))
{
SetEntityRenderMode(entity, RENDER_GLOW);
SetEntityRenderFx(entity, RENDERFX_PULSE_FAST_WIDER);
// Remove this entity 10 seconds from now (i.e. 30.0 after spawn)
CreateTimer(10.0, Timer_RemoveEntity, entity);
}
}
public Action:Timer_RemoveEntity(Handle:timer, any:entity)
{
if (IsValidEdict(entity))
RemoveEdict(entity);
}
public Event_RoundEnd(Handle:event, String:name[], bool:dontBroadcast)
{
// Reset variables after the round is over
for (new i = 0; i < MAX_EDICTS; i++)
ResetNPCVars(i);
}
public Plugin:MyInfo =
{
name = "CBase entity?",
author = "Sky-High",
description = "My first SM entity plugin",
version = "1.0",
url = "** AM Spam-Blocker V3.6 **"
};
Both methods for arrays are very usefull, i prefer yours though becous its logic is not specifically sourcemod related and it could benefit me more in the future for other projects idk .
got a few questions tough:
an invalid edict id would not be a problem in all these stocks becous all possible entities are cached into the array? it would only retrieve a false result?
__________________
Working on:
[CSGO/CSS] Mmorpg - an extensive XP/level modulair platform
Progress: [♣♣♣♣♣♣♣|♣♣♣]