STEAM GROUP
Left 4 Dead 2 Workshop Beta L4D2WSB
STEAM GROUP
Left 4 Dead 2 Workshop Beta L4D2WSB
1
IN-GAME
22
ONLINE
Founded
15 October, 2012
Neil - 119 10 Mar, 2013 @ 10:50am
VScript Suggestions
I coded my own valve server plugin[forum.l4dmaps.com] that adds several needed features. Before that, I had to rely on users setting up SourceMod. It's very difficult making an interactive mod without the following:


If anything, #2, #3, #11, #13 and #18 are the ones that are most needed from below.

(List last updated: 4/7/2013):
-------------------------------------------------------------------------------------------------
1. Ability to modify game event params.
2. Getting and setting networked properties (e.g. m_zombieClass, m_jockeyVictim, etc).
3. A method to send usermessages. Wrapper for engine->UserMessageBegin / MessageEnd and writing bytes and strings.
4. A function to dynamically change entity models, not via KV as it's buggy.
5. Entity spawn notification (with classname and entity index) -- not talking about OnPostSpawn() or PreSpawnInstance() as those don't work for everything. I am referring to adding onto gEntList's CUtlVector<IEntityListener*> and making those outputs visible to vscripts preferably.
6. A method to get the eye position. (We can always z += 64.0 though, but gets hard when player is crouching or whatever)
7. A method to get the forward vector from any given angle.
8. A method to trace from one entity infinitely in a given direction vector (an "infinite" raytrace). Not really needed though, as we can always just add a large forward vector.
9. A method to "read"/get keyvalues.
10. A method to respawn dead players, "stumble"/stagger players, drop molotov or bilebomb or pipebomb at specified location (activated-- not world spawns).
11. Forced map changing! Something like ChangeLevel(string mapName). <------ SUPER HELPFUL :)
12. Convert CBaseEntity back to entity index. Currently the workaround I am doing is using a large entity loop, 1 to 2048. It'd save processing if we can retrieve the ent index via a native.
13. IsPressingButton() - e.g. BUTTON_ATTACK, BUTTON_ATTACK2, BUTTON_JUMP, etc.
14. SayClient() or equivalent. Also would be nice if the "Console:" text doesn't get added on to the text we send. This would be unnecessary if #3 is added in.
15. Sockets library would be AWESOME.
16. Client command / unbroadcasted client command
17. Auto option for zspawn(). I.e. like "z_spawn boomer auto" in console.
18. Something that fires more often than Update(), specifically OnGameFrame().



EDIT: The following have been resolved/added/identified:
- CTerrorPlayer::OnTakeDamage() hook
- EyeAngles()


Bugs Discovered:
1. Sometimes, the trace ray appears to return entity -1 of classname "worldspawn". Applying an impulse to entity -1 (I have no idea how such an entity is valid) with ApplyAbsVelocityImpulse() will cause the character to go nuts. I recorded a video to illustrate:
http://www.youtube.com/watch?v=XLZHASqht0M


Lastly, thank you Valve for all of your hard work! The mapping/modding/dev community really appreciate all the time that you put into your games. Keep up the good work!
Last edited by Neil - 119; 7 Apr, 2013 @ 4:59pm
< >
Showing 1-15 of 75 comments
Fish 10 Mar, 2013 @ 12:18pm 
OnGameEvent_{EVENT} exists.. All events are contained within modevents.res
Rectus 10 Mar, 2013 @ 1:01pm 
Also, instead of OnTakeDamage(), there is a AllowTakeDamage(damageTable) hook, which can prevent the damage done by returning false.
A lot of the useful stuff is documented here.
shotgunefx 10 Mar, 2013 @ 3:31pm 
As others pointed out, some of the stuff is already there, though some stuff not yet on the wiki...

CTerrorPlayer.IsSurvivor()
CTerrorPlayer.GetActiveWeapon()

I would love to get/set keyvalues, but as far as m_zombieClass, there is also CTerrorPlayer.GetZombieType(). I wish there was a generic SpawnZombie callback which would allow you to change the zombie about to spawn as well as model,health, etc, sort of like EnvEntityMaker, but a work around is to hook the spawn event, use the newly spawned zombie's position as input to ZSpawn (as there is no auto option) and kill the original. I use that for Tank Slayer, the one downside is you can hear a second of the original's bacteria sounds.
Neil - 119 10 Mar, 2013 @ 4:10pm 
Thanks for the assistance.

