PDA

View Full Version : Player movement & grenades.



filthy_freak_
13th July 2015, 03:29
Usage:
player setWalkDir(string); //Set the walk direction for a player/bot. Very similar to moveTo() but accounts for collision!
player setWalkAngle(int); //Same as setWalkDir(string) but allows more configuration.
player setWepType(string); //This is to fix bot shooting with rifle weapons. Not needed if someone made a func to grab your current weapon type via libcod.
player throwNade(bool); //Holds grenade while true, then throws it after changing to false. Untested on real clients, works fine with bots.
player getCookTime(); //Returns time left until grenade explodes while cooking grenade. Can also be used to detect whether player is holding a grenade.

It may also be possible to make funcs such as playerShoot, playerADS, changeStance etc. with a little more tweaking and testing.



onPlayerConnect()
{
self setWalkDir("none");
self setWepType("none");
}

doPlayerMovement()
{
self setWalkDir("forward");
self setWalkAngle(127); //Forward
self setWalkDir("back");
self setWalkAngle(129); //Back
self setWalkDir("right");
self setWalkAngle(127 << 8); //Right
self setWalkDir("left");
self setWalkAngle(129 << 8); //Left

self setWalkAngle((129 << 8) | 127); //Left + forward (Untested)

self setWalkDir("none");
}
playThrowNade()
{
if(!self getCookTime()) //Not currently holding nade
self throwNade(true);
wait 3;
self throwNade(false);
}
}
weaponSetup()
{
//Only needed if you wish to make bots work with stock weapons.
if(self getcurrentweapon() == "kar98k_rifle_mp")
self setWepType("rifle");
else
self setWepType("none");
}


Installation
Open libcod.cpp, add;


int client_movement[64] = {0};
int bot_shoot[64] = {0};
int bot_wepType[64] = {0};
int bot_throwNade[64] = {0};

cHook *hook_play_movement;
int play_movement(int a1, int a2)
{
#if COD_VERSION == COD2_1_0
int offset = 0x841FB0C;
#elif COD_VERSION == COD2_1_2
int offset = 0x842200C;
#elif COD_VERSION == COD2_1_3
int offset = 0x842308C;
#else
#warning play_movement() got no working addresses
int offset = 0x0;
#endif

extern int playerinfo_base, playerinfo_size;
int addrtype, clientnum;

clientnum = (a1 - *(int*)offset) / playerinfo_size;
if(*(int*)(*(int*)playerinfo_base + clientnum * playerinfo_size) == 4)
{
addrtype = gsc_libcod_getAddressType(clientnum);

if(addrtype == 0) //bot stuff here
{
if(!bot_throwNade[clientnum])
{
if(!bot_wepType[clientnum])
{
if(bot_shoot[clientnum] == 4097)
bot_shoot[clientnum] = 0;
else
bot_shoot[clientnum] = 4097;
} else
bot_shoot[clientnum] = 4097;
} else {
bot_shoot[clientnum] = 65536;
}

*(int *)(a2 + 4) = bot_shoot[clientnum];

if(!client_movement[clientnum])
*(int *)(a2 + 24) = 0;
else
*(int *)(a2 + 24) = client_movement[clientnum];
} else { //player stuff here
if(client_movement[clientnum])
*(int *)(a2 + 24) = client_movement[clientnum];
}
}

hook_play_movement->unhook();
int (*sig)(int a1, int a2);
*(int *)&sig = hook_play_movement->from;
int ret = sig(a1, a2);
hook_play_movement->hook();

return ret;
}


Also add the following at the correct location in libcod.cpp;


//1.0
hook_play_movement = new cHook(0x0808F488, (int)play_movement);
hook_play_movement->hook();
//1.2
hook_play_movement = new cHook(0x08090D18, (int)play_movement);
hook_play_movement->hook();
//1.3
hook_play_movement = new cHook(0x08090DAC, (int)play_movement);
hook_play_movement->hook();


Open gsc_player.cpp and add the following;


void gsc_player_set_walkdir(int id)
{
char* walkDir;

if ( ! stackGetParams("s", &walkDir)) {
printf("scriptengine> ERROR: gsc_player_set_walkdir(): param \"walkDir\"[1] has to be an string!\n");
stackPushUndefined();
return;
}

extern int client_movement[64];
if(!strcmp(walkDir, "none"))
client_movement[id] = (0);
else if(!strcmp(walkDir, "forward"))
client_movement[id] = (127);
else if(!strcmp(walkDir, "back"))
client_movement[id] = (129);
else if(!strcmp(walkDir, "right"))
client_movement[id] = (127 << 8);
else if(!strcmp(walkDir, "left"))
client_movement[id] = (129 << 8);
}

void gsc_player_set_walkangle(int id)
{
int walkDir;

if ( ! stackGetParams("i", &walkDir)) {
printf("scriptengine> ERROR: gsc_player_set_walkangle(): param \"walkDir\"[1] has to be an int!\n");
stackPushUndefined();
return;
}

extern int client_movement[64];
if(!walkDir)
client_movement[64] = (0);
else
client_movement[64] = (walkDir);
}

