by ratbert » Thu Oct 16, 2014 7:28 pm
You maybe want to play with something new on grenade related things. Code is based off original ogre grenade throwing code with some Patrick Martin aiming code thrown in and some ideas I added in to it make it more interesting. You see references in the function names starting with "potty" which is for a porta potty monster. I think the mod was called "Burnman" quake mod (close to that name) that had a bunch of wacky monster replacements for original quake monsters. There a was a porta-potty monster that was direct replacement for the quake ogre.
I added an some code so when the porta-potty monster door opens it throws out crap at you (toilet seat, play head or gibs) using modified ogre grenade throwing function with the added Patrick Martin aiming code for better aim. So it does work pretty well for what it is worth and does give the monster better aim. Now thing is the grenade has two possible ways of working either lobbed at you directly or has a semi bouncing/homing effect that tries to follow you around to get you for a short period before explodes. Semi "bouncing/homing" effect I took from some rocket homing code functions and adapted so it was not so precise but it does the job anyhow. It would not be that hard to adapt for the quake ogre to use if anyone is interested in it. Controlling number of bounces/homing counter is in function PottyBounceGrenadeTouch using variable self.count.
I do same Semi "bouncing/homing" effect code adapted for Ogre when they throw Nuke Grenade (aka big nuke bomb) at you. It so fun trying to out run or dodge one them dang things.
Code Part
----------------------------------------------
//--------------------------------------------------------------------------
// This returns the z-velocity added to a monster's grenade based on
// the distance between attacker and target and on gravity.
//--------------------------------------------------------------------------
float(float dist) Monster_GrenadeFly =
{
local float g; // Gravity -- g = 1 is Earth gravity.
local float base; // This dictates how fast the projectile
// will fly up when it is launched.
//------------------------------------------------------//
// 800 is normal (Earth) gravity. 800 * 0.00125 = 1. //
//------------------------------------------------------//
g = (cvar("sv_gravity")) * 0.00125; // Find gravity in terms of g.
if (dist > 900) base = 200+((dist - (200 - (dist * 0.2)))*0.5);
else if (dist > 700) base = 200+((dist - (200 - (dist * 0.15)))*0.5);
else if (dist > 500) base = 200+((dist - (200 - (dist * 0.1)))*0.5);
else if (dist > 300) base = 200+((dist - 200)*0.5);
else if (dist > 200) base = 200;
else if (dist > 100) base = dist;
else base = 100;
return (base * g);
};
void() PottyGrenadeExplode2 =
{
T_RadiusDamage (self, self.owner, 160 , world);
WriteByte (#MSG_MULTICAST, #SVC_TEMPENTITY);
WriteByte (#MSG_MULTICAST, #TE_EXPLOSION);
WriteCoord (#MSG_MULTICAST, self.origin_x);
WriteCoord (#MSG_MULTICAST, self.origin_y);
WriteCoord (#MSG_MULTICAST, self.origin_z);
multicast (self.origin, #MULTICAST_PHS);
remove (self);
};
void() PottyGrenadeTouch2 =
{
if (other == self.owner)
return; // don't explode on owner
if (other.takedamage == #DAMAGE_AIM)
{
PottyGrenadeExplode2();
return;
}
sound (self, #CHAN_VOICE, "potty/potbounce.wav", 1, #ATTN_NORM); // bounce sound
if (self.velocity == '0 0 0')
self.avelocity = '0 0 0';
};
void() PottyBounceGrenadeThink =
{
self.angles = vectoangles(self.velocity);
self.nextthink = time + 0.1;
};
void() PottyBounceGrenadeSeek =
{
self.flags = self.flags - (self.flags & #FL_ONGROUND);
setorigin(self, (self.origin + '0 0 2'));
self.velocity = normalize((self.enemy.origin + self.enemy.view_ofs) - self.origin);
self.velocity = self.velocity * 600;
self.velocity_z = self.velocity_z + vlen(self.enemy.origin - self.origin);
self.angles = vectoangles(self.velocity);
self.nextthink = time + 0.01;
self.think = PottyBounceGrenadeThink;
};
void() PottyBounceGrenadeTouch =
{
if (other.health)
{
PottyGrenadeExplode2();
return;
}
if (self.count >= 11)
{
PottyGrenadeExplode2();
return;
}
sound (self, #CHAN_VOICE, "potty/potbounce.wav", 1, #ATTN_NORM); // bounce sound
self.count = self.count + 1;
self.think = PottyBounceGrenadeSeek;
self.nextthink = time + 0.01;
};
void() PottyFireGrenade =
{
local entity missile;
local float whichpart;
local float rnumwhich;
//-------------------------------------------------------- New Code --------
local float dist; // Distance between attacker and target.
local float fly; // This dictates how fast the projectile
// will fly up when it is launched.
local float airtime; // Approximate time for grenade to
// reach target.
local vector move; // xy-velocity of target.
local vector spot; // Spot where grenade will land with leading.
local vector org; // Location where grenade is spawned.
local float missilespeed;
//--------------------------------------------------------------------------
muzzleflash ();
SuperDamageSound();
sound (self, #CHAN_WEAPON, "weapons/grenade.wav", 1, #ATTN_NORM);
rnumwhich = random();
if (rnumwhich > 0.6)
monster_deathattack_messagev2(" got flushed by a", self.netname, "");
else if (rnumwhich > 0.3)
monster_deathattack_messagev2(" got the crap kicked out of them by a ", self.netname, "");
else
monster_deathattack_messagev2(" pissed off the wrong", self.netname, "");
missilespeed = 600;
missile = spawn ();
missile.owner = self;
missile.movetype = #MOVETYPE_BOUNCE;
missile.solid = #SOLID_BBOX;
// set missile speed
makevectors (self.angles);
//-------------------------------------------------------- New Code --------
org = self.origin + v_forward * 32 + v_right * -6 + '0 0 16';
dist = vlen(self.enemy.origin - org);
airtime = dist / missilespeed;
move = self.enemy.velocity;
move_z = 0;
spot = self.enemy.origin + airtime * move;
//-----------------------------------------------------------//
// Since grenades are affected by gravity, make adjustments //
// based on the anticipated location of attacker's target. //
//-----------------------------------------------------------//
if (vlen(spot - org) < dist)
spot = self.enemy.origin + airtime * move * 0.7;
else if (vlen(spot - org) > dist)
spot = self.enemy.origin + airtime * move * 1.2;
if (skill > 1)
// Use this for complete tracking.
missile.velocity = normalize (spot - org);
else
// Use this for distance tracking only.
missile.velocity = normalize (self.enemy.origin - org);
//--------------------------------------------------------------------------
missile.velocity = missile.velocity * missilespeed;
//-------------------------------------------------------- New Code --------
dist = vlen(spot - org);
//--------------------------------------------------------------//
// The monster will lob a projectile that is guaranteed to hit //
// a stationary target within a radius of 1000. //
//--------------------------------------------------------------//
fly = Monster_GrenadeFly(dist);
missile.velocity_z = (missile.velocity_z + fly);
//---------------------------------------------------------------- END -----
missile.avelocity = '300 300 300';
missile.angles = vectoangles(missile.velocity);
if (random() > 0.50)
{
missile.touch = PottyBounceGrenadeTouch;
missile.nextthink = time + 0.1;
missile.think = PottyBounceGrenadeThink;
missile.count = 0;
}
else
{
missile.nextthink = time + 2.5;
missile.think = PottyGrenadeExplode2;
missile.touch = PottyGrenadeTouch2;
}
whichpart = random();
if (whichpart > 0.66)
setmodel (missile, "progs/h_ppotty.mdl");
else if (whichpart > 0.33)
setmodel (missile, "progs/h_player.mdl");
else
setmodel (missile, "progs/gib3.mdl");
setsize (missile, '0 0 0', '0 0 0');
setorigin (missile, org);
};