Originally posted by The Fish:
OnGameEvent_{EVENT} exists.. All events are contained within modevents.res
I know. Is there a way to modify that IGameEvent pointer though? If not, shoot, I'll need to continue relying on HammerCode and SourceMod. Just an FYI, instead of checking modevents.res, IMO a more helpful document is here[wiki.alliedmods.net], however that won't be up-to-date obviously.

Originally posted by Rectus:
Also, instead of OnTakeDamage(), there is a AllowTakeDamage(damageTable) hook, which can prevent the damage done by returning false.
A lot of the useful stuff is documented here.
Beautiful, that is just fantastic. Now all I need is the ability to send usermessages and modify netprops. Maybe a function to change an entity's model too.
Last edited by Neil - 119; 10 Mar, 2013 @ 4:38pm
Neil - 119 10 Mar, 2013 @ 4:17pm 
Originally posted by shotgunefx:
As others pointed out, some of the stuff is already there, though some stuff not yet on the wiki...

CTerrorPlayer.IsSurvivor()
CTerrorPlayer.GetActiveWeapon()

I would love to get/set keyvalues, but as far as m_zombieClass, there is also CTerrorPlayer.GetZombieType(). I wish there was a generic SpawnZombie callback which would allow you to change the zombie about to spawn as well as model,health, etc, sort of like EnvEntityMaker, but a work around is to hook the spawn event, use the newly spawned zombie's position as input to ZSpawn (as there is no auto option) and kill the original. I use that for Tank Slayer, the one downside is you can hear a second of the original's bacteria sounds.
Yes, I am aware of those. I was referring to net props in general. For example, check out this script:

http://www.youtube.com/watch?v=602zppb3Swg

It's coded[zombiescanfly.com] that such that it retrieves the m_hThrower from CBaseCSGrenadeProjectile (netprops) to find the owner of the grenade, and then proceeds to target an infected entity. A lot of cool things can be done with netprops, and would be awesome to have in a vscript!
Last edited by Neil - 119; 10 Mar, 2013 @ 4:37pm
shotgunefx 10 Mar, 2013 @ 7:16pm 
It would definitely be very useful. Was just pointing out a work around for that particular situation.
Neil - 119 10 Mar, 2013 @ 7:39pm 
An EntitySpawned and PlayerSpawned callback would be awesome. Just like in SourceMod and HammerCode. I can think of over two dozen cool things to do with them. That, along with netprops and usermessages, and my cries would be heard.
Last edited by Neil - 119; 11 Mar, 2013 @ 3:16pm
Machine 11 Mar, 2013 @ 12:12am 
Those would be useful.

I'm very interested in the Pickup and drop functions on custom physics props. Is it possible to get the held entity index from a player if he is holding something? Like if a player holding a key uses a lock to make a door open without needing to drop it? Interacting with custom props could bring alot of creativity in puzzle type maps.
Neil - 119 11 Mar, 2013 @ 8:43am 
Last edited by Neil - 119; 11 Mar, 2013 @ 3:16pm
Tedgrocer 11 Mar, 2013 @ 10:34am 
Originally posted by Machine:
Those would be useful.

I'm very interested in the Pickup and drop functions on custom physics props. Is it possible to get the held entity index from a player if he is holding something? Like if a player holding a key uses a lock to make a door open without needing to drop it? Interacting with custom props could bring alot of creativity in puzzle type maps.
The GnomeHunter tutorial might be right up your alley. Although, I'm not sure if that will satisfy everything you require. https://developer.valvesoftware.com/wiki/L4D2_EMS/GnomeHunter_tutorial_1
shotgunefx 11 Mar, 2013 @ 1:42pm 
You can hook player_spawn, and also player_first_spawn. As far as usable props, most of the stuff that's new so far works in both regular campaigns and mutations, but in my tests, it "seems", not CanPickupObject(). Though you can just hook player_use and manage it that way.
Neil - 119 11 Mar, 2013 @ 2:23pm 
Originally posted by shotgunefx:
You can hook player_spawn, and also player_first_spawn. As far as usable props, most of the stuff that's new so far works in both regular campaigns and mutations, but in my tests, it "seems", not CanPickupObject(). Though you can just hook player_use and manage it that way.

Technically, we are not hooking a function unless we can modify or augment the outcome of the function. From what I've been told, we cannot modify the game event params (please confirm), but rather just "listen" for them.