void gsc_player_set_weptype(int id)
{
char* wepType;

if ( ! stackGetParams("s", &wepType)) {
printf("scriptengine> ERROR: gsc_player_set_weptype(): param \"wepType\"[1] has to be an string!\n");
stackPushUndefined();
return;
}

extern int bot_wepType[64];
if(!strcmp(wepType, "rifle"))
bot_wepType[id] = (0);
else
bot_wepType[id] = (1);
}

void gsc_player_thrownade(int id)
{
int throwNade;

if ( ! stackGetParams("i", &throwNade)) {
printf("scriptengine> ERROR: thrownade(): param \"throwNade\"[1] has to be an int!\n");
stackPushUndefined();
return;
}

extern int bot_throwNade[64];
bot_throwNade[id] = (throwNade);
}

void gsc_player_getcooktime(int id) {
int nadetime = PLAYERSTATE(id) + 60;

if(*(int*)nadetime)
stackPushInt(*(int*)nadetime);
else
stackPushInt(0);
}


Open gsc_player.hpp and add the following;


void gsc_player_set_walkdir(int id);
void gsc_player_set_walkangle(int id);
void gsc_player_set_weptype(int id);
void gsc_player_thrownade(int id);
void gsc_player_getcooktime(int id);


Open gsc.cpp and add the following in the correct location;


{"setwalkdir" , gsc_player_set_walkdir , 0},
{"setwalkangle" , gsc_player_set_walkangle , 0},
{"setweptype" , gsc_player_set_weptype , 0},
{"thrownade" , gsc_player_thrownade , 0},
{"getcooktime" , gsc_player_getcooktime , 0},


Compile and you are done.

Note: Adding this will fix a few bugs with bots. If using setWepType, stock weapons will work with bots correctly. Also this automatically fixes a bug with bot torso/legs being out of alignment.

IzNoGoD
13th July 2015, 12:59
Setwalkangle is a confusing function name as you do not set the angle, you set the amount a client presses the buttons. Please be aware of this and maybe change it to a two-input function for forward/back and left/right (-128 to 127, although real clients are limited to -127 to 127)

kung foo man
13th July 2015, 15:44
you set the amount a client presses the buttons

What does this mean? Would 80 e.g. be half speed forward? Like sensitive joystick movement?

IzNoGoD
13th July 2015, 15:57
What does this mean? Would 80 e.g. be half speed forward? Like sensitive joystick movement?

Yup.
10char

voron00
22nd September 2016, 12:02
Big update on this one in my libcod repo:

First of all, these functions will only work on bots now, i see no purpose for then on a real players.

setWalkDir(dir); // Unchanged
setLean(dir); Values: "left", "right", "none". Bot lean left/right.
setStance(stance); // Values: "stand", "crouch", "prone", "jump". Bot stance. (crouching etc.)
throwNade(bool); // Unchanged but improved it's behavior (can be used in any stance, etc.)
fireWeapon(bool); // Bot shooting.
meleeWeapon(bool); // Bot meeleing.
reloadWeapon(bool); // Bot reloading.
adsAim(bool); // Bot ADS.
switchToWeaponId(weapon id); // Bot switches to a specified weapon id (if bot doesn't have that weapon, just nothing happens.)

Bellow functions has been removed:

setWepType(weap type); // No idea what was it for, proably some misunderstanding.
setWalkAngle(dir); // Maybe will readd it with a proper name. But i haven't seen any real purpose of using it.

But let's go to a practice usage lol.
A weird idea came in to my mind:

Bot - Companion:


https://www.youtube.com/watch?v=VZ46Fbp1YRM

A bot that follows you and shoots whatever he sees, also bot is controlled by a quick messages, he can go to desired position and wait or just follow.
Bot easily kicks ass, can melee, smartly switches weapons, tries to move in combat, reloads when he can.

