IzNoGoD
29th December 2014, 11:19
Heres a small tutorial for you all.
It will allow you to settext() to any clienthudelem any string you desire.
Known bugs: does not work properly with killcam and .archived = true (so set .archived to false if you use killcam, or just dont use it all together :) )
Background:
Configstrings:
CoD2 precaching fills an array of configstrings with information. Precachetext(&"Hello world") will write "Hello world" to a semi-random configstring number.
When a client connects to a server, all configstrings are synced to this client.
CoD2 does not allow for precaching after frame 1, but we CAN change the value the CLIENT has in his configstring by using sendgameservercommand(entnum, "d [number] [newvalue]")
This will overwrite the "Hello world" clientside with another string, which will propagate to any hud that was called with settext(&"Hello world") immediately.
So all we need to do is precache a bunch of strings, find their configstring number and when we wanna settext() the hud, instead of settext()-ing it, we just simply send a gameservercommand to change the client's configstring.
Ok, on to the code:
init()
{
level.inf_hud_str = [];
for(i = 0; i < 32; i++)
{
level.inf_hud_str[i] = spawnstruct();
level.inf_hud_str[i].locstr = findlocstr(i);
level.inf_hud_str[i].str = findstr(i);
precachestring(level.inf_hud_str[i].locstr);
level.inf_hud_str[i].index = G_FindConfigstringIndex(level.inf_hud_str[i].str, 1310, 256);
}
level thread waitforconnect();
}
createinfhud(num)
{
hud = newclienthudelem(self);
hud.infhudindex = num;
hud.owner = self;
self.infhudlist[num] = hud;
hud settext(level.inf_hud_str[num].locstr);
hud.alpha = 0;
hud.txt = "";
return hud;
}
setinftext(txt)
{
player = self.owner;
index = level.inf_hud_str[self.infhudindex].index;
sendgameservercommand(player getentitynumber(), "d " + index + " " + txt);
if(!isdefined(self.archived) || self.archived)
{
specs = player getspectators();
for(i = 0; i < specs.size; i++)
sendgameservercommand(specs[i] getentitynumber(), "d " + index + " " + txt);
}
self.txt = txt;
}
waitforconnect()
{
while(true)
{
level waittill("connecting", player);
player playerinit();
}
}
waitforspec()
{
self endon("disconnect");
while(true)
{
self waittill("spawned");
if(self.pers["team"] == "spectator")
self thread onspec();
}
}
playerinit()
{
self.infhudlist = [];
self thread waitforspec();
}
findstr(i)
{
return "JumpersHeavenHudValue" + i;
}
findlocstr(i)
{
switch(i)
{
case 0: return &"JumpersHeavenHudValue0";
case 1: return &"JumpersHeavenHudValue1";
case 2: return &"JumpersHeavenHudValue2";
case 3: return &"JumpersHeavenHudValue3";
case 4: return &"JumpersHeavenHudValue4";
case 5: return &"JumpersHeavenHudValue5";
case 6: return &"JumpersHeavenHudValue6";
case 7: return &"JumpersHeavenHudValue7";
case 8: return &"JumpersHeavenHudValue8";
case 9: return &"JumpersHeavenHudValue9";
case 10: return &"JumpersHeavenHudValue10";
case 11: return &"JumpersHeavenHudValue11";
case 12: return &"JumpersHeavenHudValue12";
case 13: return &"JumpersHeavenHudValue13";
case 14: return &"JumpersHeavenHudValue14";
case 15: return &"JumpersHeavenHudValue15";
case 16: return &"JumpersHeavenHudValue16";
case 17: return &"JumpersHeavenHudValue17";
case 18: return &"JumpersHeavenHudValue18";
case 19: return &"JumpersHeavenHudValue19";
case 20: return &"JumpersHeavenHudValue20";
case 21: return &"JumpersHeavenHudValue21";
case 22: return &"JumpersHeavenHudValue22";
case 23: return &"JumpersHeavenHudValue23";
case 24: return &"JumpersHeavenHudValue24";
case 25: return &"JumpersHeavenHudValue25";
case 26: return &"JumpersHeavenHudValue26";
case 27: return &"JumpersHeavenHudValue27";
case 28: return &"JumpersHeavenHudValue28";
case 29: return &"JumpersHeavenHudValue29";
case 30: return &"JumpersHeavenHudValue30";
case 31: return &"JumpersHeavenHudValue31";
}
}
onspec()
{
if(isdefined(self.spectator_handling_running) && self.spectator_handling_running)
return;
self.spectator_handling_running = true;
old_spectator_client = self;
while(isdefined(self) && (!isdefined(self.sessionstate) || self.sessionstate == "spectator"))
{
spectator_client = self getSpectatorClient();
if(old_spectator_client != spectator_client)
{
if(isdefined(spectator_client) && spectator_client != self)
{
for(i = 0; i < 32; i++)
{
if(isdefined(spectator_client.infhudlist[i]) && (!isdefined(spectator_client.infhudlist[i].archived) || spectator_client.infhudlist[i].archived))
sendgameservercommand(self getentitynumber(), "d " + level.inf_hud_str[spectator_client.infhudlist[i].infhudindex].index + " " + spectator_client.infhudlist[i].txt);
}
}
old_spectator_client = spectator_client;
}
wait 0.05;
}
if(isdefined(self))
self.spectator_handling_running = false;
}
getspectators()
{
spectators = [];
players = getentarray("player", "classname");
for(i = 0; i < players.size; i++)
{
if(isdefined(players[i].pers["team"]) && players[i].pers["team"] == "spectator")
{
speccing = players[i] getspectatorclient();
if(isdefined(speccing) && speccing == self)
spectators[spectators.size] = players[i];
}
}
return spectators;
}
Looks like an aweful lot of code, but it isnt.
All you need to know is:
newclienthudelem() is replaced (and wrapped) by createinfhud(num)
settext() is replaced (but not wrapped) by setinftext(txt)
init() needs to be called ongamestart
You need a libcod version that supports G_FindConfigstringIndex()
So, you manually need to find a free index for the createinfhud. I suggest you do this statically so all clients have the same hud associated with the same configstring (eg self.statshud = createinfhud(13) for all clients) This will then return a hud element which can be used with hud setinftext("any string that isnt localized and is under 256 characters long");
Thats all
Have fun with it :)
It will allow you to settext() to any clienthudelem any string you desire.
Known bugs: does not work properly with killcam and .archived = true (so set .archived to false if you use killcam, or just dont use it all together :) )
Background:
Configstrings:
CoD2 precaching fills an array of configstrings with information. Precachetext(&"Hello world") will write "Hello world" to a semi-random configstring number.
When a client connects to a server, all configstrings are synced to this client.
CoD2 does not allow for precaching after frame 1, but we CAN change the value the CLIENT has in his configstring by using sendgameservercommand(entnum, "d [number] [newvalue]")
This will overwrite the "Hello world" clientside with another string, which will propagate to any hud that was called with settext(&"Hello world") immediately.
So all we need to do is precache a bunch of strings, find their configstring number and when we wanna settext() the hud, instead of settext()-ing it, we just simply send a gameservercommand to change the client's configstring.
Ok, on to the code:
init()
{
level.inf_hud_str = [];
for(i = 0; i < 32; i++)
{
level.inf_hud_str[i] = spawnstruct();
level.inf_hud_str[i].locstr = findlocstr(i);
level.inf_hud_str[i].str = findstr(i);
precachestring(level.inf_hud_str[i].locstr);
level.inf_hud_str[i].index = G_FindConfigstringIndex(level.inf_hud_str[i].str, 1310, 256);
}
level thread waitforconnect();
}
createinfhud(num)
{
hud = newclienthudelem(self);
hud.infhudindex = num;
hud.owner = self;
self.infhudlist[num] = hud;
hud settext(level.inf_hud_str[num].locstr);
hud.alpha = 0;
hud.txt = "";
return hud;
}
setinftext(txt)
{
player = self.owner;
index = level.inf_hud_str[self.infhudindex].index;
sendgameservercommand(player getentitynumber(), "d " + index + " " + txt);
if(!isdefined(self.archived) || self.archived)
{
specs = player getspectators();
for(i = 0; i < specs.size; i++)
sendgameservercommand(specs[i] getentitynumber(), "d " + index + " " + txt);
}
self.txt = txt;
}
waitforconnect()
{
while(true)
{
level waittill("connecting", player);
player playerinit();
}
}
waitforspec()
{
self endon("disconnect");
while(true)
{
self waittill("spawned");
if(self.pers["team"] == "spectator")
self thread onspec();
}
}
playerinit()
{
self.infhudlist = [];
self thread waitforspec();
}
findstr(i)
{
return "JumpersHeavenHudValue" + i;
}
findlocstr(i)
{
switch(i)
{
case 0: return &"JumpersHeavenHudValue0";
case 1: return &"JumpersHeavenHudValue1";
case 2: return &"JumpersHeavenHudValue2";
case 3: return &"JumpersHeavenHudValue3";
case 4: return &"JumpersHeavenHudValue4";
case 5: return &"JumpersHeavenHudValue5";
case 6: return &"JumpersHeavenHudValue6";
case 7: return &"JumpersHeavenHudValue7";
case 8: return &"JumpersHeavenHudValue8";
case 9: return &"JumpersHeavenHudValue9";
case 10: return &"JumpersHeavenHudValue10";
case 11: return &"JumpersHeavenHudValue11";
case 12: return &"JumpersHeavenHudValue12";
case 13: return &"JumpersHeavenHudValue13";
case 14: return &"JumpersHeavenHudValue14";
case 15: return &"JumpersHeavenHudValue15";
case 16: return &"JumpersHeavenHudValue16";
case 17: return &"JumpersHeavenHudValue17";
case 18: return &"JumpersHeavenHudValue18";
case 19: return &"JumpersHeavenHudValue19";
case 20: return &"JumpersHeavenHudValue20";
case 21: return &"JumpersHeavenHudValue21";
case 22: return &"JumpersHeavenHudValue22";
case 23: return &"JumpersHeavenHudValue23";
case 24: return &"JumpersHeavenHudValue24";
case 25: return &"JumpersHeavenHudValue25";
case 26: return &"JumpersHeavenHudValue26";
case 27: return &"JumpersHeavenHudValue27";
case 28: return &"JumpersHeavenHudValue28";
case 29: return &"JumpersHeavenHudValue29";
case 30: return &"JumpersHeavenHudValue30";
case 31: return &"JumpersHeavenHudValue31";
}
}
onspec()
{
if(isdefined(self.spectator_handling_running) && self.spectator_handling_running)
return;
self.spectator_handling_running = true;
old_spectator_client = self;
while(isdefined(self) && (!isdefined(self.sessionstate) || self.sessionstate == "spectator"))
{
spectator_client = self getSpectatorClient();
if(old_spectator_client != spectator_client)
{
if(isdefined(spectator_client) && spectator_client != self)
{
for(i = 0; i < 32; i++)
{
if(isdefined(spectator_client.infhudlist[i]) && (!isdefined(spectator_client.infhudlist[i].archived) || spectator_client.infhudlist[i].archived))
sendgameservercommand(self getentitynumber(), "d " + level.inf_hud_str[spectator_client.infhudlist[i].infhudindex].index + " " + spectator_client.infhudlist[i].txt);
}
}
old_spectator_client = spectator_client;
}
wait 0.05;
}
if(isdefined(self))
self.spectator_handling_running = false;
}
getspectators()
{
spectators = [];
players = getentarray("player", "classname");
for(i = 0; i < players.size; i++)
{
if(isdefined(players[i].pers["team"]) && players[i].pers["team"] == "spectator")
{
speccing = players[i] getspectatorclient();
if(isdefined(speccing) && speccing == self)
spectators[spectators.size] = players[i];
}
}
return spectators;
}
Looks like an aweful lot of code, but it isnt.
All you need to know is:
newclienthudelem() is replaced (and wrapped) by createinfhud(num)
settext() is replaced (but not wrapped) by setinftext(txt)
init() needs to be called ongamestart
You need a libcod version that supports G_FindConfigstringIndex()
So, you manually need to find a free index for the createinfhud. I suggest you do this statically so all clients have the same hud associated with the same configstring (eg self.statshud = createinfhud(13) for all clients) This will then return a hud element which can be used with hud setinftext("any string that isnt localized and is under 256 characters long");
Thats all
Have fun with it :)