TheOysterHippopotami said:The vast, vast majority of bows in all level tiers should use arrows. That is, if we want archery to be interesting at all.
New arrows would also be awesome to have.
.float hit_z;
void() spike_touch =
{
local float rand;
if (other == self.owner)
return;
if (other.solid == SOLID_TRIGGER)
return; // trigger field, do nothing
if (pointcontents(self.origin) == CONTENT_SKY)
{
remove(self);
return;
}
// hit something that bleeds
if (other.takedamage)
{
spawn_touchblood (9);
T_Damage (other, self, self.owner, 9);
}
else
{
WriteByte (MSG_BROADCAST, SVC_TEMPENTITY);
if (self.classname == "wizspike")
WriteByte (MSG_BROADCAST, TE_WIZSPIKE);
else if (self.classname == "knightspike")
WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE);
else
WriteByte (MSG_BROADCAST, TE_SPIKE);
WriteCoord (MSG_BROADCAST, self.origin_x);
WriteCoord (MSG_BROADCAST, self.origin_y);
WriteCoord (MSG_BROADCAST, self.origin_z);
}
remove(self);
};
/*
============
T_Damage
The damage is coming from inflictor, but get mad at attacker
This should be the only function that ever reduces health.
============
*/
void(entity targ, entity inflictor, entity attacker, float damage) T_Damage=
{
local vector dir;
local entity oldself;
local float save;
local float take;
if (!targ.takedamage)
return;
// used by buttons and triggers to set activator for target firing
damage_attacker = attacker;
// check for quad damage powerup on the attacker
if (attacker.super_damage_finished > time)
damage = damage * 4;
// save damage based on the target's armor level
save = ceil(targ.armortype*damage);
if (save >= targ.armorvalue)
{
save = targ.armorvalue;
targ.armortype = 0; // lost all armor
targ.items = targ.items - (targ.items & (IT_ARMOR1 | IT_ARMOR2 | IT_ARMOR3));
}
targ.armorvalue = targ.armorvalue - save;
take = ceil(damage-save);
// add to the damage total for clients, which will be sent as a single
// message at the end of the frame
// FIXME: remove after combining shotgun blasts?
if (targ.flags & FL_CLIENT)
{
targ.dmg_take = targ.dmg_take + take;
targ.dmg_save = targ.dmg_save + save;
targ.dmg_inflictor = inflictor;
}
// figure momentum add
if ( (inflictor != world) && (targ.movetype == MOVETYPE_WALK) )
{
dir = targ.origin - (inflictor.absmin + inflictor.absmax) * 0.5;
dir = normalize(dir);
targ.velocity = targ.velocity + dir*damage*8;
}
// check for godmode or invincibility
if (targ.flags & FL_GODMODE)
return;
if (targ.invincible_finished >= time)
{
if (self.invincible_sound < time)
{
sound (targ, CHAN_ITEM, "items/protect3.wav", 1, ATTN_NORM);
self.invincible_sound = time + 2;
}
return;
}
// team play damage avoidance
if ( (teamplay == 1) && (targ.team > 0)&&(targ.team == attacker.team) )
return;
// do the damage
targ.health = targ.health - take;
if (targ.health <= 0)
{
Killed (targ, attacker);
return;
}
// react to the damage
oldself = self;
self = targ;
if ( (self.flags & FL_MONSTER) && attacker != world)
{
// get mad unless of the same class (except for soldiers)
if (self != attacker && attacker != self.enemy)
{
if ( (self.classname != attacker.classname)
|| (self.classname == "monster_army" ) )
{
if (self.enemy.classname == "player")
self.oldenemy = self.enemy;
self.enemy = attacker;
FoundTarget ();
}
}
}
if (self.th_pain)
{
self.th_pain (attacker, take);
// nightmare mode monsters don't go into pain frames often
if (skill == 3)
self.pain_finished = time + 5;
}
self = oldself;
};
ceriux said:i cant honestly say how the detection works engine side esp. since quake models only have one individual hitbox, but this is a projectile touch snippit :
Code:.float hit_z; void() spike_touch = { local float rand; if (other == self.owner) return; if (other.solid == SOLID_TRIGGER) return; // trigger field, do nothing if (pointcontents(self.origin) == CONTENT_SKY) { remove(self); return; } // hit something that bleeds if (other.takedamage) { spawn_touchblood (9); T_Damage (other, self, self.owner, 9); } else { WriteByte (MSG_BROADCAST, SVC_TEMPENTITY); if (self.classname == "wizspike") WriteByte (MSG_BROADCAST, TE_WIZSPIKE); else if (self.classname == "knightspike") WriteByte (MSG_BROADCAST, TE_KNIGHTSPIKE); else WriteByte (MSG_BROADCAST, TE_SPIKE); WriteCoord (MSG_BROADCAST, self.origin_x); WriteCoord (MSG_BROADCAST, self.origin_y); WriteCoord (MSG_BROADCAST, self.origin_z); } remove(self); };
void CGenericItem::Projectile_CheckHit( void )
{
if ( ProjectileData->IgnoreNPC ) return;
TraceResult tr;
Vector vMoveDir = pev->angles;
vMoveDir.x = -vMoveDir.x;
UTIL_MakeVectors( vMoveDir );
Vector vecEnd = pev->origin + pev->velocity.Normalize() * 36;
int trflags = MSTRACE_SOLIDSHIELDS|MSTRACE_LARGEHITBOXES;
MSTraceLine( pev->origin, vecEnd, dont_ignore_monsters, edict(), tr, trflags ); if ( tr.flFraction < 1.0 )
{
CBaseEntity *pEntity = MSInstance(tr.pHit);
if( pEntity )
{
ProjectileTouch( pEntity );
}
}
}
void CGenericItem::ProjectileTouch( CBaseEntity *pOther )
{
//if ( ProjectileData->IgnoreNPC ) return;
startdbg;
TypeCheck;
if( pev->owner == pOther->edict()
|| pOther->MSMoveType == MOVETYPE_ARROW
|| !FBitSet( MSProperties(), ITEM_PROJECTILE ) )
return;
float dmgMultiplier = 1.0f;
//Thothie - trying to fix sounds of arrows always coming from 0x0x0
Vector old_location;
old_location = pev->origin;
Vector vForward;
if( pev->velocity.Length() ) vForward = pev->velocity;
else
{
UTIL_MakeVectorsPrivate( Vector(-pev->angles.x,pev->angles.y,pev->angles.z), pev->velocity, NULL, NULL );
pev->velocity *= ProjectileData->Speed;
}
if( (pOther->MyMonsterPointer() && !pOther->IsAlive()) )
return; //Hit a dead monster, keep going
damage_t Damage;
CBaseEntity *pDamageEnt = NULL;
CBaseEntity *pOwner = RetrieveEntity( ENT_EXPOWNER );
if( pOwner && !ProjectileData->IgnoreNPC )
{
if( pOwner->IsPlayer() )
{
CMSMonster *pMonsterOwner = (CMSMonster *)pOwner;
dmgMultiplier = pMonsterOwner->GetSkillStat( ProjectileData->StatPower, ProjectileData->PropPower ) / STATPROP_MAX_VALUE;
dmgMultiplier = max( dmgMultiplier, 0.001f );
}
clrmem( Damage );
Damage.pInflictor = this;
Damage.pAttacker = pOwner;
Damage.vecSrc = pev->origin;
Damage.vecEnd = pev->origin + vForward;
Damage.flRange = ProjectileData->flDamageAOERange;
Damage.flDamage = ProjectileData->Damage * dmgMultiplier;
Damage.iDamageType = DMG_NEVERGIB|DMG_NOSKIN;
Damage.flHitPercentage = 100.0f;
Damage.sDamageType = ProjectileData->sDamageType;
Damage.flAOERange = ProjectileData->flDamageAOERange;
Damage.flAOEAttn = ProjectileData->flDamageAOEAttn;
Damage.ExpUseProps = true;
Damage.ExpStat = ProjectileData->StatExp;
Damage.ExpProp = ProjectileData->PropExp;
hitent_list Hits;
DoDamage( Damage, Hits );
pDamageEnt = Hits.ClosestHit( );
}
if( pOther->IsMSMonster( ) && ProjectileData->CollideHitBox && !pDamageEnt )
{
//Just keep going if I hit a npc bounding box but not an actual hitbox
return;
}
pev->origin = old_location; //Thothie AUG2011_15 - move back to location so sound plays from right spot
CallScriptEvent( "game_projectile_landed" );
//if( pDamageEnt )
if ( !ProjectileData->IgnoreNPC ) pev->origin = Damage.outTraceResult.vecEndPos;
if( pDamageEnt &&
pDamageEnt->pev->takedamage && !ProjectileData->IgnoreWorld )
{
if( FBitSet( pDamageEnt->pev->flags, FL_GODMODE ) && !ProjectileData->IgnoreNPC ) //Monster has godmode
{
//Delay removal, so further arrow code doesn't crash
DelayedRemove( );
return;
}
dbg ("Params List");
static msstringlist Params;
dbg ("Clear List");
Params.clearitems();
dbg ("PDamageEnt");
Params.add( EntToString(pDamageEnt) );
dbg ("SendEvent");
pev->origin = old_location; //Thothie AUG2011_15 - move back to location so sound plays from right spot
CallScriptEvent( "game_projectile_hitnpc", &Params );
dbg ("IgnoreNPC");
if ( ProjectileData->IgnoreNPC ) return;
if ( ProjectileData->IgnoreNPC )
{
pev->owner = NULL;
}
else
{
pev->solid = SOLID_NOT;
//ExpireTime = ProjectileData->TimeStickTime;
MSMoveType = MOVETYPE_STUCKARROW;
}
}
else {
//No monster or monster I hit is dead or doesn't take damage
pev->owner = NULL;
pev->origin = old_location; //Thothie AUG2010_26 - move back to location so sound plays from right spot
CallScriptEvent( "game_projectile_hitwall" );
}
m_TimeExpire = gpGlobals->time + ExpireTime;
ClearBits( Properties, ITEM_PROJECTILE );
pev->movetype = MOVETYPE_NONE;
SetTouch( NULL );
enddbg;
}
Yeah, I has not only the Quake SDK code, but the engine code as well... And have indeed been using to Quake 1 code to track down what Half-Life1 is doing, in places we can't normally look... Granted, this doesn't apply to all the new crap they added.cerix said:also heres the entire quake source code (not the engine side code, just the ss game logic) hosted on the web, incase you wanted to look through the tutorial step by step to see whats done when making an ss entity communicate with a cs one.
This hit detection, in this code, is server side. The client has its own collision detection for tempents.ceriux said:so it's not possible to keep hit detection over on server side code on half-life?
Not sure if yer talking about the model indexes or the hit box indexes... Or how putting either into a flag would help... For the model indexes, the problem is I've no way to turn a client side model index into a server side ID. The client can determine whether he hit or not, but eventually, something's gotta happen server side, and the server needs to know who got hit. ...and for the hitboxes... The function seems to work fine, it's just these projectile trace lines aren't doing what they should be.ceriux said:also it's not possible use the index you get back as a flag?
You always do projectiles on the server. You can make them invisible so they're not transferred over the network.
<Sniper> On the client, you shoot from the same position.
<Sniper> The client will see the arrow fly and hit something
<Sniper> If the client and server connection isn't 100% in sync, it won't really matter
<ceriux> mm well they've been having problems with lagging arrows and what not. drawing them over the client would have reduced how laggy they seemed. so i should let him know its not possible?
<Sniper> that's how it'd be done in a commercial game
<Sniper> client predicts where the arrow lands
<Sniper> server doesn't tell the client about it, does the actual arrow physics.
<Sniper> Most of the time it
<Sniper> should be accurate..
<Sniper> When you encounter heavy lag, it'll obviously not match the server. But they're arrows, they fly fast enough that no one will care.
<Sniper> That's basically how bullet tracers in counter-strike work.
Thothie said:If our arrows fired in quick straight lines, it'd be alright