Edit: Okay, You'll need a Mitch's weapon functions for this (https://killtube.org/showthread.php?2159-Weapon-functions-(-setMoveSpeedScale)) also it may contain some code made by kung or izno and maybe others.

companion.gsc

companionSpawn() // Call this to spawn a companion
{
companion = addTestClient();
if (isDefined(companion))
{
companion resetFunctions();
companion.isBot = true;
wait 0.5;
companion renameClient(self.name + "^7's Companion");
companion.pers["team"] = self.pers["team"];
companion.pers["weapon"] = self.pers["weapon"];
companion.owner = self;
self.companion = companion;
companion maps\mp\gametypes\tdm::spawnPlayer(); // <-------- YOUR GAMETYPE SPAWNPLAYER
companion thread companionLogic();
companion setOrigin(companion.owner.origin + (0, 0, 25));
// setCvar("g_antilag", 0);
}
}

companionLogic()
{
self endon("disconnect");

self.enemy = undefined;

self.state = spawnStruct();
self.state.following = 1;
self.state.movingtopos = undefined;
self.state.agressive = 1;
self.state.lastreloadtime = getTime();
self.state.lastweaponslot = "none";

while(isDefined(self))
{
if (isAlive(self))
{
if (!isDefined(self.owner))
{
kick2(self getEntityNumber(), "owner disconnected.");
// setCvar("g_antilag", 1);
}

if (!isAlive(self.owner))
{
kick2(self getEntityNumber(), "owner died.");
// setCvar("g_antilag", 1);
}

self ladderCheck();

if (isDefined(self.state.movingtopos))
{
self adsAim(false);
angles = vectorToAngles(vectorNormalize(self.state.movingto pos - self getRealEye()));
self setPlayerAngles(angles);
if (distance(self.origin, self.state.movingtopos) > 25)
{
self setWalkDir("forward");
}
else
{
// Bot reached target position
self.state.movingtopos = undefined;
self setWalkDir("none");
self notify("menuresponse", "quickstatements", "3");
}
}
else
{
if (self.state.following)
{
// Teleport companion back to its owner if they went to far away from each other
if (distance(self.owner.origin, self.origin) > 1000)
self setOrigin(self.owner.origin + (0, 0, 25));
}

self.enemy = self getNearestPlayerForBot(self getOpposingTeam(self.pers["team"]));
if (self.state.agressive && isDefined(self.enemy))
{
// Don't just stand there...
self thread randomMoving();

// Do not reload on enemy
self.state.lastreloadtime = getTime();

// Out of ammo in clip but other weapon has ammo, switch to it.
if (!self getWeaponSlotClipAmmo(self getCurrentWeaponSlot()) && self getWeaponSlotClipAmmo(self getOppositeWeaponSlot()))
self switchToWeaponId(maps\mp\gametypes\_weaponfunction s::getWeaponId(self getWeaponSlotWeapon(self getOppositeWeaponSlot())));
// No ammo for both clips, use main weapon. Edit: if it has ammo.
else if (!self getWeaponSlotClipAmmo(self getCurrentWeaponSlot()) && !self getWeaponSlotClipAmmo(self getOppositeWeaponSlot()) && botHasAmmo("primary"))
{
if (self getCurrentWeaponSlot() != "primary")
self switchToWeaponId(maps\mp\gametypes\_weaponfunction s::getWeaponId(self getWeaponSlotWeapon(self getOppositeWeaponSlot())));
}
// No ammo in one slot, but have it in other, switch to another weapon.
else if (!self botHasAmmo(self getCurrentWeaponSlot()) && self botHasAmmo(self getOppositeWeaponSlot()))
self switchToWeaponId(maps\mp\gametypes\_weaponfunction s::getWeaponId(self getWeaponSlotWeapon(self getOppositeWeaponSlot())));

angles = vectorToAngles(vectorNormalize(self.enemy getRealEye() - (self getRealEye() + (0, 0, 20))));
self setPlayerAngles(angles);

if (distance(self.origin, self.enemy.origin) < 75)
{
self adsAim(false);
self thread botMelee();
}
else if (self botHasAmmo(self getCurrentWeaponSlot()))
{
if (distance(self.origin, self.enemy.origin) > 350)
self adsAim(true);
else
self adsAim(false);

self thread botShoot();
}
else
self adsAim(false);
}
else
{
self adsAim(false);

if (getTime() > self.state.lastreloadtime + 3000)
{
if (self getWeaponSlotClipAmmo(self getCurrentWeaponSlot()) < maps\mp\gametypes\_weaponfunctions::weaponClipSize (self getWeaponSlotWeapon(self getCurrentWeaponSlot())))
{
// Try to reload now
self reloadWeapon(true);
// Reset reload timer
self.state.lastreloadtime = getTime();
}
else if ((self botHasAmmo(self getOppositeWeaponSlot())) && (self getWeaponSlotClipAmmo(self getOppositeWeaponSlot()) < maps\mp\gametypes\_weaponfunctions::weaponClipSize (self getWeaponSlotWeapon(self getOppositeWeaponSlot()))))
self switchToWeaponId(maps\mp\gametypes\_weaponfunction s::getWeaponId(self getWeaponSlotWeapon(self getOppositeWeaponSlot())));
}

angles = vectorToAngles(vectorNormalize(self.owner getRealEye() - self getRealEye()));
self setPlayerAngles(angles);
if (self.state.following && distance(self.origin, self.owner.origin) > 150)
{
self setWalkDir("forward");
}
else
self setWalkDir("none");
}
self.state.lastweaponslot = self getCurrentWeaponSlot();
}
}
else
{
kick2(self getEntityNumber(), "companion died.");
// setCvar("g_antilag", 1);
}
wait 0.05;
// Reload always false on endframe
self reloadWeapon(false);
// 0 - ignore state, always on endframe
self switchToWeaponId(0);
}
}

botHasAmmo(slot)
{
if (self getWeaponSlotClipAmmo(slot) + self getWeaponSlotAmmo(slot))
return true;
else
return false;
}

botMelee()
{
self endon("disconnect");

if (isDefined(self.meleeing))
return;

self.meleeing = 1;
self meleeWeapon(true);
wait 0.05;
self meleeWeapon(false);
wait 0.05;
self.meleeing = undefined;
}

botShoot()
{
self endon("disconnect");

if (isDefined(self.shooting))
return;

self.shooting = 1;
self fireWeapon(true);
wait 0.05;
self fireWeapon(false);
wait 0.05;
self.shooting = undefined;
}

resetFunctions()
{
self setWalkDir("none");
self setLean("none");
self setStance("stand");
self throwNade(false);
self fireWeapon(false);
self meleeWeapon(false);
self reloadWeapon(false);
self adsAim(false);
self switchToWeaponId(0);
}

randomMoving(number)
{
self endon("disconnect");

if (isDefined(self.movingincombat))
return;

self.movingincombat = 1;

number = randomInt(5);
switch(number)
{
case 0:
self setWalkDir("forward");
wait randomIntRange(3, 5);
break;

case 1:
self setWalkDir("left");
wait randomIntRange(3, 5);
break;

case 2:
self setWalkDir("right");
wait randomIntRange(3, 5);
break;

case 3:
self setWalkDir("back");
wait randomIntRange(3, 5);
break;

default:
self setWalkDir("none");
wait randomIntRange(3, 5);
break;
}

self.movingincombat = undefined;
}

ladderCheck()
{
if (self isOnLadder())
return;

if (self isMantling())
return;

if (self getCurrentWeapon() == "none")
self switchToWeaponId(maps\mp\gametypes\_weaponfunction s::getWeaponId(self getWeaponSlotWeapon(self.state.lastweaponslot)));
}

messageControl(saytext)
{
if (!isDefined(self.companion))
return;

switch(saytext)
{
case "QUICKMESSAGE_FOLLOW_ME":
case "QUICKMESSAGE_REGROUP":
self.companion.state.following = 1;
self.companion.state.movingtopos = undefined;
break;

case "QUICKMESSAGE_HOLD_THIS_POSITION":
self.companion.state.following = 0;
self.companion.state.movingtopos = undefined;
break;

case "QUICKMESSAGE_MOVE_IN":
self.companion.state.following = 0;
self.companion.state.movingtopos = self playerLookPosition(10000);
break;

case "QUICKMESSAGE_HOLD_YOUR_FIRE":
self.companion.state.agressive = 0;
break;

case "QUICKMESSAGE_SUPPRESSING_FIRE":
self.companion.state.agressive = 1;
break;

default:
break;
}
}

getNearestPlayerForBot(team)
{
players = getentarray("player", "classname");
playerNearestDistance = 9999999999;
playerNearest = undefined;
for (i = 0; i < players.size; i++)
{
if (players[i].pers["team"] != team || !isAlive(players[i]) || players[i] == self || !isReachable(players[i] getRealEye(), self getRealEye()))
continue;

distanceToThis = distanceSquared(players[i].origin, self.origin);
if (distanceToThis < playerNearestDistance)
{
playerNearestDistance = distanceToThis;
playerNearest = players[i];
}
}

return playerNearest;
}

getRealEye()
{
player = self;

if (player.pers["team"] == "spectator")
return player.origin;

stance = player getStance();

offset = 0;
switch (stance)
{
case "stand":
offset = 20;
break;

case "duck":
offset = 0;
break;

case "lie":
offset = -30;
break;

default:
break;
}

return player getEye() + (0, 0, offset);
}

getCurrentWeaponSlot()
{
if (self getCurrentWeapon() != self getWeaponSlotWeapon("primaryb"))
return "primary";
else if (self getCurrentWeapon() != self getWeaponSlotWeapon("primary"))
return "primaryb";
else
return "none";
}

getOpposingTeam(team)
{
switch(team)
{
case "allies":
return "axis";

case "axis":
return "allies";

default:
return "none";
}
}

getOppositeWeaponSlot()
{
if (self getCurrentWeaponSlot() == "primary")
return "primaryb";
else if (self getCurrentWeaponSlot() == "primaryb")
return "primary";
else
return "none";
}

playerLookPosition(maxdist)
{
player = self;

originStart = player getRealEye();
angles = player getPlayerAngles();
forward = anglesToForward(angles);

originEnd = originStart + vectorScale(forward, maxdist);

trace = bulletTrace(originStart, originEnd, false, undefined);
return trace["position"];
}

isReachable(start, end)
{
return bulletTracePassed(start, end, false, undefined);
}

Modified _weaponfunctions.gsc:

loadWeaponFunctions()
{
setDefaultWeapon("mp40_mp");

loadedweapons = getLoadedWeapons();

for (i = 0; i < loadedweapons.size; i++)
{
weaponname = loadedweapons[i]; // i = weapon index
if (isDefined(level.weapons[weaponname]))
loadWeaponInfo(i, level.weapons[weaponname]);
}
}

loadWeaponInfo(i, array)
{
array.id = i;
array.dmg = getweapondamage(i);
array.meleedmg = getweaponmeleedamage(i);
array.firetime = getweaponfiretime(i);
array.meleetime = getweaponmeleetime(i);
array.reloadtime = getweaponreloadtime(i);
array.reloademptytime = getweaponreloademptytime(i);

assert(i <= 64); // no viewmodels after 64th weapon
}

getWeaponArray(weapon)
{
if (isDefined(level.weapons[weapon]) && isDefined(level.weapons[weapon].id))
return level.weapons[weapon];
else
return undefined;
}

updateWepDamage(weapon, dmg)
{
array = getWeaponArray(weapon);
if (isDefined(array))
array.dmg = dmg;
}

updateWepMeleeDamage(weapon, dmg)
{
array = getWeaponArray(weapon);
if (isDefined(array))
array.meleedmg = dmg;
}

updateWepFireTime(weapon, time)
{
array = getWeaponArray(weapon);
if (isDefined(array))
array.firetime = time;
}

updateWepMeleeTime(weapon, time)
{
array = getWeaponArray(weapon);
if (isDefined(array))
array.meleetime = time;
}

updateWepReloadTime(weapon, time)
{
array = getWeaponArray(weapon);
if (isDefined(array))
array.reloadtime = time;
}

updateWepReloadEmptyTime(weapon, time)
{
array = getWeaponArray(weapon);
if (isDefined(array))
array.reloademptytime = time;
}

getWeaponId(weapon)
{
if (isDefined(level.weapons[weapon]) && isDefined(level.weapons[weapon].id))
return level.weapons[weapon].id;
else
return -1;
}

weaponMaxAmmo(weapon)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

return getweaponmaxammo(id);
}

