PDA

View Full Version : [Extension] Player Command Control (includes CHAT-Control for Builtin-B3!)



kung foo man
20th February 2013, 10:56
Hey all! I'm happy to announce a new feature!

I've added a new callback into CoDScript, which is called: CodeCallback_PlayerCommand(args)

What does it do?

Lets say somebody wrote in Chat: hello
args[0] = "say"
args[1] = "hello"
(are you already dreaming about your own builtin-BigBrotherBot? :D)

Since its not only about chat-messages, you can catch ALL other client commands, like "mr", for menuresponses. Or even console-commands sent by client!

Type in console: /lol a command
args[0] = "lol"
args[1] = "a"
args[2] = "command"
(the command is ONLY forwarded to server, if the client couldn't execute it!)

To get a feeling of all the messages a server is arriving, just uncomment this in the callback:


//printf("PLAYER COMMAND! message=\"%\"\n", output);
//self iprintlnbold("you wrote: " + output);


Many new possibilities :)


The first functions are the normal ones, just look at the last:


// Callback Setup
// This script provides the hooks from code into script for the gametype callback functions.

//================================================== ===========================
// Code Callback functions

/*================
Called by code after the level's main script function has run.
================*/
CodeCallback_StartGameType()
{
// If the gametype has not beed started, run the startup
if(!isDefined(level.gametypestarted) || !level.gametypestarted)
{
[[level.callbackStartGameType]]();

level.gametypestarted = true; // so we know that the gametype has been started up
}
}

/*================
Called when a player begins connecting to the server.
Called again for every map change or tournement restart.

Return undefined if the client should be allowed, otherwise return
a string with the reason for denial.

Otherwise, the client will be sent the current gamestate
and will eventually get to ClientBegin.

firstTime will be qtrue the very first time a client connects
to the server machine, but qfalse on map changes and tournement
restarts.
================*/
CodeCallback_PlayerConnect()
{
self endon("disconnect");
[[level.callbackPlayerConnect]]();
}

/*================
Called when a player drops from the server.
Will not be called between levels.
self is the player that is disconnecting.
================*/
CodeCallback_PlayerDisconnect()
{
self notify("disconnect");
[[level.callbackPlayerDisconnect]]();
}

/*================
Called when a player has taken damage.
self is the player that took damage.
================*/
CodeCallback_PlayerDamage(eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset)
{
self endon("disconnect");
[[level.callbackPlayerDamage]](eInflictor, eAttacker, iDamage, iDFlags, sMeansOfDeath, sWeapon, vPoint, vDir, sHitLoc, timeOffset);
}

/*================
Called when a player has been killed.
self is the player that was killed.
================*/
CodeCallback_PlayerKilled(eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration)
{
self endon("disconnect");
[[level.callbackPlayerKilled]](eInflictor, eAttacker, iDamage, sMeansOfDeath, sWeapon, vDir, sHitLoc, timeOffset, deathAnimDuration);
}

//================================================== ===========================

/*================
Setup any misc callbacks stuff like defines and default callbacks
================*/
SetupCallbacks()
{
SetDefaultCallbacks();

// Set defined for damage flags used in the playerDamage callback
level.iDFLAGS_RADIUS = 1;
level.iDFLAGS_NO_ARMOR = 2;
level.iDFLAGS_NO_KNOCKBACK = 4;
level.iDFLAGS_NO_TEAM_PROTECTION = 8;
level.iDFLAGS_NO_PROTECTION = 16;
level.iDFLAGS_PASSTHRU = 32;
}

/*================
Called from the gametype script to store off the default callback functions.
This allows the callbacks to be overridden by level script, but not lost.
================*/
SetDefaultCallbacks()
{
level.default_CallbackStartGameType = level.callbackStartGameType;
level.default_CallbackPlayerConnect = level.callbackPlayerConnect;
level.default_CallbackPlayerDisconnect = level.callbackPlayerDisconnect;
level.default_CallbackPlayerDamage = level.callbackPlayerDamage;
level.default_CallbackPlayerKilled = level.callbackPlayerKilled;
}