Also, from what I can see in my modevents.res, there is no player_spawn, but there is a player_first_spawn, but I still have the older non-beta L4D2 installed. IMO, it's still not as solid as a hook to SurvivorBot::Spawn(), because I have seen instances where the event is never broadcasted (during my long hours of SM and HC modding). To prevent items from being picked up dynamically, I've always hooked CBaseEntity::Use(), and I have no idea if that can be done in EMS (maybe there is an alternative way or workaround, perhaps CanPickupObject). It would be helpful if Valve provided us modders with more hooks. For example, CTerrorPlayer::Weapon_CanUse(), NextBotPlayer<CTerrorPlayer>::Weapon_Equip(), SurvivorBot::Weapon_Switch() to name a few more. Again, there may be a workaround for these. I am just naming some that I have hooked in my c++ server plugin that I couldn't find with vscripts. Lastly, getting and setting netprops, e.g. sample function from my c++ valve server plugin (VSP):


static int GetEntityPropInt(lua_State* L) { OUTPUT_FUNC; edict_t* edict = CheckEntity(L, 1); if (!edict) { lua_pushnumber(L, -1); return 1; } CBaseEntity* ent = g_HCBase->EdictToBaseEntity(edict); if (!ent) { lua_pushnumber(L, -1); return 1; } IServerUnknown* pUnk = (IServerUnknown*)ent; IServerNetworkable* pNet = pUnk->GetNetworkable(); if (!pNet) { lua_pushnumber(L, -1); return 1; } char* prop = const_cast<char*>(luaL_checkstring(L, 2)); char* serverclass = const_cast<char*>(pNet->GetServerClass()->GetName()); int intval = g_HCBase->GetPropertyInt(serverclass, prop, edict); lua_pushnumber(L, intval); return 1; } int HammerCodeBase::GetPropertyInt(char* pClassname, char* pNetProp, edict_t* pEdict) { CBaseEntity* pEntity = EdictToBaseEntity(pEdict); if (!pEntity) return -1; int element = 0; int bit_count = 0; bool isDataMap = false; int size = 4; int offset = Base_FindOffset(pClassname, pNetProp, pEntity, &bit_count, &element, &isDataMap); if (!offset) return -1; bool is_unsigned = false; if (!isDataMap) { Vector data = GetBitCountData(pClassname, pNetProp, pEntity, offset); bit_count = data[0]; is_unsigned = (bool)data[3]; } // Credits for this last part go to SM if (bit_count < 1) bit_count = size * 8; if (bit_count >= 17) return *(int32_tr *)((uint8_tr *)pEntity + offset); else if (bit_count >= 9) { if (is_unsigned) return *(uint16_tr *)((uint8_tr *)pEntity + offset); else return *(int16_tr *)((uint8_tr *)pEntity + offset); } else if (bit_count >= 2) { if (is_unsigned) return *(uint8_tr *)((uint8_tr *)pEntity + offset); else return *(int8_tr *)((uint8_tr *)pEntity + offset); } else return *(bool *)((uint8_tr *)pEntity + offset) ? 1 : 0; }


I personally cannot think of any rational way of coding a function like that running off Squirrel VM :P It would be highly appreciated to have a method to modify netprops in our scripts. Maybe a wrapper function for IVEngineServer::UserMessageBegin() too! :)
Last edited by Neil - 119; 15 Mar, 2013 @ 4:13pm
shotgunefx 11 Mar, 2013 @ 8:13pm 
I'm going to guess no, though while I have an idea of what's going on in that code, I'm not 100% ;) Is it trying to determine the offset from a prop to another entity?

You're right about most events, you are passively receiving them. Not all events are in modevent.res btw, those are just the custom L4D2 ones. When in doubt, use display_game_events 1. spawn and first_spawn definitely work. I use both in Tank Slayer,
Fish 12 Mar, 2013 @ 1:42am 
Players don't "spawn" as such. They spawn the first time where they are inititilized, and when dead are just dormant. They are then rescued, and the modevent reflects this. "survivor_rescued" is in the modevents.

All the events seem to be in the update folder modevent.res, the left4dead2/resources/modevents.res appears to be out of date.
Neil - 119 12 Mar, 2013 @ 7:21am 
@shotgunefx: Ah, that's a good concmd to know :) As for the c++ function, it retrieves an integer netprop and pushes the value back onto the Lua stack.

@The Fish: If you change teams, SurvivorBot::Spawn() seems to fire again (and over and over again for infected), but the event player_first_spawn does not. You are correct in your reasoning that the client entities are created once.
< >
Showing 1-15 of 75 comments
Per page: 1530 50