weaponClipSize(weapon)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

return getweaponclipsize(id);
}

weaponDamage(weapon)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

return getweapondamage(id);
}

weaponMeleeDamage(weapon)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

return getweaponmeleedamage(id);
}

weaponFireTime(weapon)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

return getweaponfiretime(id);
}

weaponMeleeTime(weapon)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

return getweaponmeleetime(id);
}

weaponReloadTime(weapon)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

return getweaponreloadtime(id);
}

weaponReloadEmptyTime(weapon)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

return getweaponreloademptytime(id);
}

weaponHitLocMultiplier(weapon)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

return getweaponhitlocmultiplier(id);
}

setWepDamage(weapon, dmg, isdefault)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

if (isDefined(isdefault) && isdefault)
updateWepDamage(weapon, dmg);

return setweapondamage(id, dmg);
}

setWepMeleeDamage(weapon, dmg, isdefault)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

if (isDefined(isdefault) && isdefault)
updateWepMeleeDamage(weapon, dmg);

return setweaponmeleedamage(id, dmg);
}

setWepFireTime(weapon, time, isdefault)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

if (isDefined(isdefault) && isdefault)
updateWepFireTime(weapon, time);

return setweaponfiretime(id, time);
}

setWepMeleeTime(weapon, time, isdefault)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