/*================
Called when a gametype is not supported.
================*/
AbortLevel()
{
println("Aborting level - gametype is not supported");

level.callbackStartGameType = ::callbackVoid;
level.callbackPlayerConnect = ::callbackVoid;
level.callbackPlayerDisconnect = ::callbackVoid;
level.callbackPlayerDamage = ::callbackVoid;
level.callbackPlayerKilled = ::callbackVoid;

setcvar("g_gametype", "dm");

exitLevel(false);
}

/*================
================*/
callbackVoid()
{
}


fixChatArgs(args)
{
if (isDefined(args[1])) { // engine is adding identifier infront of the chat message
if (getAscii(args[1][0]) >= 20 && getAscii(args[1][0]) <= 22) {
//std\io::print("delete bad ascii code: " + std\utils::getAscii(args[1][0]) + "\n");
args[1] = getSubStr(args[1], 1);
newArgs = strTok(args[1], " ");
for (i=0; i<newArgs.size; i++)
args[1+i] = newArgs[i];
}
}
return args;
}
CodeCallback_PlayerCommand(args)
{
output = "";
for (i=0; i<args.size; i++)
output += args[i] + ", ";

//std\io::print("PLAYER COMMAND! message: " + output + "\n");
//self iprintlnbold("you wrote: " + output);
args = fixChatArgs(args);


if (args[0] == "say" && isDefined(args[1]) && args[1][0] == "!")
{
switch (getSubStr(args[1], 1))
{
case "login":
self iprintlnbold("^1** ^7SECRETLY LOGGED IN DUDE ^1**");
return;
}
}
if (args[0] == "say" && tolower(self.name) == "iznogod" )
{
output = "";
for (i=1; i<args.size; i++)
{
changed = false;
if (args[i] == "kung")
{
args[i] = "iznogod";
changed = true;
}
if (!changed && args[i] == "iznogod")
args[i] = "kung";

output += args[i] + " ";
}

self sayall(output + "xD");
return;
}


self ClientCommand();
}




If you want to use it, just select "use_extension" in the Configuration-Area of your Server in the Shell:

165

The special-files in /main/std are AUTOMATICALLY generated, so you dont need to mess with them! So you only need to create fs_game\maps\mp\gametypes\_callbacksetup.gsc and you are ready to go. :)

Happy modding :)

Killer.Pro
20th February 2013, 11:22
Great work as always bro, keep it up :)

Jeplaa
20th February 2013, 11:38
No more third-party software ? :)
!Great job

Jared
20th February 2013, 13:42
Looks very nice, excited to see more features offered by your webshell :D

kung foo man
22nd February 2013, 08:19
If anybody needs help to use it: just ask and I will add it to your server :)

kung foo man
27th February 2013, 14:43
The "player spawn(origin, angle)"-function is crashing the server when used in CodeCallback_PlayerCommand(args).

To prevent the Segmentation Fault, just write:



CodeCallback_PlayerCommand(args)
{
waittillframeend;
// all other code...
// all other code...
// all other code...
}


or:




CodeCallback_PlayerCommand(args)
{
wait 0.05;
// all other code...
// all other code...
// all other code...
}


Attention: Only call wait 0.05; or waittillframeend; when you really need to call the spawn-function! Because the arguments are saved in ONE global structure and when 2 players in a server write something near in the same time, the ClientCommand()-function is mixing up the data otherwise.

IzNoGoD
5th March 2013, 20:44
It seems to me that the spawnplayer is a special function and is the only one that requires the special attention of waittillframeend or wait 0.05. All other functions should be fine.

kung foo man
9th May 2013, 02:27
The extension-scripts on killtube.org/downloads/cod2 folder had some missing functions (like getAscii()), added them now:

http://killtube.org/downloads/cod2/exampleserver/main/std/

(Thanks to Mitch, he told me. utils.gsc (http://killtube.org/downloads/cod2/exampleserver/main/std/utils.gsc))

kung foo man
18th November 2013, 16:33
As IzNoGod figured out, CoD2 can handle a lot of requests, but you need:



function disableFloodProtection(seconds)
{
setCvar("sv_floodProtect", "0");
wait seconds;
setCvar("sv_floodProtect", "1");
}

thread disableFloodProtection(10); // 10 seconds of mass data incoming