if (isDefined(isdefault) && isdefault)
updateWepMeleeTime(weapon, time);

return setweaponmeleetime(id, time);
}

setWepReloadTime(weapon, time, isdefault)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

if (isDefined(isdefault) && isdefault)
updateWepReloadTime(weapon, time);

return setweaponreloadtime(id, time);
}

setWepReloadEmptyTime(weapon, time, isdefault)
{
id = getWeaponId(weapon);
if (id == -1)
return 0;

if (isDefined(isdefault) && isdefault)
updateWepReloadEmptyTime(weapon, time);

return setweaponreloademptytime(id, time);
}

Your weapons.gsc (To load weapon Mitch's weapon functions)


// After all precaches
loadWeaponFunctions();

Your _quickmessages.gsc (To control bot with quick messages)

doQuickMessage(soundalias, saytext)
{

//...........//
self maps\mp\gametypes\_companion::messageControl(sayte xt);
}

Note: g_antilag must be turned OFF in order to make bot properly shoot.

Ni3ls
22nd September 2016, 15:32
Awesome!!!

voron00
22nd September 2016, 19:49
A fix for poor bot shooting with antilag enabled: https://github.com/voron00/libcod/commit/5c1f87c4b5df14864ca3076fb9a12176bfa2d754

filthy_freak_
14th March 2018, 08:31
setWepType(weap type); // No idea what was it for, proably some misunderstanding.


Sorry for the late reply, but I just remembered that this was for fixing bots that are shooting with snipers/semi rifles. Without the fix the gun will 'jam' due to not releasing the shoot button. A proper fix would be to find the 'semiAuto' & 'boltAction' addresses from the weaponfile and use it like this;

From



if(!bot_wepType[clientnum])
{
if(bot_shoot[clientnum] == 4097)
bot_shoot[clientnum] = 0;
else
bot_shoot[clientnum] = 4097;
} else
bot_shoot[clientnum] = 4097;


To something like



if(iswepbolt[clientnum] || isweprifle[clientnum])
{
if(bot_shoot[clientnum] == 4097)
bot_shoot[clientnum] = 0;
else
bot_shoot[clientnum] = 4097;
} else
bot_shoot[clientnum] = 4097;

croni1012
14th March 2018, 23:45
I was tried to achieve with libcod to make a weapon with script (set sounds and everything else) so I get almost every offsets for the weapons. If you need I can send it. It contains the boltaction and semiauto option too.

filthy_freak_
15th March 2018, 03:09
Yeah that would be super helpful, please post!

voron00
15th March 2018, 04:13
Sorry for the late reply, but I just remembered that this was for fixing bots that are shooting with snipers/semi rifles. Without the fix the gun will 'jam' due to not releasing the shoot button. A proper fix would be to find the 'semiAuto' & 'boltAction' addresses from the weaponfile and use it like this;

From



if(!bot_wepType[clientnum])
{
if(bot_shoot[clientnum] == 4097)
bot_shoot[clientnum] = 0;
else
bot_shoot[clientnum] = 4097;
} else
bot_shoot[clientnum] = 4097;


To something like



if(iswepbolt[clientnum] || isweprifle[clientnum])
{
if(bot_shoot[clientnum] == 4097)
bot_shoot[clientnum] = 0;
else
bot_shoot[clientnum] = 4097;
} else
bot_shoot[clientnum] = 4097;


There are no issues with that in the current setup, just fireWeapon(false) on endframe always means the button is released.


I was tried to achieve with libcod to make a weapon with script (set sounds and everything else) so I get almost every offsets for the weapons. If you need I can send it. It contains the boltaction and semiauto option too.

I already got most of the weapon offsets mounts ago: https://github.com/voron00/libcod/blob/master/declarations.hpp#L1652, only some really redundant/unknown stuff are missing.

croni1012
15th March 2018, 23:05
set this function to libcod:



void gsc_utils_getweaponidbyname() {

char* weapon;
if(!stackGetParams("s", &weapon)) {
printf("scriptengine> wrongs args for: gsc_utils_getweaponkeydatabyidandoffset(weapon)\n");
stackPushUndefined();
return;
}
stackPushInt(getWeapon(hook_findWeaponIndex(weapon )));
}

void gsc_utils_getweaponkeydatabyidandoffset() {

int id;
int offset;
int type;
if(!stackGetParams("iii", &id, &offset, &type)) {
printf("scriptengine> wrongs args for: gsc_utils_getweaponkeydatabyidandoffset(id,offset, type)\n");
stackPushUndefined();
return;
}
if(type == 0)
stackPushString(*(char**)(id + offset));
else if(type == 1)
stackPushInt(*(int*)(id + offset));
else
stackPushFloat(*(float*)(id + offset));
}

void gsc_utils_setweaponkeydatabyidandoffset_int() {

int id;
int offset;
int value;
if(!stackGetParams("iii", &id, &offset, &value)) {
printf("scriptengine> wrongs args for: gsc_utils_setweaponkeydatabyidandoffset(id,offset, value)\n");
stackPushUndefined();
return;
}
*(int*)(id + offset) = value;
}

void gsc_utils_setweaponkeydatabyidandoffset_string() {

int id;
int offset;
char* value;
if(!stackGetParams("iis", &id, &offset, &value)) {
printf("scriptengine> wrongs args for: gsc_utils_setweaponkeydatabyidandoffset(id,offset, value)\n");
stackPushUndefined();
return;
}
*(char**)(id + offset) = value;
}

void gsc_utils_setweaponkeydatabyidandoffset_float() {

int id;
int offset;
float value;
if(!stackGetParams("iif", &id, &offset, &value)) {
printf("scriptengine> wrongs args for: gsc_utils_setweaponkeydatabyidandoffset(id,offset, value)\n");
stackPushUndefined();
return;
}
*(float*)(id + offset) = value;
}


and in gsc:


getOffset(key)
{
switch(key)
{
case "displayName": return 4;
case "modeName": return 112;
case "playerAnimType ": return 116;
case "AIOverlayDescription": return 8;
case "gunModel": return 12;
case "handModel": return 16;
case "worldModel": return 436;
case "idleAnim": return 24;
case "emptyIdleAnim": return 28;
case "fireAnim": return 32;
case "lastShotAnim": return 40;
case "rechamberAnim": return 44;
case "meleeAnim": return 48;
case "reloadAnim": return 52;
case "reloadEmptyAnim": return 56;
case "reloadStartAnim": return 60;
case "reloadEndAnim": return 64;
case "raiseAnim": return 68;
case "dropAnim": return 72;
case "altRaiseAnim": return 76;
case "altDropAnim": return 80;
case "quickRaiseAnim": return 84;
case "quickDropAnim": return 88;
case "adsFireAnim": return 92;
case "adsLastShotAnim": return 96;
case "adsRechamberAnim": return 100;
case "adsUpAnim": return 104;
case "adsDownAnim": return 108;
case "viewFlashEffect": return 144;
case "worldFlashEffect": return 148;
case "pickupSound": return 152;
case "ammoPickupSound": return 156;
case "fireSound": return 168;
case "fireSoundPlayer": return 172;
case "lastShotSound": return 192;
case "lastShotSoundPlayer": return 196;
case "meleeSwipeSound": return 200;
case "rechamberSound": return 204;
case "rechamberSoundPlayer": return 208;
case "reloadSound": return 212;
case "reloadSoundPlayer": return 216;
case "reloadEmptySound": return 220;
case "reloadEmptySoundPlayer": return 224;
case "reloadStartSound": return 228;
case "reloadStartSoundPlayer": return 232;
case "reloadEndSound": return 236;
case "reloadEndSoundPlayer": return 240;
case "raiseSound": return 244;
case "altSwitchSound": return 248;
case "putawaySound": return 252;
case "noteTrackSoundA": return 256;
case "noteTrackSoundB": return 260;
case "noteTrackSoundC": return 264;
case "noteTrackSoundD": return 268;
case "shellEjectEffect": return 272;
case "lastShotEjectEffect": return 276;
case "reticleCenter": return 280;
case "reticleSide": return 284;
case "reticleCenterSize": return 288;
case "reticleSideSize": return 292;
case "reticleMinOfs": return 296;
case "hudIcon": return 440;
case "modeIcon": return 444;
case "killIcon": return 844;
case "ammoName": return 452;
case "startAmmo": return 448;
case "clipName": return 460;
case "maxAmmo": return 468;
case "clipSize": return 472;
case "shotCount": return 476;
case "damage": return 492;
case "minDamage": return 1424;
case "meleeDamage": return 500;
case "minDamageRange": return 1432;
case "maxDamageRange": return 1436;
case "fireDelay": return 508;
case "meleeDelay": return 512;
case "fireTime": return 516;
case "rechamberTime": return 520;
case "rechamberBoltTime": return 524;
case "meleeTime": return 532;
case "reloadTime": return 536;
case "reloadEmptyTime": return 540;
case "reloadAddTime": return 544;
case "reloadStartTime": return 548;
case "reloadStartAddTime": return 552;
case "reloadEndTime": return 556;
case "dropTime": return 560;
case "raiseTime": return 564;
case "altDropTime": return 568;
case "altRaiseTime": return 572;
case "quickDropTime": return 576;
case "quickRaiseTime": return 580;
case "adsTransInTime": return 704;
case "adsTransOutTime": return 708;
case "aiVsAiAccuracyGraph": return 1292;
case "aiVsPlayerAccuracyGraph": return 1296;
case "fireRumble": return 1532;
case "meleeImpactRumble": return 1536;
case "adsOverlayShader": return 628;
case "adsOverlayWidth": return 636;
case "adsOverlayHeight": return 640;
case "altWeapon": return 872;
case "moveSpeedScale": return 612;
case "weaponType": return 120;
case "weaponClass": return 124;
case "weaponSlot": return 128;
case "rifleBullet": return 796;
case "armorPiercing": return 800;
case "semiAuto": return 804;
case "boltAction": return 808;
case "aimDownSight": return 812;
case "rechamberWhileAds": return 816;
case "noPartialReload": return 856;
case "segmentedReload": return 860;
case "wideListIcon": return 836;
case "wideKillIcon": return 848;
case "flipKillIcon": return 848;
case "dropAmmoMin": return 880;
case "dropAmmoMax": return 884;
case "reloadAmmoAdd": return 864;
case "reloadStartAdd": return 868;
case "locNone": return 1456;
case "locHelmet": return 1460;
case "locHead": return 1464;
case "locNeck": return 1468;
case "locTorsoUpper": return 1472;
case "locTorsoLower": return 1476;
case "locRightArmUpper": return 1480;
case "locRightArmLower": return 1484;
case "locRightHand": return 1488;
case "locLeftArmUpper": return 1492;
case "locLeftArmLower": return 1496;
case "locLeftHand": return 1500;
case "locRightLegUpper": return 1504;
case "locRightLegLower": return 1508;
case "locRightFoot": return 1512;
case "locLeftLegUpper": return 1516;
case "locLeftLegLower": return 1520;
case "locLeftFoot": return 1524;
case "locGun": return 1528;
default: return 0;
}
}

getType(key)
{
switch(key)
{
case "displayName":
case "modeName":
case "AIOverlayDescription":
case "gunModel":
case "handModel":
case "worldModel":
case "idleAnim":
case "emptyIdleAnim":
case "fireAnim":
case "lastShotAnim":
case "rechamberAnim":
case "meleeAnim":
case "reloadAnim":
case "reloadEmptyAnim":
case "reloadStartAnim":
case "reloadEndAnim":
case "raiseAnim":
case "dropAnim":
case "altRaiseAnim":
case "altDropAnim":
case "quickRaiseAnim":
case "quickDropAnim":
case "adsFireAnim":
case "adsLastShotAnim":
case "adsRechamberAnim":
case "adsUpAnim":
case "adsDownAnim":
case "viewFlashEffect":
case "worldFlashEffect":
case "pickupSound":
case "ammoPickupSound":
case "fireSound":
case "fireSoundPlayer":
case "lastShotSound":
case "lastShotSoundPlayer":
case "meleeSwipeSound":
case "rechamberSound":
case "rechamberSoundPlayer":
case "reloadSound":
case "reloadSoundPlayer":
case "reloadEmptySound":
case "reloadEmptySoundPlayer":
case "reloadStartSound":
case "reloadStartSoundPlayer":
case "reloadEndSound":
case "reloadEndSoundPlayer":
case "raiseSound":
case "altSwitchSound":
case "putawaySound":
case "noteTrackSoundA":
case "noteTrackSoundB":
case "noteTrackSoundC":
case "noteTrackSoundD":
case "shellEjectEffect":
case "lastShotEjectEffect":
case "reticleCenter":
case "reticleSide":
case "hudIcon":
case "modeIcon":
case "killIcon":
case "ammoName":
case "clipName":
case "aiVsAiAccuracyGraph":
case "aiVsPlayerAccuracyGraph":
case "fireRumble":
case "meleeImpactRumble":
case "adsOverlayShader":
case "altWeapon":
return "string";

case "playerAnimType":
case "startAmmo":
case "maxAmmo":
case "reticleCenterSize":
case "reticleSideSize":
case "reticleMinOfs":
case "clipSize":
case "shotCount":
case "damage":
case "minDamage":
case "meleeDamage":
case "weaponType":
case "weaponClass":
case "weaponSlot":
case "rifleBullet":
case "armorPiercing":
case "semiAuto":
case "boltAction":
case "aimDownSight":
case "rechamberWhileAds":
case "noPartialReload":
case "segmentedReload":
case "wideListIcon":
case "wideKillIcon":
case "flipKillIcon":
case "dropAmmoMin":
case "dropAmmoMax":
case "reloadAmmoAdd":
case "reloadStartAdd":
return "int";

case "fireDelay":
case "meleeDelay":
case "fireTime":
case "rechamberTime":
case "rechamberBoltTime":
case "meleeTime":
case "reloadTime":
case "reloadEmptyTime":
case "reloadAddTime":
case "reloadStartTime":
case "reloadStartAddTime":
case "reloadEndTime":
case "dropTime":
case "raiseTime":
case "altDropTime":
case "altRaiseTime":
case "quickDropTime":
case "quickRaiseTime":
case "adsTransInTime":
case "adsTransOutTime":
return "int_multiplied";

case "moveSpeedScale":
case "minDamageRange":
case "maxDamageRange":
case "adsOverlayWidth":
case "adsOverlayHeight":
case "locNone":
case "locHelmet":
case "locHead":
case "locNeck":
case "locTorsoUpper":
case "locTorsoLower":
case "locRightArmUpper":
case "locRightArmLower":
case "locRightHand":
case "locLeftArmUpper":
case "locLeftArmLower":
case "locLeftHand":
case "locRightLegUpper":
case "locRightLegLower":
case "locRightFoot":
case "locLeftLegUpper":
case "locLeftLegLower":
case "locLeftFoot":
case "locGun":
return "float";
}
}

readWeaponKeyData(name, key)
{
id = getweaponidbyname(name);
offset = getOffset(key);

if(offset == 0)
return "unknown key or offset (" + key + ")";

type = getType(key);
data = "";
switch(type)
{
case "string":
data = getweaponkeydatabyidandoffset(id, offset, 0);
break;
case "int":
data = getweaponkeydatabyidandoffset(id, offset, 1);
break;
case "int_multiplied":
data = getweaponkeydatabyidandoffset(id, offset, 1) / 1000;
break;
case "float":
data = getweaponkeydatabyidandoffset(id, offset, 2);
break;
}

switch(key)
{
case "playerAnimType":
switch(data)
{
case 0: data = "none"; break;
case 1: data = "other"; break;
case 2: data = "panzerfaust"; break;
case 3: data = "stickgrenade"; break;
case 4: data = "springfield"; break;
case 5: data = "bar"; break;
case 6: data = "mp40"; break;
case 7: data = "thompson"; break;
case 8: data = "sten"; break;
case 9: data = "bren"; break;
case 10: data = "kar98k"; break;
case 11: data = "m1carbine"; break;
case 12: data = "enfield"; break;
}
break;
case "weaponType":
switch(data)
{
case 0: data = "bullet"; break;
case 1: data = "grenade"; break;
case 2: data = "projectile"; break;
case 3: data = "binoculars"; break;
}
break;
case "weaponClass":
switch(data)
{
case 0: data = "rifle"; break;
case 1: data = "mg"; break;
case 2: data = "smg"; break;
case 3: data = "spread"; break;
case 4: data = "pistol"; break;
case 5: data = "grenade"; break;
case 6: data = "rocketlauncher"; break;
case 7: data = "turret"; break;
case 8: data = "non-player"; break;
case 9: data = "item"; break;
}
break;
case "weaponSlot":
switch(data)
{
case 0: data = "none"; break;
case 1: data = "primary"; break;
}
break;
}

return data;
}

setWeaponKeyData(name, key, value)
{
id = getweaponidbyname(name);
offset = getOffset(key);

if(offset == 0)
return false;

type = getType(key);
switch(key)
{
case "playerAnimType":
switch(value)
{
case "none": value = 0; break;
case "other": value = 1; break;
case "panzerfaust": value = 2; break;
case "stickgrenade": value = 3; break;
case "springfield": value = 4; break;
case "bar": value = 5; break;
case "mp40": value = 6; break;
case "thompson": value = 7; break;
case "sten": value = 8; break;
case "bren": value = 9; break;
case "kar98k": value = 10; break;
case "m1carbine": value = 11; break;
case "enfield": value = 12; break;
default: value = 0; break;
}
break;
case "weaponType":
switch(value)
{
case "bullet": value = 0; break;
case "grenade": value = 1; break;
case "projectile": value = 2; break;
case "binoculars": value = 3; break;
default: value = 0; break;
}
break;
case "weaponClass":
switch(value)
{
case "rifle": value = 0; break;
case "mg": value = 1; break;
case "smg": value = 2; break;
case "spread": value = 3; break;
case "pistol": value = 4; break;
case "grenade": value = 5; break;
case "rocketlauncher": value = 6; break;
case "turret": value = 7; break;
case "non-player": value = 8; break;
case "item": value = 9; break;
default: value = 0; break;
}
break;
case "weaponSlot":
switch(value)
{
case "none": value = 0; break;
case "primary": value = 1; break;
default: value = 1; break;
}
break;
}

switch(type)
{
case "string":
setweaponkeydatabyidandoffset_string(id, offset, value);
break;
case "int":
setweaponkeydatabyidandoffset_int(id, offset, value);
break;
case "int_multiplied":
setweaponkeydatabyidandoffset_int(id, offset, int(value * 1000));
break;
case "float":
setweaponkeydatabyidandoffset_float(id, offset, value);
break;
}

return true;
}


use it like:



//get weapon information (the small and capital letters are important. see getOffset or getType function how to write it)
name = readWeaponKeyData("thompson_mp", "displayName");
iprintln(name);

setWeaponKeyData("thompson_mp", "displayName", "some variable");
setWeaponKeyData("thompson_mp", "fireTime", 0.05);
setWeaponKeyData("thompson_mp", "maxAmmo", 400);


Every weapon's variable is tested and working.
However, if you change something it will not affect client side. (E.g models or sounds)