Convert the new added files from CRLF into LF and add modified source code in game directory (final part)

This commit is contained in:
LegendGuard 2023-07-26 18:37:21 +02:00 committed by GitHub
parent 0e0bdc0ac8
commit b1176b99fb
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
38 changed files with 3680 additions and 1966 deletions

File diff suppressed because it is too large Load diff

View file

@ -1,156 +1,156 @@
// HEXEN : Zeroth
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "Game_local.h"
void idPlayer::Event_SetViewAngles( idVec3 &vec ) {
viewAngles[0] = vec.x;
viewAngles[1] = vec.y;
viewAngles[2] = vec.z;
}
void idPlayer::Event_GetEyePos( void ) {
idThread::ReturnVector( GetEyePosition() );
}
void idPlayer::Event_SetFreeMove( const float yesorno ) {
//spawnArgs.SetInt("freemovement", yesorno);
if (yesorno) {
FreeMove=true;
}else{
FreeMove=false;
}
}
void idPlayer::Event_ChaosDevice( void ) {
SetOrigin(SpawnPos);
SetViewAngles(SpawnViewAngles);
}
void idPlayer::Event_GiveHealth( const float amount ) {
health+=amount;
}
void idPlayer::Event_GiveSpeed( const float amount ) {
speedMod+=amount;
}
void idPlayer::Event_GiveArmor( const float amount ) {
inventory.armor+=amount;
}
void idPlayer::Event_SetHealth( const float amount ) {
health=amount;
}
void idPlayer::Event_SetArmor( const float amount ) {
inventory.armor=amount;
}
void idPlayer::Event_SetInvincible( const float number ) {
if (number != 0) {
invincible = true;
}else{
invincible = false;
}
}
void idPlayer::Event_GetInvincible( void ) {
if (godmode || invincible) {
idThread::ReturnFloat(1);
}else{
idThread::ReturnFloat(0);
}
}
void idPlayer::Event_GetClass( void ) {
idThread::ReturnFloat( inventory.Class );
}
void idPlayer::Event_GetHealth( void ) {
idThread::ReturnFloat( health );
}
void idPlayer::Event_GetFullHealth( void ) {
idThread::ReturnFloat( inventory.maxHealth );
}
void idPlayer::Event_GetFullArmor( void ) {
idThread::ReturnFloat( inventory.maxarmor );
}
void idPlayer::Event_GetFullAmmo( const char* ammo_classname ) {
idThread::ReturnFloat( spawnArgs.GetInt( va( "max_%s", ammo_classname ), "0" ) );
}
void idPlayer::Event_GetAmmo( const char* ammo_classname ) {
idThread::ReturnFloat( inventory.ammo[ idWeapon::GetAmmoNumForName( ammo_classname ) ] );
}
void idPlayer::Event_SetAmmo( const char* ammo_classname, float amount ) {
if ( ammo_classname ) {
inventory.ammo[ idWeapon::GetAmmoNumForName( ammo_classname ) ] = amount;
}
}
void idPlayer::Event_GetArmor( void ) {
idThread::ReturnFloat( inventory.armor );
}
void idPlayer::Event_StickToSurface( const idVec3 &surfaceNormal ) {
//idPhysics_Actor *x=GetPhysics();
physicsObj.SetSurfaceNormal(surfaceNormal);
physicsObj.SetStuckToSurface(true);
}
void idPlayer::Event_UnstickToSurface( void ) {
physicsObj.SetStuckToSurface(false);
}
bool idPlayer::StuckToSurface( void ) {
return physicsObj.StuckToSurface();
}
void idPlayer::Event_StuckToSurface( void ) {
idThread::ReturnFloat((float)StuckToSurface());
}
void idPlayer::Event_SetPowerTome( float val ) {
PowerTome = !(!val);
}
void idPlayer::Event_GetPowerTome( void ) {
idThread::ReturnFloat((float)PowerTome);
}
void idPlayer::Event_VecFacingP( void ) {
// return proper facing direction (yaw only)
idVec3 dir=viewAxis[ 0 ] * physicsObj.GetGravityAxis();
dir.Normalize();
idThread::ReturnVector(dir);
}
void idPlayer::Event_HudMessage( const char *message ) {
ShowHudMessage( message );
}
void idPlayer::Event_VecForwardP( void ) {
idThread::ReturnVector(VecForwardP());
}
idVec3 idPlayer::VecForwardP( void ) const {
// return proper forward vector for whatever way the player is looking
idVec3 dir=viewAngles.ToForward() * physicsObj.GetGravityAxis();
dir.Normalize();
return dir;
}
// HEXEN : Zeroth
void idPlayer::Event_ArtifactUseFlash( void ) {
if ( hud ) {
hud->HandleNamedEvent( "eoc_artifactUse" );
}
}
// HEXEN : Zeroth
#include "../idlib/precompiled.h"
#pragma hdrstop
#include "Game_local.h"
void idPlayer::Event_SetViewAngles( idVec3 &vec ) {
viewAngles[0] = vec.x;
viewAngles[1] = vec.y;
viewAngles[2] = vec.z;
}
void idPlayer::Event_GetEyePos( void ) {
idThread::ReturnVector( GetEyePosition() );
}
void idPlayer::Event_SetFreeMove( const float yesorno ) {
//spawnArgs.SetInt("freemovement", yesorno);
if (yesorno) {
FreeMove=true;
}else{
FreeMove=false;
}
}
void idPlayer::Event_ChaosDevice( void ) {
SetOrigin(SpawnPos);
SetViewAngles(SpawnViewAngles);
}
void idPlayer::Event_GiveHealth( const float amount ) {
health+=amount;
}
void idPlayer::Event_GiveSpeed( const float amount ) {
speedMod+=amount;
}
void idPlayer::Event_GiveArmor( const float amount ) {
inventory.armor+=amount;
}
void idPlayer::Event_SetHealth( const float amount ) {
health=amount;
}
void idPlayer::Event_SetArmor( const float amount ) {
inventory.armor=amount;
}
void idPlayer::Event_SetInvincible( const float number ) {
if (number != 0) {
invincible = true;
}else{
invincible = false;
}
}
void idPlayer::Event_GetInvincible( void ) {
if (godmode || invincible) {
idThread::ReturnFloat(1);
}else{
idThread::ReturnFloat(0);
}
}
void idPlayer::Event_GetClass( void ) {
idThread::ReturnFloat( inventory.Class );
}
void idPlayer::Event_GetHealth( void ) {
idThread::ReturnFloat( health );
}
void idPlayer::Event_GetFullHealth( void ) {
idThread::ReturnFloat( inventory.maxHealth );
}
void idPlayer::Event_GetFullArmor( void ) {
idThread::ReturnFloat( inventory.maxarmor );
}
void idPlayer::Event_GetFullAmmo( const char* ammo_classname ) {
idThread::ReturnFloat( spawnArgs.GetInt( va( "max_%s", ammo_classname ), "0" ) );
}
void idPlayer::Event_GetAmmo( const char* ammo_classname ) {
idThread::ReturnFloat( inventory.ammo[ idWeapon::GetAmmoNumForName( ammo_classname ) ] );
}
void idPlayer::Event_SetAmmo( const char* ammo_classname, float amount ) {
if ( ammo_classname ) {
inventory.ammo[ idWeapon::GetAmmoNumForName( ammo_classname ) ] = amount;
}
}
void idPlayer::Event_GetArmor( void ) {
idThread::ReturnFloat( inventory.armor );
}
void idPlayer::Event_StickToSurface( const idVec3 &surfaceNormal ) {
//idPhysics_Actor *x=GetPhysics();
physicsObj.SetSurfaceNormal(surfaceNormal);
physicsObj.SetStuckToSurface(true);
}
void idPlayer::Event_UnstickToSurface( void ) {
physicsObj.SetStuckToSurface(false);
}
bool idPlayer::StuckToSurface( void ) {
return physicsObj.StuckToSurface();
}
void idPlayer::Event_StuckToSurface( void ) {
idThread::ReturnFloat((float)StuckToSurface());
}
void idPlayer::Event_SetPowerTome( float val ) {
PowerTome = !(!val);
}
void idPlayer::Event_GetPowerTome( void ) {
idThread::ReturnFloat((float)PowerTome);
}
void idPlayer::Event_VecFacingP( void ) {
// return proper facing direction (yaw only)
idVec3 dir=viewAxis[ 0 ] * physicsObj.GetGravityAxis();
dir.Normalize();
idThread::ReturnVector(dir);
}
void idPlayer::Event_HudMessage( const char *message ) {
ShowHudMessage( message );
}
void idPlayer::Event_VecForwardP( void ) {
idThread::ReturnVector(VecForwardP());
}
idVec3 idPlayer::VecForwardP( void ) const {
// return proper forward vector for whatever way the player is looking
idVec3 dir=viewAngles.ToForward() * physicsObj.GetGravityAxis();
dir.Normalize();
return dir;
}
// HEXEN : Zeroth
void idPlayer::Event_ArtifactUseFlash( void ) {
if ( hud ) {
hud->HandleNamedEvent( "eoc_artifactUse" );
}
}

View file

@ -1,304 +1,304 @@
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
const idVec3 GOLEM_ROCKS_NO_GRAVITY = idVec3(0,0,0);
const int GOLEM_ROCKS_MAX = 13;
const int GOLEM_ROCKS_MIN = 8;
const int GOLEM_ROCKS_MIN_CHECK_DELAY = 2000;
const int GOLEM_ROCKS_MAX_DIST = 300;
const int GOLEM_ROCKS_ATTRACT_SPEED = 240;
const int GOLEM_RICKS_MAX_MOVE_TIME_BEFORE_BIND = 5000;
const int GOLEM_ROCKS_BIND_DISTANCE = 16;
const idEventDef AI_Golem_SawEnemy( "SawEnemy" );
CLASS_DECLARATION( idAI, idAI_Golem )
EVENT( AI_Golem_SawEnemy, idAI_Golem::Event_SawEnemy )
END_CLASS
void idAI_Golem::Spawn() {
alive = false;
nextFindRocks = 0;
totRocks = 0;
nextBoneI = 0;
nextBone(); // start er off
golemType = spawnArgs.GetString("golemType");
onEnt = 0;
onFire = -1;
}
void idAI_Golem::Save( idSaveGame *savefile ) const {
savefile->WriteFloat( totRocks );
savefile->WriteFloat( nextFindRocks );
savefile->WriteInt( nextBoneI );
savefile->WriteString( curBone );
savefile->WriteString( golemType );
savefile->WriteBool( alive );
savefile->WriteInt( rocks.Num() );
for ( int i=0; i<rocks.Num(); i++ ) {
savefile->WriteObject( rocks[i] );
}
}
void idAI_Golem::Restore( idRestoreGame *savefile ) {
savefile->ReadFloat( totRocks );
savefile->ReadFloat( nextFindRocks );
savefile->ReadInt( nextBoneI );
savefile->ReadString( curBone );
savefile->ReadString( golemType );
savefile->ReadBool( alive );
int i;
savefile->ReadInt( i );
idClass *obj;
for ( ; i>0; i-- ) {
savefile->ReadObject( obj );
rocks.Append( static_cast< idMoveable* >( obj ) );
}
}
void idAI_Golem::findNewRocks() {
idMoveable *rock = FindGolemRock();
if ( rock ) {
addRock( rock );
}
}
void idAI_Golem::addRock( idMoveable *newRock ) {
newRock->BecomeNonSolid();
newRock->spawnArgs.SetBool("golem_owned", 1);
newRock->spawnArgs.SetFloat("golem_bindTime", gameLocal.time + GOLEM_RICKS_MAX_MOVE_TIME_BEFORE_BIND );
newRock->spawnArgs.SetBool("golem_bound", 0);
newRock->spawnArgs.Set("old_bounce", newRock->spawnArgs.GetString("snd_bounce") );
newRock->spawnArgs.Set("snd_bounce", ""); // no bounce sounds while on the golem, gets REAL annoying.
newRock->spawnArgs.Set("bone", curBone);
newRock->health = 1000;
newRock->GetPhysics()->DisableClip();
rocks.Append(newRock);
totRocks++;
nextBone();
}
void idAI_Golem::Think() {
idAI::Think();
if ( alive ) {
evalRocks();
}
}
void idAI_Golem::evalRocks() {
int i;
float length;
idVec3 dist;
idStr bone;
if ( gameLocal.time > nextFindRocks ) {
nextFindRocks = gameLocal.time + 2000; // find new rocks every 2 seconds
findNewRocks();
}
for (i=0; i < rocks.Num(); i++) {
if ( !rocks[i] ) {
continue;
}
bone = rocks[i]->spawnArgs.GetString("bone");
if ( !rocks[i]->spawnArgs.GetBool("golem_bound") ) {
dist = GetJointPos(animator.GetJointHandle(bone)) - rocks[i]->GetPhysics()->GetOrigin();
length = dist.Length();
// if rocks are close enough or max time movement has passed, bind them.
if ( length < GOLEM_ROCKS_BIND_DISTANCE || gameLocal.time > rocks[i]->spawnArgs.GetFloat("golem_bindTime") ) {
rocks[i]->GetPhysics()->SetGravity( GOLEM_ROCKS_NO_GRAVITY );
//rocks[i]->SetOrigin( GetLocalCoordinates( GetJointPos(animator.GetJointHandle(bone)) ) );
rocks[i]->SetOrigin( GetJointPos(animator.GetJointHandle(bone)) );
rocks[i]->spawnArgs.Set("golem_bound", "1");
rocks[i]->SetAngles( idAngles(gameLocal.random.RandomInt() % 200 - 100, gameLocal.random.RandomInt() % 200 - 100, gameLocal.random.RandomInt() % 200 - 100 ) );
rocks[i]->BindToJoint(this, bone, 1);
rocks[i]->GetPhysics()->EnableClip();
// else just move them
} else {
dist.Normalize();
//looks shitty: rocks[i]->GetPhysics()->SetAngularVelocity( idVec3(gameLocal.random.RandomInt() % 200 - 100, gameLocal.random.RandomInt() % 200 - 100, gameLocal.random.RandomInt() % 200 - 100 ) );
rocks[i]->GetPhysics()->SetLinearVelocity( dist * GOLEM_ROCKS_ATTRACT_SPEED );
}
continue;
}
// if a rock takes damage, the golem takes damage
if ( rocks[i]->health < 1000 ) {
Damage( NULL, NULL, idVec3(0,0,0), "damage_golem1", 1000 - rocks[i]->health, 0 ); // Z.TODO: this needs to be the damage def of the weapon used...somehow...
rocks[i]->health = 1000;
}
}
}
void idAI_Golem::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location, idVec3 &iPoint ) {
if ( !fl.takedamage ) {
return;
}
if ( !inflictor ) {
inflictor = gameLocal.world;
}
if ( !attacker ) {
attacker = gameLocal.world;
}
const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
if ( !damageDef ) {
gameLocal.Error( "Unknown damageDef '%s'", damageDefName );
}
int damage = damageDef->GetInt( "damage" ) * damageScale;
damage = GetDamageForLocation( damage, location );
// inform the attacker that they hit someone
attacker->DamageFeedback( this, inflictor, damage );
if ( damage > 0 ) {
health -= damage;
if ( health <= 0 ) {
if ( health < -999 ) {
health = -999;
}
gameLocal.Printf("BLOWUP!\n");
BlowUp();
Killed( inflictor, attacker, damage, dir, location );
} else {
Pain( inflictor, attacker, damage, dir, location );
}
} else {
// don't accumulate knockback
if ( af.IsLoaded() ) {
// clear impacts
af.Rest();
// physics is turned off by calling af.Rest()
BecomeActive( TH_PHYSICS );
}
}
}
void idAI_Golem::BlowUp( void ) {
//spawnArgs.SetVector( "origin", GetPhysics()->GetOrigin() );
//spawnArgs.Set( "classname", "proj_golemsoul" );
//gameLocal.SpawnEntityDef( spawnArgs );
//soul->GetPhysics()->SetOrigin( GetPhysics()->GetOrigin() );
// rocks get removed from head to toe.
for (int i=rocks.Num(); i >= 0; i--) {
if ( !rocks[i] ) {
rocks[i]->GetPhysics()->SetGravity(gameLocal.GetGravity());
rocks[i]->spawnArgs.Set("golem_owned", 0);
rocks[i]->spawnArgs.Set("golem_bound", 0);
rocks[i]->spawnArgs.Set("golem_bindTime", 0);
rocks[i]->spawnArgs.Set("snd_bounce", rocks[i]->spawnArgs.GetString("old_bounce") ); //Z.TODO
rocks[i]->Unbind();
rocks[i]->BecomeSolid();
idVec3 dx;
dx.x = gameLocal.random.RandomInt() % 200 - 100;
dx.y = gameLocal.random.RandomInt() % 200 - 100;
dx.z = ( gameLocal.random.RandomInt() % 100 ) * 3;
dx.Normalize();
rocks[i]->GetPhysics()->SetLinearVelocity( dx * 600 );
dx.x = gameLocal.random.RandomInt() % 200 - 100;
dx.y = gameLocal.random.RandomInt() % 200 - 100;
dx.z = gameLocal.random.RandomInt() % 200 - 100;
dx.Normalize();
rocks[i]->GetPhysics()->EnableClip();
rocks[i]->GetPhysics()->SetAngularVelocity( dx * 100 );
rocks.RemoveIndex(i);
}
}
}
void idAI_Golem::nextBone() {
// one rock per joint, from toe to head.
switch ( nextBoneI ) {
case 0: curBone = "lfoot"; break;
case 1: curBone = "rfoot"; break;
case 2: curBone = "lknee"; break;
case 3: curBone = "rknee"; break;
case 4: curBone = "pelvis"; break;
case 5: curBone = "spineup"; break;
case 6: curBone = "lhand"; break;
case 7: curBone = "rhand"; break;
case 8: curBone = "lloarm"; break;
case 9: curBone = "rloarm"; break;
case 10: curBone = "luparm"; break;
case 11: curBone = "ruparm"; break;
case 12: curBone = "head"; break;
default: curBone = ""; break;
}
nextBoneI++;
}
void idAI_Golem::Event_SawEnemy() {
alive=true;
}
const char * idAI_Golem::GetGolemType( void ) const {
return golemType.c_str();
}
// HEXEN : Zeroth
idMoveable *idAI_Golem::FindGolemRock( void ) {
int hash, i;
idMoveable *target=NULL;
hash = gameLocal.entypeHash.GenerateKey( idMoveable::Type.classname, true );
for ( i = gameLocal.entypeHash.First( hash ); i != -1; i = gameLocal.entypeHash.Next( i ) ) {
if ( gameLocal.entities[i] && gameLocal.entities[i]->IsType( idMoveable::Type ) ) {
target = static_cast< idMoveable* >( gameLocal.entities[i] );
if ( target->IsHidden() ) {
continue;
}
if ( target->spawnArgs.GetInt("golem_owned") == 1 ) {
continue;
}
/* smaller golemd haven't been implemented yet
if ( !target->spawnArgs.GetInt("forLargeGolem") ) {
continue;
}
*/
if ( GetGolemType() != target->spawnArgs.GetString("rockType") ) {
continue;
}
// trace from golem to rock
trace_t trace;
idEntity *traceEnt = NULL;
gameLocal.clip.TraceBounds( trace,
GetJointPos( animator.GetJointHandle( curBone ) ),
target->GetPhysics()->GetOrigin(),
idBounds( GOLEM_TRACE_MINS, GOLEM_TRACE_MAXS ),
MASK_MONSTERSOLID,
this );
if ( trace.fraction < 1.0f ) {
traceEnt = gameLocal.entities[ trace.c.entityNum ];
}
// make sure rock isn't through a wall or something.
if ( !traceEnt || traceEnt != target ) {
continue;
}
return target;
}
}
return NULL;
}
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
const idVec3 GOLEM_ROCKS_NO_GRAVITY = idVec3(0,0,0);
const int GOLEM_ROCKS_MAX = 13;
const int GOLEM_ROCKS_MIN = 8;
const int GOLEM_ROCKS_MIN_CHECK_DELAY = 2000;
const int GOLEM_ROCKS_MAX_DIST = 300;
const int GOLEM_ROCKS_ATTRACT_SPEED = 240;
const int GOLEM_RICKS_MAX_MOVE_TIME_BEFORE_BIND = 5000;
const int GOLEM_ROCKS_BIND_DISTANCE = 16;
const idEventDef AI_Golem_SawEnemy( "SawEnemy" );
CLASS_DECLARATION( idAI, idAI_Golem )
EVENT( AI_Golem_SawEnemy, idAI_Golem::Event_SawEnemy )
END_CLASS
void idAI_Golem::Spawn() {
alive = false;
nextFindRocks = 0;
totRocks = 0;
nextBoneI = 0;
nextBone(); // start er off
golemType = spawnArgs.GetString("golemType");
onEnt = 0;
onFire = -1;
}
void idAI_Golem::Save( idSaveGame *savefile ) const {
savefile->WriteFloat( totRocks );
savefile->WriteFloat( nextFindRocks );
savefile->WriteInt( nextBoneI );
savefile->WriteString( curBone );
savefile->WriteString( golemType );
savefile->WriteBool( alive );
savefile->WriteInt( rocks.Num() );
for ( int i=0; i<rocks.Num(); i++ ) {
savefile->WriteObject( rocks[i] );
}
}
void idAI_Golem::Restore( idRestoreGame *savefile ) {
savefile->ReadFloat( totRocks );
savefile->ReadFloat( nextFindRocks );
savefile->ReadInt( nextBoneI );
savefile->ReadString( curBone );
savefile->ReadString( golemType );
savefile->ReadBool( alive );
int i;
savefile->ReadInt( i );
idClass *obj;
for ( ; i>0; i-- ) {
savefile->ReadObject( obj );
rocks.Append( static_cast< idMoveable* >( obj ) );
}
}
void idAI_Golem::findNewRocks() {
idMoveable *rock = FindGolemRock();
if ( rock ) {
addRock( rock );
}
}
void idAI_Golem::addRock( idMoveable *newRock ) {
newRock->BecomeNonSolid();
newRock->spawnArgs.SetBool("golem_owned", 1);
newRock->spawnArgs.SetFloat("golem_bindTime", gameLocal.time + GOLEM_RICKS_MAX_MOVE_TIME_BEFORE_BIND );
newRock->spawnArgs.SetBool("golem_bound", 0);
newRock->spawnArgs.Set("old_bounce", newRock->spawnArgs.GetString("snd_bounce") );
newRock->spawnArgs.Set("snd_bounce", ""); // no bounce sounds while on the golem, gets REAL annoying.
newRock->spawnArgs.Set("bone", curBone);
newRock->health = 1000;
newRock->GetPhysics()->DisableClip();
rocks.Append(newRock);
totRocks++;
nextBone();
}
void idAI_Golem::Think() {
idAI::Think();
if ( alive ) {
evalRocks();
}
}
void idAI_Golem::evalRocks() {
int i;
float length;
idVec3 dist;
idStr bone;
if ( gameLocal.time > nextFindRocks ) {
nextFindRocks = gameLocal.time + 2000; // find new rocks every 2 seconds
findNewRocks();
}
for (i=0; i < rocks.Num(); i++) {
if ( !rocks[i] ) {
continue;
}
bone = rocks[i]->spawnArgs.GetString("bone");
if ( !rocks[i]->spawnArgs.GetBool("golem_bound") ) {
dist = GetJointPos(animator.GetJointHandle(bone)) - rocks[i]->GetPhysics()->GetOrigin();
length = dist.Length();
// if rocks are close enough or max time movement has passed, bind them.
if ( length < GOLEM_ROCKS_BIND_DISTANCE || gameLocal.time > rocks[i]->spawnArgs.GetFloat("golem_bindTime") ) {
rocks[i]->GetPhysics()->SetGravity( GOLEM_ROCKS_NO_GRAVITY );
//rocks[i]->SetOrigin( GetLocalCoordinates( GetJointPos(animator.GetJointHandle(bone)) ) );
rocks[i]->SetOrigin( GetJointPos(animator.GetJointHandle(bone)) );
rocks[i]->spawnArgs.Set("golem_bound", "1");
rocks[i]->SetAngles( idAngles(gameLocal.random.RandomInt() % 200 - 100, gameLocal.random.RandomInt() % 200 - 100, gameLocal.random.RandomInt() % 200 - 100 ) );
rocks[i]->BindToJoint(this, bone, 1);
rocks[i]->GetPhysics()->EnableClip();
// else just move them
} else {
dist.Normalize();
//looks shitty: rocks[i]->GetPhysics()->SetAngularVelocity( idVec3(gameLocal.random.RandomInt() % 200 - 100, gameLocal.random.RandomInt() % 200 - 100, gameLocal.random.RandomInt() % 200 - 100 ) );
rocks[i]->GetPhysics()->SetLinearVelocity( dist * GOLEM_ROCKS_ATTRACT_SPEED );
}
continue;
}
// if a rock takes damage, the golem takes damage
if ( rocks[i]->health < 1000 ) {
Damage( NULL, NULL, idVec3(0,0,0), "damage_golem1", 1000 - rocks[i]->health, 0 ); // Z.TODO: this needs to be the damage def of the weapon used...somehow...
rocks[i]->health = 1000;
}
}
}
void idAI_Golem::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location, idVec3 &iPoint ) {
if ( !fl.takedamage ) {
return;
}
if ( !inflictor ) {
inflictor = gameLocal.world;
}
if ( !attacker ) {
attacker = gameLocal.world;
}
const idDict *damageDef = gameLocal.FindEntityDefDict( damageDefName );
if ( !damageDef ) {
gameLocal.Error( "Unknown damageDef '%s'", damageDefName );
}
int damage = damageDef->GetInt( "damage" ) * damageScale;
damage = GetDamageForLocation( damage, location );
// inform the attacker that they hit someone
attacker->DamageFeedback( this, inflictor, damage );
if ( damage > 0 ) {
health -= damage;
if ( health <= 0 ) {
if ( health < -999 ) {
health = -999;
}
gameLocal.Printf("BLOWUP!\n");
BlowUp();
Killed( inflictor, attacker, damage, dir, location );
} else {
Pain( inflictor, attacker, damage, dir, location );
}
} else {
// don't accumulate knockback
if ( af.IsLoaded() ) {
// clear impacts
af.Rest();
// physics is turned off by calling af.Rest()
BecomeActive( TH_PHYSICS );
}
}
}
void idAI_Golem::BlowUp( void ) {
//spawnArgs.SetVector( "origin", GetPhysics()->GetOrigin() );
//spawnArgs.Set( "classname", "proj_golemsoul" );
//gameLocal.SpawnEntityDef( spawnArgs );
//soul->GetPhysics()->SetOrigin( GetPhysics()->GetOrigin() );
// rocks get removed from head to toe.
for (int i=rocks.Num(); i >= 0; i--) {
if ( !rocks[i] ) {
rocks[i]->GetPhysics()->SetGravity(gameLocal.GetGravity());
rocks[i]->spawnArgs.Set("golem_owned", 0);
rocks[i]->spawnArgs.Set("golem_bound", 0);
rocks[i]->spawnArgs.Set("golem_bindTime", 0);
rocks[i]->spawnArgs.Set("snd_bounce", rocks[i]->spawnArgs.GetString("old_bounce") ); //Z.TODO
rocks[i]->Unbind();
rocks[i]->BecomeSolid();
idVec3 dx;
dx.x = gameLocal.random.RandomInt() % 200 - 100;
dx.y = gameLocal.random.RandomInt() % 200 - 100;
dx.z = ( gameLocal.random.RandomInt() % 100 ) * 3;
dx.Normalize();
rocks[i]->GetPhysics()->SetLinearVelocity( dx * 600 );
dx.x = gameLocal.random.RandomInt() % 200 - 100;
dx.y = gameLocal.random.RandomInt() % 200 - 100;
dx.z = gameLocal.random.RandomInt() % 200 - 100;
dx.Normalize();
rocks[i]->GetPhysics()->EnableClip();
rocks[i]->GetPhysics()->SetAngularVelocity( dx * 100 );
rocks.RemoveIndex(i);
}
}
}
void idAI_Golem::nextBone() {
// one rock per joint, from toe to head.
switch ( nextBoneI ) {
case 0: curBone = "lfoot"; break;
case 1: curBone = "rfoot"; break;
case 2: curBone = "lknee"; break;
case 3: curBone = "rknee"; break;
case 4: curBone = "pelvis"; break;
case 5: curBone = "spineup"; break;
case 6: curBone = "lhand"; break;
case 7: curBone = "rhand"; break;
case 8: curBone = "lloarm"; break;
case 9: curBone = "rloarm"; break;
case 10: curBone = "luparm"; break;
case 11: curBone = "ruparm"; break;
case 12: curBone = "head"; break;
default: curBone = ""; break;
}
nextBoneI++;
}
void idAI_Golem::Event_SawEnemy() {
alive=true;
}
const char * idAI_Golem::GetGolemType( void ) const {
return golemType.c_str();
}
// HEXEN : Zeroth
idMoveable *idAI_Golem::FindGolemRock( void ) {
int hash, i;
idMoveable *target=NULL;
hash = gameLocal.entypeHash.GenerateKey( idMoveable::Type.classname, true );
for ( i = gameLocal.entypeHash.First( hash ); i != -1; i = gameLocal.entypeHash.Next( i ) ) {
if ( gameLocal.entities[i] && gameLocal.entities[i]->IsType( idMoveable::Type ) ) {
target = static_cast< idMoveable* >( gameLocal.entities[i] );
if ( target->IsHidden() ) {
continue;
}
if ( target->spawnArgs.GetInt("golem_owned") == 1 ) {
continue;
}
/* smaller golemd haven't been implemented yet
if ( !target->spawnArgs.GetInt("forLargeGolem") ) {
continue;
}
*/
if ( GetGolemType() != target->spawnArgs.GetString("rockType") ) {
continue;
}
// trace from golem to rock
trace_t trace;
idEntity *traceEnt = NULL;
gameLocal.clip.TraceBounds( trace,
GetJointPos( animator.GetJointHandle( curBone ) ),
target->GetPhysics()->GetOrigin(),
idBounds( GOLEM_TRACE_MINS, GOLEM_TRACE_MAXS ),
MASK_MONSTERSOLID,
this );
if ( trace.fraction < 1.0f ) {
traceEnt = gameLocal.entities[ trace.c.entityNum ];
}
// make sure rock isn't through a wall or something.
if ( !traceEnt || traceEnt != target ) {
continue;
}
return target;
}
}
return NULL;
}

View file

@ -1,46 +1,46 @@
#ifndef __AI_GOLEM_
#define __AI_GOLEM_
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
const idVec3 GOLEM_TRACE_MINS = idVec3(-1,-1,-1);
const idVec3 GOLEM_TRACE_MAXS = idVec3(-1,-1,-1);
class idAI_Golem : public idAI {
public:
CLASS_PROTOTYPE( idAI_Golem );
void Spawn();
void Think();
void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location, idVec3 &iPoint );
void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) { idVec3 zero; Damage(inflictor, attacker, dir, damageDefName, damageScale, location, zero); }
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
public:
const char * GetGolemType( void ) const;
private:
float totRocks; // this IS the total number of rocks.
float nextFindRocks; // time delay for finding new rocks
int nextBoneI;
idStr curBone;
idStr golemType;
idList<idMoveable *> rocks;
bool alive;
int onEnt;
private:
void findNewRocks( void ); // look for new rocks
void addRock( idMoveable *newRock );
void evalRocks( void ); // call this every frame to do all rock related junk
void nextBone( void );
void BlowUp( void );
void Event_SawEnemy( void );
idMoveable *idAI_Golem::FindGolemRock( void );
};
#endif // __AI_GOLEM_
#ifndef __AI_GOLEM_
#define __AI_GOLEM_
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
const idVec3 GOLEM_TRACE_MINS = idVec3(-1,-1,-1);
const idVec3 GOLEM_TRACE_MAXS = idVec3(-1,-1,-1);
class idAI_Golem : public idAI {
public:
CLASS_PROTOTYPE( idAI_Golem );
void Spawn();
void Think();
void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location, idVec3 &iPoint );
void Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir, const char *damageDefName, const float damageScale, const int location ) { idVec3 zero; Damage(inflictor, attacker, dir, damageDefName, damageScale, location, zero); }
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
public:
const char * GetGolemType( void ) const;
private:
float totRocks; // this IS the total number of rocks.
float nextFindRocks; // time delay for finding new rocks
int nextBoneI;
idStr curBone;
idStr golemType;
idList<idMoveable *> rocks;
bool alive;
int onEnt;
private:
void findNewRocks( void ); // look for new rocks
void addRock( idMoveable *newRock );
void evalRocks( void ); // call this every frame to do all rock related junk
void nextBone( void );
void BlowUp( void );
void Event_SawEnemy( void );
idMoveable *idAI_Golem::FindGolemRock( void );
};
#endif // __AI_GOLEM_

View file

@ -1,118 +1,118 @@
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
const int SHADOWSPAWN_RANGE_ATTACK_RATE = 3;
const int SHADOWSPAWN_DRAIN_RATE = 10;
#if 0
CLASS_DECLARATION( idAI, idAI_Shadowspawn )
END_CLASS
void idAI_Shadowspawn::regenerate() {
float drainTime=0;
idVec3 dir;
float giveUp=DelayTime(5);
// // regenerate 2 health every second
// if ( regenTime > ( gameLocal.time / 1000 ) && getHealth() < getFloat("health") ) {
// setHealth(getHealth() + 1);
// regenTime = delaytime(1);
// }
//vec.Length(GetOrigin() - enemy.GetEyePos()) < 80
if ( !enemy ) {
return;
}
SetAnimState( ANIMCHANNEL_TORSO, "Torso_TelePull", 4 );
stayPut=getWorldOrigin(); // shadowspawn should not be moved by projectiles, etc, might put player outside of level
while ( 1 ) {
setWorldOrigin(stayPut);
if ( vec.Length(stayPut - enemy->GetPhysics()->GetOrigin()()) < 90 ) {
break;
} else if (( gameLocal.time / 1000 ) > giveUp) {
SetAnimState( ANIMCHANNEL_TORSO, "Torso_Idle", 4 );
return;
}
enemy->GetPhysics()->SetLinearVelocity( sys.vecNormalize(stayPut - enemy->GetPhysics()->GetOrigin()()) * 80);
waitFrame();
}
enemy.bind(me);
//enemyStayPut = enemy.getWorldOrigin();
float tim=DelayTime(2);
//vector turny = getAngles();
SetAnimState( ANIMCHANNEL_TORSO, "Torso_AttackDrain", 4 );
while ( 1 ) {
setWorldOrigin(stayPut); // shadowspawn should not be moved by projectiles, etc, might put player outside of level
//enemy.setWorldOrigin(enemyStayPut);
//turnTo(turny.y + 180);
if (drainTime < ( gameLocal.time / 1000 )) {
drainTime = DelayTime(1);
directDamage(enemy, "damage_shadowspawn_drain");
setHealth(getHealth()+100);
}
if ( tim < ( gameLocal.time / 1000 ) ) {
SetAnimState( ANIMCHANNEL_TORSO, "Torso_Repulse", 4 );
waitAction( "repulse" );
enemy.unbind();
dir = sys.vecNormalize(enemy->GetPhysics()->GetOrigin()() - stayPut) * 1180;
dir.z = 0;
enemy->GetPhysics()->SetLinearVelocity( dir );
break;
}
waitFrame();
}
}
void idAI_Shadowspawn::telleport() {
float tDelay;
idVec3 pV;
float dist;
float ang;
idVec3 enemyOrigin = enemy->GetPhysics()->GetOrigin()();
nextTelleport = ( gameLocal.time / 1000 ) + sys.random(4)+7;
// lunge at player and disappear
pV = sys.vecNormalize(enemy.GetEyePos() - GetOrigin());
turnToEntity(enemy);
tDelay = 1 + ( gameLocal.time / 1000 );
GetPhysics()->SetLinearVelocity(pV * 1066);
while (( gameLocal.time / 1000 ) < tDelay && vec.Length(GetOrigin() - enemy.GetEyePos()) > 20) {
waitFrame();
}
hide();
// delay
tDelay = sys.random(3) + ( gameLocal.time / 1000 );
while (( gameLocal.time / 1000 ) < tDelay) {
waitFrame();
}
// reappear
ang = sys.random(360);
dist = sys.random(350)+150;
pV = enemy.GetEyePos();
pV.x = pV.x + dist * sys.sin(ang);
pV.y = pV.y + dist * sys.cos(ang);
//pV.z = enemyOrigin.z;
SetOrigin(pV);
show();
doTelleport = false;
}
#endif
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
const int SHADOWSPAWN_RANGE_ATTACK_RATE = 3;
const int SHADOWSPAWN_DRAIN_RATE = 10;
#if 0
CLASS_DECLARATION( idAI, idAI_Shadowspawn )
END_CLASS
void idAI_Shadowspawn::regenerate() {
float drainTime=0;
idVec3 dir;
float giveUp=DelayTime(5);
// // regenerate 2 health every second
// if ( regenTime > ( gameLocal.time / 1000 ) && getHealth() < getFloat("health") ) {
// setHealth(getHealth() + 1);
// regenTime = delaytime(1);
// }
//vec.Length(GetOrigin() - enemy.GetEyePos()) < 80
if ( !enemy ) {
return;
}
SetAnimState( ANIMCHANNEL_TORSO, "Torso_TelePull", 4 );
stayPut=getWorldOrigin(); // shadowspawn should not be moved by projectiles, etc, might put player outside of level
while ( 1 ) {
setWorldOrigin(stayPut);
if ( vec.Length(stayPut - enemy->GetPhysics()->GetOrigin()()) < 90 ) {
break;
} else if (( gameLocal.time / 1000 ) > giveUp) {
SetAnimState( ANIMCHANNEL_TORSO, "Torso_Idle", 4 );
return;
}
enemy->GetPhysics()->SetLinearVelocity( sys.vecNormalize(stayPut - enemy->GetPhysics()->GetOrigin()()) * 80);
waitFrame();
}
enemy.bind(me);
//enemyStayPut = enemy.getWorldOrigin();
float tim=DelayTime(2);
//vector turny = getAngles();
SetAnimState( ANIMCHANNEL_TORSO, "Torso_AttackDrain", 4 );
while ( 1 ) {
setWorldOrigin(stayPut); // shadowspawn should not be moved by projectiles, etc, might put player outside of level
//enemy.setWorldOrigin(enemyStayPut);
//turnTo(turny.y + 180);
if (drainTime < ( gameLocal.time / 1000 )) {
drainTime = DelayTime(1);
directDamage(enemy, "damage_shadowspawn_drain");
setHealth(getHealth()+100);
}
if ( tim < ( gameLocal.time / 1000 ) ) {
SetAnimState( ANIMCHANNEL_TORSO, "Torso_Repulse", 4 );
waitAction( "repulse" );
enemy.unbind();
dir = sys.vecNormalize(enemy->GetPhysics()->GetOrigin()() - stayPut) * 1180;
dir.z = 0;
enemy->GetPhysics()->SetLinearVelocity( dir );
break;
}
waitFrame();
}
}
void idAI_Shadowspawn::telleport() {
float tDelay;
idVec3 pV;
float dist;
float ang;
idVec3 enemyOrigin = enemy->GetPhysics()->GetOrigin()();
nextTelleport = ( gameLocal.time / 1000 ) + sys.random(4)+7;
// lunge at player and disappear
pV = sys.vecNormalize(enemy.GetEyePos() - GetOrigin());
turnToEntity(enemy);
tDelay = 1 + ( gameLocal.time / 1000 );
GetPhysics()->SetLinearVelocity(pV * 1066);
while (( gameLocal.time / 1000 ) < tDelay && vec.Length(GetOrigin() - enemy.GetEyePos()) > 20) {
waitFrame();
}
hide();
// delay
tDelay = sys.random(3) + ( gameLocal.time / 1000 );
while (( gameLocal.time / 1000 ) < tDelay) {
waitFrame();
}
// reappear
ang = sys.random(360);
dist = sys.random(350)+150;
pV = enemy.GetEyePos();
pV.x = pV.x + dist * sys.sin(ang);
pV.y = pV.y + dist * sys.cos(ang);
//pV.z = enemyOrigin.z;
SetOrigin(pV);
show();
doTelleport = false;
}
#endif

View file

@ -1,15 +1,15 @@
#if 0
class idAI_Shadowspawn : public idAI {
public:
CLASS_PROTOTYPE( idAI_Shadowspawn );
void telleport();
void Spawn();
void regenerate();
private:
idEntity enemy;
idVec3 stayPut;
//vector enemyStayPut;
};
#endif
#if 0
class idAI_Shadowspawn : public idAI {
public:
CLASS_PROTOTYPE( idAI_Shadowspawn );
void telleport();
void Spawn();
void regenerate();
private:
idEntity enemy;
idVec3 stayPut;
//vector enemyStayPut;
};
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,108 +1,108 @@
#ifndef __AI_VELOXITE_H__
#define __AI_VELOXITE_H__
typedef enum v_stype {
v_none = 0,
v_slope = 1,
v_wall = 2
};
class idAI_Veloxite : public idAI {
public:
CLASS_PROTOTYPE( idAI_Veloxite );
void Spawn( void );
void Think( void );
void LinkScriptVariables( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
// ***********************************************************
// Helper Functions
// ***********************************************************
private:
ID_INLINE bool onWall( void );
ID_INLINE bool wallIsWalkable( idEntity *wall );
ID_INLINE v_stype surfaceType( idVec3 normal );
// ***********************************************************
// Class Method Declarations
// ***********************************************************
private:
// surface checks etc
float checkSurfaces( void );
bool checkSlope( void );
bool checkLedge( void );
bool checkWall( void );
void getOnSurface( const idVec3 &norm, int numt = 0 );
void getOffSurface( bool fall );
void doSurfaceTransition( void );
void postSurfaceTransition( void );
// player chasing / attacks
bool checkDropAttack( void );
// bool checkParallel( void ); // if enemy is above velox (relative to velox's gravity) and there there is floor to drop on, do it.
// fix oops's
bool checkFallingSideways( void ); // if we're going faster than 300, we must be falling, make sure it's truly straight down!
bool checkHovering( void ); // if we're AI_ONGROUND but origin is not above a surface, we're hovering over a ledge. do something...
// ***********************************************************
// Variables
// ***********************************************************
private:
// transitions
bool doPostTrans;
bool doTrans;
int curTrans;
int numTrans; // in frames
idVec3 transGrav;
idVec3 destGrav;
idVec3 upVec;
// other stuff
trace_t trace;
float nextWallCheck;
float maxGraceTime;
float debuglevel;
idVec3 veloxMins;
idVec3 veloxMaxs;
idVec3 traceMins;float next;
idVec3 traceMaxs;
/* Debug Level:
1 - useful functions that dont happen every frame
5 - useful functions that happen every frame
10 - unuseful functions that happen every frame
15 - unuseful functions that may happen more than every frame
20 - things you'll functions never want to see
*/
// ***********************************************************
// Script Stuff
// ***********************************************************
protected:
idScriptBool AI_ALIGNING;
idScriptBool AI_WALLING;
idScriptBool AI_LEDGING;
idScriptBool AI_SLOPING;
idScriptBool AI_LEAPING;
idScriptBool AI_FALLING;
idScriptBool AI_DROPATTACK;
idScriptBool AI_ONWALL;
private:
void Event_doSurfaceChecks( void );
void Event_doneLeaping( void );
void Event_startLeaping( void );
void Event_getVeloxJumpVelocity( float speed, float max_height, float channel, const char *animname );
void Event_getOffWall( float fall );
};
#endif // __AI_VELOXITE_H__
#ifndef __AI_VELOXITE_H__
#define __AI_VELOXITE_H__
typedef enum v_stype {
v_none = 0,
v_slope = 1,
v_wall = 2
};
class idAI_Veloxite : public idAI {
public:
CLASS_PROTOTYPE( idAI_Veloxite );
void Spawn( void );
void Think( void );
void LinkScriptVariables( void );
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
// ***********************************************************
// Helper Functions
// ***********************************************************
private:
ID_INLINE bool onWall( void );
ID_INLINE bool wallIsWalkable( idEntity *wall );
ID_INLINE v_stype surfaceType( idVec3 normal );
// ***********************************************************
// Class Method Declarations
// ***********************************************************
private:
// surface checks etc
float checkSurfaces( void );
bool checkSlope( void );
bool checkLedge( void );
bool checkWall( void );
void getOnSurface( const idVec3 &norm, int numt = 0 );
void getOffSurface( bool fall );
void doSurfaceTransition( void );
void postSurfaceTransition( void );
// player chasing / attacks
bool checkDropAttack( void );
// bool checkParallel( void ); // if enemy is above velox (relative to velox's gravity) and there there is floor to drop on, do it.
// fix oops's
bool checkFallingSideways( void ); // if we're going faster than 300, we must be falling, make sure it's truly straight down!
bool checkHovering( void ); // if we're AI_ONGROUND but origin is not above a surface, we're hovering over a ledge. do something...
// ***********************************************************
// Variables
// ***********************************************************
private:
// transitions
bool doPostTrans;
bool doTrans;
int curTrans;
int numTrans; // in frames
idVec3 transGrav;
idVec3 destGrav;
idVec3 upVec;
// other stuff
trace_t trace;
float nextWallCheck;
float maxGraceTime;
float debuglevel;
idVec3 veloxMins;
idVec3 veloxMaxs;
idVec3 traceMins;float next;
idVec3 traceMaxs;
/* Debug Level:
1 - useful functions that dont happen every frame
5 - useful functions that happen every frame
10 - unuseful functions that happen every frame
15 - unuseful functions that may happen more than every frame
20 - things you'll functions never want to see
*/
// ***********************************************************
// Script Stuff
// ***********************************************************
protected:
idScriptBool AI_ALIGNING;
idScriptBool AI_WALLING;
idScriptBool AI_LEDGING;
idScriptBool AI_SLOPING;
idScriptBool AI_LEAPING;
idScriptBool AI_FALLING;
idScriptBool AI_DROPATTACK;
idScriptBool AI_ONWALL;
private:
void Event_doSurfaceChecks( void );
void Event_doneLeaping( void );
void Event_startLeaping( void );
void Event_getVeloxJumpVelocity( float speed, float max_height, float channel, const char *animname );
void Event_getOffWall( float fall );
};
#endif // __AI_VELOXITE_H__

View file

@ -0,0 +1,15 @@
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
CLASS_DECLARATION( idEntity, idEntity_MultiModel )
END_CLASS
void idEntity_MultiModel::Spawn() { }
void idEntity_MultiModel::Think() {
idEntity::Think();
}

View file

@ -0,0 +1,14 @@
#ifndef __CHAOSDEVICEMODEL_H__
#define __CHAOSDEVICEMODEL_H__
class idEntity_ChaosDeviceModel : idEntity {
public:
CLASS_PROTOTYPE( idEntity_ChaosDeviceModel );
void Spawn();
void Think();
private:
};
#endif // __CHAOSDEVICEMODEL_H__

85
game/objects/Leaf.cpp Normal file
View file

@ -0,0 +1,85 @@
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
CLASS_DECLARATION( idMoveable, idEntity_Leaf )
END_CLASS
void idEntity_Leaf::Spawn() {
liveTime = spawnArgs.GetFloat( "leaf_liveTime" ); // in seconds. Keep this low to prevent too many leaves in the map at a time. each leaf is an entity! Try to make each leaf live at least until it touches the ground. Some leaves will slide along the ground if they live long enough. default: 8
moveSpeed = spawnArgs.GetFloat( "leaf_moveSpeed" ); // from 1-10. How fast the leaves move regardless of wind. Keep this high. default: 10
spread = spawnArgs.GetFloat( "leaf_spread" ); // from 1-10. Affects how far apart leafs speread apart when falling. default: 10
windPower = spawnArgs.GetFloat( "leaf_windPower" ); // from 1-10. How strong the wind is on the leaves. default: 1
windDir = spawnArgs.GetVector("leaf_windDir" ); // Wind direction. default: '0 1 0'
gravity = spawnArgs.GetVector("leaf_gravity" ); // Gravity of the leaf. Keep this pretty low, or accept the default. default: '0 0 -20'
origin = spawnArgs.GetVector("leaf_origin" );
ang = GetAngles();
dieTime = gameLocal.time + liveTime * 1000;
if ( moveSpeed == 0 ) {
moveSpeed = 1;
}
if ( origin != idVec3( 0, 0, 0 ) ) {
SetOrigin( origin );
}
spread = spread / 20; //max spread is 0.5
dir = gameLocal.random.RandomInt( 3 );
if ( dir < 1 ) { spreadX = spread; }
else if ( dir < 2 && dir > 1 ) { spreadX = 0; }
else { spreadX = -spread; }
dir = gameLocal.random.RandomInt( 3 );
if ( dir < 1 ) { spreadY = spread; }
else if ( dir < 2 && dir > 1 ) { spreadY = 0; }
else { spreadY = -spread; }
SetAngles( idAngles( gameLocal.random.CRandomFloat()*360, gameLocal.random.CRandomFloat()*360, gameLocal.random.CRandomFloat()*360) );
GetPhysics()->SetLinearVelocity( idVec3( 0, 0, 0 ) );
GetPhysics()->SetGravity( idVec3( 0, 0, 0 ) ); //gravity - if we set zero gravity, the leaves stop when they hit the ground. dont know why, but it's cool!
curVel = GetPhysics()->GetLinearVelocity();
nextAngles = 0;
}
void idEntity_Leaf::Think() {
idEntity::Think();
if ( gameLocal.time >= dieTime ) {
PostEventMS( &EV_Remove, 0.0 );
}
if ( gameLocal.random.RandomInt( 100 ) > 33 ) {
return;
}
curDir = GetPhysics()->GetLinearVelocity();
curDir.Normalize();
curDir.x = curDir.x + gameLocal.random.RandomFloat() - 0.5 + windDir.x * ( windPower / 14 );
curDir.y = curDir.y + gameLocal.random.RandomFloat() - 0.5 + windDir.y * ( windPower / 14 );
curDir.z = curDir.z + gameLocal.random.RandomFloat() - 0.5 + windDir.z * ( windPower / 14 );
// more spread
curDir.x = curDir.x + spreadX;
curDir.y = curDir.y + spreadY;
curVel = curDir * moveSpeed * ( windPower + 1 ) + gravity;
GetPhysics()->SetLinearVelocity( curVel );
if ( gameLocal.time > nextAngles ) {
angles.x = gameLocal.random.CRandomFloat();
angles.y = gameLocal.random.CRandomFloat();
angles.z = gameLocal.random.CRandomFloat();
angles.Normalize();
angles *= 180 * ( windPower / 10 );
GetPhysics()->SetAngularVelocity( angles );
nextAngles = gameLocal.time + 500 + gameLocal.random.RandomFloat() * 3000;
}
}

29
game/objects/Leaf.h Normal file
View file

@ -0,0 +1,29 @@
#ifndef __LEAF_H__
#define __LEAF_H__
class idEntity_Leaf : idMoveable {
public:
CLASS_PROTOTYPE( idEntity_Leaf );
void Spawn();
void Think();
private:
float liveTime;
float moveSpeed;
float spread;
float windPower;
idVec3 windDir;
idVec3 gravity;
idVec3 origin;
idVec3 curDir;
idVec3 angles;
idVec3 curVel;
idAngles ang;
float spreadX;
float spreadY;
float dir;
float dieTime;
float nextAngles;
};
#endif // __LEAF_H__

View file

@ -0,0 +1,42 @@
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
#include "LeafEmitter.h"
CLASS_DECLARATION( idEntity, idEntity_LeafEmitter )
END_CLASS
void idEntity_LeafEmitter::Spawn() {
nextLeaf=0;
interval=spawnArgs.GetFloat( "emitter_leaf_interval" );
maxLeaf=spawnArgs.GetFloat( "emitter_leaf_max" );
leaf.SetFloat("leaf_liveTime", spawnArgs.GetFloat("leaf_liveTime"));
leaf.SetFloat("leaf_spread", spawnArgs.GetFloat("leaf_spread"));
leaf.SetFloat("leaf_windPower", spawnArgs.GetFloat("leaf_windPower"));
leaf.SetVector("leaf_windDir", spawnArgs.GetVector("leaf_windDir"));
leaf.SetFloat("leaf_moveSpeed", spawnArgs.GetFloat("leaf_moveSpeed"));
leaf.SetVector("leaf_gravity", spawnArgs.GetVector("leaf_gravity"));
leaf.SetFloat("leaf_maxSpinSpeed", spawnArgs.GetFloat("leaf_maxSpinSpeed"));
leaf.SetVector("leaf_origin", GetPhysics()->GetOrigin());
}
void idEntity_LeafEmitter::Think() {
if ( ( gameLocal.time / 1000 ) > nextLeaf) {
float i = gameLocal.random.RandomFloat() * 4;
if ( gameLocal.random.RandomInt(1) > 1 ) {
leaf.Set("classname", "object_leaf_lg");
} else {
leaf.Set("classname", "object_leaf_sm");
}
gameLocal.SpawnEntityDef( leaf );
nextLeaf = ( gameLocal.time / 1000 ) + interval;
}
}

View file

@ -0,0 +1,17 @@
#ifndef __LEAFEMITTER_H__
#define __LEAFEMITTER_H__
class idEntity_LeafEmitter : idEntity {
public:
CLASS_PROTOTYPE( idEntity_LeafEmitter );
void Spawn();
void Think();
private:
float nextLeaf;
float interval;
float maxLeaf;
idDict leaf;
};
#endif // __LEAFEMITTER_H__

77
game/objects/Tree.cpp Normal file
View file

@ -0,0 +1,77 @@
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
CLASS_DECLARATION( idAnimated, idAnimated_Tree )
END_CLASS
void idAnimated_Tree::Spawn() {
// randomize tree branch positions
RandomizeJoints();
// set up swaying
idVec3 treeDim = GetModelDims();
normAngle = idAngles( 0, 0, 0 );
windSpeed = spawnArgs.GetFloat( "wind_speed" );
maxAngle = RAD2DEG( idMath::ATan( OBJECT_TREE_MAX_SWAY_DIST / treeDim.z ) );
float useAngle = maxAngle * ( windSpeed / OBJECT_TREE_MAX_WIND_SPEED );
swayAngle = spawnArgs.GetAngles( "wind_dir" ); swayAngle *= useAngle;
randSwayRange = useAngle / 8; // an eighth of swayAngle
swayTime = 3000 - ( ( windSpeed / OBJECT_TREE_MAX_WIND_SPEED ) * 2000 ) + 1000; // 1 < swatTime < 3
transitions = ( swayTime / 1000 ) * OBJECT_TREE_JOINT_ANGLE_TRANSITIONS_PER_SEC;
swayDir = 1;
}
void idAnimated_Tree::Think( void ) {
idAngles to;
float doSpeed;
float rndTime;
idAnimated::Think();
if ( ( gameLocal.time ) < nextSway ) {
return;
}
if ( swayDir == 1 ) {
swayDir = -1;
to = swayAngle;
to.yaw = to.yaw + gameLocal.random.RandomInt(randSwayRange*2) - randSwayRange;
to.pitch = to.pitch + gameLocal.random.RandomInt(randSwayRange*2) - randSwayRange;
// only a forward sway should have decreased time per transition (wind gusts)
rndTime = gameLocal.random.RandomFloat() - 0.5;
} else {
swayDir = 1;
float rnd = ( gameLocal.random.RandomFloat() * windSpeed / 2 ) / OBJECT_TREE_MAX_WIND_SPEED ; // the faster the wind, the less likely to make a full backsway (wind gusts)
to = swayAngle * rnd;
rndTime = gameLocal.random.RandomFloat() / 32;
}
doSpeed = swayTime + ( rndTime * 1000 );
for (int i=0; i<OBJECT_TREE_NUM_JOINTS; i++) {
TransitionJointAngle( (jointHandle_t) i , (jointModTransform_t) 1, to, curAngle, doSpeed, transitions );
}
curAngle = to;
nextSway = gameLocal.time + doSpeed + OBJECT_TREE_PAUSE_TIME;
}
void idAnimated_Tree::RandomizeJoints( void ) {
idAngles curAng;
idAngles rndAng;
rndAng.yaw = gameLocal.random.RandomInt(OBJECT_TREE_MAX_RANDOM_JOINT_ANGLE*2) - OBJECT_TREE_MAX_RANDOM_JOINT_ANGLE;
rndAng.pitch = gameLocal.random.RandomInt(OBJECT_TREE_MAX_RANDOM_JOINT_ANGLE*2) - OBJECT_TREE_MAX_RANDOM_JOINT_ANGLE;
rndAng.roll = gameLocal.random.RandomInt(OBJECT_TREE_MAX_RANDOM_JOINT_ANGLE*2) - OBJECT_TREE_MAX_RANDOM_JOINT_ANGLE;
for (int i=0; i<OBJECT_TREE_NUM_JOINTS; i++) {
curAng = this->GetJointAngle( (jointHandle_t) i );
SetJointAngle( (jointHandle_t) i , (jointModTransform_t) 1, rndAng + curAng );
}
}

31
game/objects/Tree.h Normal file
View file

@ -0,0 +1,31 @@
#ifndef __TREE_H__
#define __TREE_H__
const int OBJECT_TREE_PAUSE_TIME = 0; // in ms, pause after each transition // update: this seems to make movement much less life-like, so I Set it to zero.
const int OBJECT_TREE_NUM_JOINTS = 5;
const int OBJECT_TREE_MAX_SWAY_DIST = 32; // in units, the maximum distance trees will sway when winds are strongest
const int OBJECT_TREE_MAX_WIND_SPEED = 10;
const int OBJECT_TREE_JOINT_ANGLE_TRANSITIONS_PER_SEC = 12; // this is about all we're gunna get. the joints don't update quick enough (at least on my system, but I assume it's time-based so it shouldnt matter). regardless, each transition is another calculation.
const int OBJECT_TREE_MAX_RANDOM_JOINT_ANGLE = 2;
class idAnimated_Tree : idAnimated {
public:
CLASS_PROTOTYPE( idAnimated_Tree );
void Spawn();
void Think();
void RandomizeJoints( void );
private:
idAngles normAngle;
idAngles curAngle;
float maxAngle;
idAngles swayAngle;
float swayDir;
float swayTime;
float randSwayRange;
float nextSway;
float transitions;
float windSpeed;
};
#endif // __TREE_H__

View file

@ -1670,3 +1670,13 @@ bool idClip::DrawModelContactFeature( const contactInfo_t &contact, const idClip
return true;
}
/*
============
Zeroth
idClipModel::GetRenderModelHandle
============
*/
int idClipModel::GetRenderModelHandle( void ) {
return renderModelHandle;
}

View file

@ -112,6 +112,8 @@ public:
static void SaveTraceModels( idSaveGame *savefile );
static void RestoreTraceModels( idRestoreGame *savefile );
// HEXEN : Zeroth
int GetRenderModelHandle( void );
private:
bool enabled; // true if this clip model is used for clipping
@ -277,6 +279,7 @@ public:
int contentMask, const idEntity *passEntity );
bool TraceBounds( trace_t &results, const idVec3 &start, const idVec3 &end, const idBounds &bounds,
int contentMask, const idEntity *passEntity );
idVec3 TraceSurfaceNormal( trace_t &results, const idVec3 &A, const idVec3 &B, const float clipMask, const idEntity *pass );
// clip versus a specific model
void TranslationModel( trace_t &results, const idVec3 &start, const idVec3 &end,
@ -340,6 +343,18 @@ ID_INLINE bool idClip::TracePoint( trace_t &results, const idVec3 &start, const
return ( results.fraction < 1.0f );
}
ID_INLINE idVec3 idClip::TraceSurfaceNormal( trace_t &trace, const idVec3 &A, const idVec3 &B, const float clipMask, const idEntity *pass ) {
TracePoint( trace, A, B, clipMask, pass );
// if near a surface
if ( trace.fraction < 1.0f ) {
idVec3 bub = trace.c.normal;
return trace.c.normal;
} else {
return idVec3( 0, 0, 0 );
}
}
ID_INLINE bool idClip::TraceBounds( trace_t &results, const idVec3 &start, const idVec3 &end, const idBounds &bounds, int contentMask, const idEntity *passEntity ) {
temporaryClipModel.LoadModel( idTraceModel( bounds ) );
Translation( results, start, end, &temporaryClipModel, mat3_identity, contentMask, passEntity );

View file

@ -91,6 +91,13 @@ public:
void Save( idSaveGame *savefile ) const;
void Restore( idRestoreGame *savefile );
// HEXEN : Zeroth
public:
idVec3 TransitionFromGravity;
idVec3 TransitionToGravity;
int curTransition;
float nextTransition;
public: // common physics interface
// set pointer to entity using physics
virtual void SetSelf( idEntity *e ) = 0;

View file

@ -6371,11 +6371,12 @@ bool idPhysics_AF::Evaluate( int timeStepMSec, int endTimeMSec ) {
AddPushVelocity( current.pushVelocity );
current.pushVelocity.Zero();
if ( IsOutsideWorld() ) {
gameLocal.Warning( "articulated figure moved outside world bounds for entity '%s' type '%s' at (%s)",
self->name.c_str(), self->GetType()->classname, bodies[0]->current->worldOrigin.ToString(0) );
Rest();
}
// HEXEN : Zeroth - for some entities, it is okay to move outside world bounds. would be nice to have a "canMoveOutsideWorld" spawnArg
// if ( IsOutsideWorld() ) {
// gameLocal.Warning( "articulated figure moved outside world bounds for entity '%s' type '%s' at (%s)",
// self->name.c_str(), self->GetType()->classname, bodies[0]->current->worldOrigin.ToString(0) );
// Rest();
// }
#ifdef AF_TIMINGS
timer_total.Stop();

View file

@ -275,9 +275,44 @@ idPhysics_Actor::SetGravity
================
*/
void idPhysics_Actor::SetGravity( const idVec3 &newGravity ) {
if ( newGravity != gravityVector ) {
idPhysics_Base::SetGravity( newGravity );
SetClipModelAxis();
if ( newGravity == gravityVector ) {
return;
}
idPlayer *player = NULL;
idAngles newVA;
idAngles oldang;
if ( self->IsType( idPlayer::Type ) ) {
player = static_cast<idPlayer *>( self );
oldang = player->GetAngles();
}
idPhysics_Base::SetGravity( newGravity );
SetClipModelAxis();
if ( player ) {
idAngles mang = player->GetAngles();
// fix view angles - not perfect, but best I can figure. todo: check out
oldang=mang-oldang;
newVA = player->viewAngles;
if ( mang.roll > 90 || mang.roll < -90 ) {
newVA.yaw += oldang.yaw;
// newVA.yaw += oldang.yaw * ( idMath::Fabs( mang.roll ) / 180.0f );
// gameLocal.Printf("up: %f\n", ( idMath::Fabs( mang.roll ) / 180.0f ));
} else {
newVA.yaw -= oldang.yaw;
// newVA.yaw -= oldang.yaw * ( ( 180.0f - idMath::Fabs( mang.roll ) ) / 180.0f );
// gameLocal.Printf("down %f\n", ( ( 180.0f - idMath::Fabs( mang.roll ) ) / 180.0f ) );
}
/* sorta works, but has a jerk now and again
newVA.yaw += oldang.yaw * ( idMath::Fabs( mang.roll ) / 180.0f );
newVA.yaw -= oldang.yaw * ( ( 180.0f - idMath::Fabs( mang.roll ) ) / 180.0f );
*/
player->SetViewAngles(newVA);
}
}

View file

@ -110,6 +110,11 @@ protected:
// results of last evaluate
idEntityPtr<idEntity> groundEntityPtr;
// HEXEN : Zeroth
protected:
bool IsStuckToSurface;
idVec3 SurfaceNormal;
};
#endif /* !__PHYSICS_ACTOR_H__ */

View file

@ -439,6 +439,16 @@ const idVec3 &idPhysics_Base::GetGravityNormal( void ) const {
return gravityNormal;
}
/*
================
Zeroth
idPhysics_Base::SetGravityNormal
================
*/
void idPhysics_Base::SetGravityNormal( idVec3 newNormal ) {
gravityNormal = newNormal;
}
/*
================
idPhysics_Base::ClipTranslation
@ -605,6 +615,23 @@ bool idPhysics_Base::HasGroundContacts( void ) const {
return false;
}
/*
================
HEXEN
idPhysics_Base::NumGroundContacts
================
*/
int idPhysics_Base::NumGroundContacts( void ) const {
int i, cnt = 0;
for ( i = 0; i < contacts.Num(); i++ ) {
if ( contacts[ i ].normal * -gravityNormal > 0.0f ) {
cnt++;
}
}
return cnt;
}
/*
================
idPhysics_Base::IsGroundEntity

View file

@ -108,6 +108,10 @@ public: // common physics interface
const idVec3 & GetGravity( void ) const;
const idVec3 & GetGravityNormal( void ) const;
// HEXEN : Zeroth
public:
void SetGravityNormal( idVec3 newNormal );
void ClipTranslation( trace_t &results, const idVec3 &translation, const idClipModel *model ) const;
void ClipRotation( trace_t &results, const idRotation &rotation, const idClipModel *model ) const;
int ClipContents( const idClipModel *model ) const;
@ -144,6 +148,10 @@ public: // common physics interface
void WriteToSnapshot( idBitMsgDelta &msg ) const;
void ReadFromSnapshot( const idBitMsgDelta &msg );
// HEXEN : Zeroth
public:
int NumGroundContacts( void ) const;
protected:
idEntity * self; // entity using this physics object
int clipMask; // contents the physics object collides with

View file

@ -509,6 +509,9 @@ bool idPhysics_Monster::Evaluate( int timeStepMSec, int endTimeMSec ) {
current.velocity += gravityVector * timeStep;
}
} else {
// HEXEN : Zeroth
// eoc_DoStuckOnSurface();
if ( useVelocityMove ) {
delta = current.velocity * timeStep;
} else {
@ -535,10 +538,11 @@ bool idPhysics_Monster::Evaluate( int timeStepMSec, int endTimeMSec ) {
current.velocity += current.pushVelocity;
current.pushVelocity.Zero();
if ( IsOutsideWorld() ) {
gameLocal.Warning( "clip model outside world bounds for entity '%s' at (%s)", self->name.c_str(), current.origin.ToString(0) );
Rest();
}
// HEXEN : Zeroth - sometimes this is okay
//if ( IsOutsideWorld() ) {
// gameLocal.Warning( "clip model outside world bounds for entity '%s' at (%s)", self->name.c_str(), current.origin.ToString(0) );
// Rest();
//}
return ( current.origin != oldOrigin );
}

View file

@ -464,7 +464,7 @@ void idPhysics_Player::Friction( void ) {
drop = 0;
// spectator friction
if ( current.movementType == PM_SPECTATOR ) {
if ( current.movementType == PM_SPECTATOR || current.movementType == PM_FLY ) {
drop += speed * PM_FLYFRICTION * frametime;
}
// apply ground friction
@ -599,6 +599,38 @@ void idPhysics_Player::FlyMove( void ) {
idPhysics_Player::SlideMove( false, false, false, false );
}
/*
===================
HEXEN
idPhysics_Player::FlyMoveWithCollision
===================
*/
void idPhysics_Player::FlyMoveWithCollision( void ) {
idVec3 wishvel;
float wishspeed;
idVec3 wishdir;
float scale;
// normal slowdown
idPhysics_Player::Friction();
scale = idPhysics_Player::CmdScale( command );
if ( !scale ) {
wishvel = vec3_origin;
} else {
wishvel = scale * (viewForward * command.forwardmove + viewRight * command.rightmove);
wishvel -= scale * gravityNormal * command.upmove;
}
wishdir = wishvel;
wishspeed = wishdir.Normalize();
idPhysics_Player::Accelerate( wishdir, wishspeed, PM_FLYACCELERATE );
idPhysics_Player::SlideMove( true, true, true, true );
}
/*
===================
idPhysics_Player::AirMove
@ -925,6 +957,83 @@ void idPhysics_Player::LadderMove( void ) {
idPhysics_Player::SlideMove( false, ( command.forwardmove > 0 ), false, false );
}
/*
=============
HEXEN
idPhysics_Player::StuckToSurfaceMove
=============
*/
void idPhysics_Player::StuckToSurfaceMove( void ) {
idVec3 wishdir, wishvel, right;
float wishspeed, scale;
float upscale;
// stick to the ladder
wishvel = -100.0f * SurfaceNormal;
current.velocity = ( gravityNormal * current.velocity ) * gravityNormal + wishvel;
upscale = ( -gravityNormal * viewForward + 0.5f ) * 2.5f;
if ( upscale > 1.0f ) {
upscale = 1.0f;
}
else if ( upscale < -1.0f ) {
upscale = -1.0f;
}
scale = idPhysics_Player::CmdScale( command );
wishvel = -0.9f * gravityNormal * upscale * scale * (float) command.forwardmove;
// strafe
if ( command.rightmove ) {
// right vector orthogonal to gravity
right = viewRight - ( gravityNormal * viewRight ) * gravityNormal;
// project right vector into ladder plane
right = right - ( SurfaceNormal * right ) * SurfaceNormal;
right.Normalize();
// if we are looking away from the ladder, reverse the right vector
if ( SurfaceNormal * viewForward > 0.0f ) {
right = -right;
}
wishvel += 2.0f * right * scale * (float) command.rightmove;
}
// up down movement
if ( command.upmove ) {
wishvel += -0.5f * gravityNormal * scale * (float) command.upmove;
}
// accelerate
wishspeed = wishvel.Normalize();
idPhysics_Player::Accelerate( wishvel, wishspeed, PM_ACCELERATE );
// cap the vertical velocity
upscale = current.velocity * -gravityNormal;
if ( upscale < -PM_LADDERSPEED ) {
current.velocity += gravityNormal * ( upscale + PM_LADDERSPEED );
}
else if ( upscale > PM_LADDERSPEED ) {
current.velocity += gravityNormal * ( upscale - PM_LADDERSPEED );
}
if ( (wishvel * gravityNormal) == 0.0f ) {
if ( current.velocity * gravityNormal < 0.0f ) {
current.velocity += gravityVector * frametime;
if ( current.velocity * gravityNormal > 0.0f ) {
current.velocity -= ( gravityNormal * current.velocity ) * gravityNormal;
}
}
else {
current.velocity -= gravityVector * frametime;
if ( current.velocity * gravityNormal < 0.0f ) {
current.velocity -= ( gravityNormal * current.velocity ) * gravityNormal;
}
}
}
idPhysics_Player::SlideMove( false, ( command.forwardmove > 0 ), false, false );
}
/*
=============
idPhysics_Player::CorrectAllSolid
@ -1311,12 +1420,52 @@ void idPhysics_Player::DropTimers( void ) {
}
}
/*
================
Zeroth
idPhysics_Player::EvalGravity
================
*/
void idPhysics_Player::EvalGravity( void ) {
const int transitions = 8;
const float transitionTime = 0.10f;
idVec3 curOrigin = clipModel->GetOrigin();
idVec3 curGrav = gravityVector;
float curTime = MS2SEC( gameLocal.realClientTime );
if ( TransitionToGravity != idVec3(0,0,0) && GetGravityNormal() != TransitionToGravity && nextTransition < curTime ) {
double gravAmount = sqrt( curGrav.x * curGrav.x + curGrav.y * curGrav.y + curGrav.z * curGrav.z );
idVec3 gravDir = TransitionToGravity * curTransition +
TransitionFromGravity * ( transitions - curTransition );
gravDir.Normalize();
idActor * owner = static_cast< idActor * >( masterEntity );
if (curTransition == transitions) {
SetGravity( TransitionToGravity * gravAmount );
TransitionToGravity.Zero();
nextTransition = 0;
} else {
SetGravity( gravDir * gravAmount );
curTransition++;
nextTransition = MS2SEC( gameLocal.realClientTime ) + ( transitionTime / transitions );
}
// flip viewAngles cuz ... things get screwey
// avoid getting stuck in wall
while ( groundPlane && !HasGroundContacts() ) { // we must have ground contacts at all times that we have a groundPlane, else we risk falling through floor
current.origin = current.origin - gravityNormal;
CheckGround();
}
}
}
/*
================
idPhysics_Player::MovePlayer
================
*/
void idPhysics_Player::MovePlayer( int msec ) {
EvalGravity(); //seems the best place to put this. MovePlayer seems to get called every single frame regardless of if player is actually moving.
// this counter lets us debug movement problems with a journal
// by setting a conditional breakpoint for the previous frame
@ -1363,6 +1512,13 @@ void idPhysics_Player::MovePlayer( int msec ) {
return;
}
// freemove
if ( current.movementType == PM_FLY ) {
FlyMoveWithCollision();
idPhysics_Player::DropTimers(); // 404
return;
}
// special no clip mode
if ( current.movementType == PM_NOCLIP ) {
idPhysics_Player::NoclipMove();
@ -1397,6 +1553,10 @@ void idPhysics_Player::MovePlayer( int msec ) {
// dead
idPhysics_Player::DeadMove();
}
else if ( StuckToSurface() ) { // HEXEN : Zeroth
DoStuckToSurface();
idPhysics_Player::StuckToSurfaceMove();
}
else if ( ladder ) {
// going up or down a ladder
idPhysics_Player::LadderMove();
@ -1422,6 +1582,23 @@ void idPhysics_Player::MovePlayer( int msec ) {
idPhysics_Player::SetWaterLevel();
idPhysics_Player::CheckGround();
// HEXEN : Zeroth - test if we should modify players gravity
//idPlayer *player = static_cast<idPlayer *>( masterEntity );
if ( self->gravityMod ) {
// grnd is not the ground the players feet are on, it's the surface directly below the player's origin
idVec3 myOrigin = GetOrigin();
float grndDist = 16;
trace_t grnd;
gameLocal.clip.TracePoint( grnd, myOrigin, myOrigin + GetGravityNormal() * grndDist, MASK_PLAYERSOLID, self );
if ( grnd.fraction < 1.0f && GetGravityNormal() != -grnd.c.normal && TransitionToGravity != -grnd.c.normal ) {
TransitionToGravity = -grnd.c.normal;
TransitionFromGravity = GetGravityNormal();
curTransition = 0;
}
}
// move the player velocity back into the world frame
current.velocity += current.pushVelocity;
current.pushVelocity.Zero();
@ -1520,6 +1697,9 @@ idPhysics_Player::idPhysics_Player( void ) {
ladderNormal.Zero();
waterLevel = WATERLEVEL_NONE;
waterType = 0;
IsStuckToSurface = false;
SurfaceNormal.Zero();
TransitionToGravity.Zero();
}
/*
@ -1753,9 +1933,10 @@ bool idPhysics_Player::Evaluate( int timeStepMSec, int endTimeMSec ) {
clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() );
if ( IsOutsideWorld() ) {
gameLocal.Warning( "clip model outside world bounds for entity '%s' at (%s)", self->name.c_str(), current.origin.ToString(0) );
}
// HEXEN : Zeroth - sometimes this is okay
//if ( IsOutsideWorld() ) {
// gameLocal.Warning( "clip model outside world bounds for entity '%s' at (%s)", self->name.c_str(), current.origin.ToString(0) );
//}
return true; //( current.origin != oldOrigin );
}
@ -2056,3 +2237,58 @@ void idPhysics_Player::ReadFromSnapshot( const idBitMsgDelta &msg ) {
clipModel->Link( gameLocal.clip, self, 0, current.origin, clipModel->GetAxis() );
}
}
/*
================
Zeroth
idPhysics_Player::StuckToSurface
================
*/
bool idPhysics_Player::StuckToSurface( void ) {
return IsStuckToSurface;
}
/*
================
Zeroth
idPhysics_Player::GetSurfaceNormal
================
*/
idVec3 idPhysics_Player::GetSurfaceNormal( void ) {
return SurfaceNormal;
}
/*
================
Zeroth
idPhysics_Player::SetSurfaceNormal
================
*/
void idPhysics_Player::SetSurfaceNormal( idVec3 newNormal ) {
SurfaceNormal = newNormal;
}
/*
================
Zeroth
idPhysics_Player::SetStuckToSurface
================
*/
void idPhysics_Player::SetStuckToSurface( bool yesOrNo ) {
IsStuckToSurface = yesOrNo;
}
/*
================
Zeroth
idPhysics_Player::DoStuckToSurface
Do all the math and junk to stick to a wall. This function should be called prior to moving an actor.
================
*/
void idPhysics_Player::DoStuckToSurface( void ) {
if ( StuckToSurface() ) {
idVec3 wishvel = -100.0f * SurfaceNormal;
current.velocity = ( gravityNormal * current.velocity ) * gravityNormal + wishvel;
}
}

View file

@ -49,6 +49,7 @@ typedef enum {
PM_SPECTATOR, // flying without gravity but with collision detection
PM_FREEZE, // stuck in place without control
PM_NOCLIP // flying without collision detection nor gravity
PM_FLY // flying without gravity but with collision detection
} pmtype_t;
typedef enum {
@ -100,6 +101,14 @@ public:
bool OnLadder( void ) const;
const idVec3 & PlayerGetOrigin( void ) const; // != GetOrigin
// HEXEN : Zeroth
public:
bool StuckToSurface( void );
void SetStuckToSurface( bool yesOrNo );
idVec3 GetSurfaceNormal( void );
void SetSurfaceNormal( idVec3 newNormal );
void DoStuckToSurface( void );
public: // common physics interface
bool Evaluate( int timeStepMSec, int endTimeMSec );
void UpdateTime( int endTimeMSec );
@ -177,6 +186,7 @@ private:
void WaterJumpMove( void );
void WaterMove( void );
void FlyMove( void );
void FlyMoveWithCollision( void );
void AirMove( void );
void WalkMove( void );
void DeadMove( void );
@ -192,6 +202,11 @@ private:
void SetWaterLevel( void );
void DropTimers( void );
void MovePlayer( int msec );
// HEXEN : Zeroth
private:
void EvalGravity( void );
void StuckToSurfaceMove( void );
};
#endif /* !__PHYSICS_PLAYER_H__ */

View file

@ -967,11 +967,12 @@ bool idPhysics_RigidBody::Evaluate( int timeStepMSec, int endTimeMSec ) {
current.externalForce.Zero();
current.externalTorque.Zero();
if ( IsOutsideWorld() ) {
gameLocal.Warning( "rigid body moved outside world bounds for entity '%s' type '%s' at (%s)",
self->name.c_str(), self->GetType()->classname, current.i.position.ToString(0) );
Rest();
}
// HEXEN : Zeroth - for some entities, it is okay to move outside world bounds. would be nice to have a "canMoveOutsideWorld" spawnArg
// if ( IsOutsideWorld() ) {
// gameLocal.Warning( "rigid body moved outside world bounds for entity '%s' type '%s' at (%s)",
// self->name.c_str(), self->GetType()->classname, current.i.position.ToString(0) );
// Rest();
// }
#ifdef RB_TIMINGS
timer_total.Stop();

View file

@ -1174,7 +1174,7 @@ float idPush::ClipTranslationalPush( trace_t &results, idEntity *pusher, const i
// if blocking entities should be crushed
if ( flags & PUSHFL_CRUSH ) {
check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, "damage_crush", 1.0f, CLIPMODEL_ID_TO_JOINT_HANDLE( pushResults.c.id ) );
check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, "damage_crush", 1.0f, CLIPMODEL_ID_TO_JOINT_HANDLE( pushResults.c.id ), pushResults.c.point );
continue;
}
@ -1344,7 +1344,7 @@ float idPush::ClipRotationalPush( trace_t &results, idEntity *pusher, const int
// if blocking entities should be crushed
if ( flags & PUSHFL_CRUSH ) {
check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, "damage_crush", 1.0f, CLIPMODEL_ID_TO_JOINT_HANDLE( pushResults.c.id ) );
check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, "damage_crush", 1.0f, CLIPMODEL_ID_TO_JOINT_HANDLE( pushResults.c.id ), pushResults.c.point );
continue;
}

View file

@ -0,0 +1,266 @@
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
const int FIREBEAM_METEOR_DELAY = 300; // in msec
const int FIREBEAM_METEOR_NUM = 8;
const int FIREBEAM_METEOR_SPEED = 400;
const int FIREBEAM_METOER_DISTT = 200; // distance between pairs in sky
const int FIREBEAM_METOER_DISTB = 75; // distance between pairs when reach firebeam
const int FIREBEAM_METEOR_HEIGHT = 200;
static const int BFG_DAMAGE_FREQUENCY = 333;
static const float BOUNCE_SOUND_MIN_VELOCITY = 200.0f;
static const float BOUNCE_SOUND_MAX_VELOCITY = 400.0f;
const idEventDef EV_LaunchFireBeam( "LaunchFireBeam", "vvvfff" );
/*************************************
zeroth
idProj_FireBeam
*************************************/
CLASS_DECLARATION( idProjectile, idProj_FireBeam )
EVENT( EV_LaunchFireBeam, idProj_FireBeam::Event_Launch )
END_CLASS
void idProj_FireBeam::Spawn( void ) {
}
void idProj_FireBeam::Think( void ) {
if ( state == 2 && meteorNum < FIREBEAM_METEOR_NUM ) {
idVec3 dir;
const idDict *boltDef;
idEntity *bolt;
idVec3 forw = GetPhysics()->GetLinearVelocity();
forw.Normalize();
dir.z = forw.z;
for ( int i=0; i<2; i++ ) {
if ( i == 0 ) {
// counter clockwise
dir.x = -forw.y;
dir.y = forw.x;
} else {
// clockwise
dir.x = forw.y;
dir.y = -forw.x;
}
boltDef = gameLocal.FindEntityDefDict( "projectile_firestorm_meteor" );
gameLocal.SpawnEntityDef( *boltDef, &bolt );
if ( !bolt ) {
return;
}
idProjectile *blt = static_cast< idProjectile * >(bolt);
idVec3 vec1 = GetPhysics()->GetOrigin() + dir * FIREBEAM_METOER_DISTT;
vec1.z += FIREBEAM_METEOR_HEIGHT;
blt->GetPhysics()->SetOrigin( vec1 );
idVec3 vec2 = GetPhysics()->GetOrigin() + dir * FIREBEAM_METOER_DISTB;
vec2 -= vec1;
vec2.Normalize();
//blt->SetAngles( vec2.ToAngles() );
//blt->GetPhysics()->SetLinearVelocity( vec2 * FIREBEAM_METEOR_SPEED );
blt->Launch( vec1, vec2, vec2 * FIREBEAM_METEOR_SPEED );
}
meteorNum++;
}
idProjectile::Think();
}
void idProj_FireBeam::Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire, const float launchPower, const float dmgPower ) {
idProjectile::Launch( start, dir, pushVelocity, timeSinceFire, launchPower, dmgPower);
}
void idProj_FireBeam::Event_Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire, const float launchPower, const float dmgPower ) {
idProjectile::Launch( start, dir, pushVelocity, timeSinceFire, launchPower, dmgPower );
}
/*************************************
zeroth
idProj_Incinerator
*************************************/
CLASS_DECLARATION( idProjectile, idProj_Incinerator )
END_CLASS
void idProj_Incinerator::Spawn( void ) {
ent = NULL;
}
void idProj_Incinerator::Incinerate( void ) {
particleEmitter_t pe;
//idStr particleName = "firestorm_incinerator";
idVec3 origin;
idMat3 axis;
// if there's no animator, just bind one flame to the entity where we impacted it
if ( !ent->GetAnimator() ) {/*
idEntity *flame;
const idDict *flameDef = gameLocal.FindEntityDefDict( "firestorm_incinerator_flame" );
gameLocal.SpawnEntityDef( *flameDef, &flame );
flame->GetPhysics()->SetOrigin( GetPhysics()->GetOrigin() );
flame->Bind(ent, 0);*/
return;
}
ent->onFire = gameLocal.time + 5000;
}
bool idProj_Incinerator::Collide( const trace_t &collision, const idVec3 &velocity ) {
idEntity *ignore;
const char *damageDefName;
idVec3 dir;
float push;
float damageScale;
if ( state == EXPLODED || state == FIZZLED ) {
return true;
}
// predict the explosion
if ( gameLocal.isClient ) {
if ( ClientPredictionCollide( this, spawnArgs, collision, velocity, !spawnArgs.GetBool( "net_instanthit" ) ) ) {
Explode( collision, NULL );
return true;
}
return false;
}
// remove projectile when a 'noimpact' surface is hit
if ( ( collision.c.material != NULL ) && ( collision.c.material->GetSurfaceFlags() & SURF_NOIMPACT ) ) {
PostEventMS( &EV_Remove, 0 );
common->DPrintf( "Projectile collision no impact\n" );
return true;
}
// get the entity the projectile collided with
ent = gameLocal.entities[ collision.c.entityNum ];
if ( ent == owner.GetEntity() ) {
assert( 0 );
return true;
}
// just get rid of the projectile when it hits a player in noclip
if ( ent->IsType( idPlayer::Type ) && static_cast<idPlayer *>( ent )->noclip ) {
PostEventMS( &EV_Remove, 0 );
return true;
}
// direction of projectile
dir = velocity;
dir.Normalize();
// projectiles can apply an additional impulse next to the rigid body physics impulse
if ( spawnArgs.GetFloat( "push", "0", push ) && push > 0.0f ) {
ent->ApplyImpulse( this, collision.c.id, collision.c.point, push * dir );
}
// MP: projectiles open doors
if ( gameLocal.isMultiplayer && ent->IsType( idDoor::Type ) && !static_cast< idDoor * >(ent)->IsOpen() && !ent->spawnArgs.GetBool( "no_touch" ) ) {
ent->ProcessEvent( &EV_Activate , this );
}
if ( ent->IsType( idActor::Type ) || ( ent->IsType( idAFAttachment::Type ) && static_cast<const idAFAttachment*>(ent)->GetBody()->IsType( idActor::Type ) ) ) {
if ( !projectileFlags.detonate_on_actor ) {
return false;
}
} else {
if ( !projectileFlags.detonate_on_world ) {
if ( !StartSound( "snd_ricochet", SND_CHANNEL_ITEM, 0, true, NULL ) ) {
float len = velocity.Length();
if ( len > BOUNCE_SOUND_MIN_VELOCITY ) {
SetSoundVolume( len > BOUNCE_SOUND_MAX_VELOCITY ? 1.0f : idMath::Sqrt( len - BOUNCE_SOUND_MIN_VELOCITY ) * ( 1.0f / idMath::Sqrt( BOUNCE_SOUND_MAX_VELOCITY - BOUNCE_SOUND_MIN_VELOCITY ) ) );
StartSound( "snd_bounce", SND_CHANNEL_ANY, 0, true, NULL );
}
}
return false;
}
}
SetOrigin( collision.endpos );
SetAxis( collision.endAxis );
// unlink the clip model because we no longer need it
GetPhysics()->UnlinkClip();
damageDefName = spawnArgs.GetString( "def_damage" );
ignore = NULL;
// if the hit entity takes damage
if ( ent->fl.takedamage ) {
if ( damagePower ) {
damageScale = damagePower;
} else {
damageScale = 1.0f;
}
// if the projectile owner is a player
if ( owner.GetEntity() && owner.GetEntity()->IsType( idPlayer::Type ) ) {
// if the projectile hit an actor
if ( ent->IsType( idActor::Type ) ) {
idPlayer *player = static_cast<idPlayer *>( owner.GetEntity() );
player->AddProjectileHits( 1 );
damageScale *= player->PowerUpModifier( PROJECTILE_DAMAGE );
}
}
if ( damageDefName[0] != '\0' ) {
ent->Damage( this, owner.GetEntity(), dir, damageDefName, damageScale, CLIPMODEL_ID_TO_JOINT_HANDLE( collision.c.id ), idVec3( collision.c.point ) );
ignore = ent;
}
}
// if the projectile causes a damage effect
if ( spawnArgs.GetBool( "impact_damage_effect" ) ) {
// if the hit entity has a special damage effect
if ( ent->spawnArgs.GetBool( "bleed" ) ) {
ent->AddDamageEffect( collision, velocity, damageDefName );
} else {
AddDefaultDamageEffect( collision, velocity );
}
}
Explode( collision, ignore );
Incinerate();
return true;
}
/*************************************
zeroth
idProj_IncineratorFlame
*************************************/
CLASS_DECLARATION( idEntity, idProj_IncineratorFlame )
END_CLASS
void idProj_IncineratorFlame::Spawn() {
PostEventMS( &EV_Remove, gameLocal.random.RandomFloat() * 1000 + 4000 );
}

View file

@ -0,0 +1,41 @@
#ifndef __AI_FIRESTORM_H__
#define __AI_FIRESTORM_H__
// one flame to go on one joint. idProj_Incinerator creates these entities.
class idProj_IncineratorFlame : public idEntity {
public:
CLASS_PROTOTYPE( idProj_IncineratorFlame );
void Spawn( void );
};
// base class for projetiles that incinerate things
class idProj_Incinerator : public idProjectile {
public:
CLASS_PROTOTYPE( idProj_Incinerator );
void Spawn( void );
void Incinerate( void );
bool Collide( const trace_t &collision, const idVec3 &velocity );
private:
bool incinerate;
idEntity * ent;
};
class idProj_FireBeam : public idProj_Incinerator {
public:
CLASS_PROTOTYPE( idProj_FireBeam );
void Think( void );
void Spawn( void );
void Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire = 0.0f, const float launchPower = 1.0f, const float dmgPower = 1.0f );
private:
float gravTime;
private:
int meteorNum;
private:
void Event_Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire, const float launchPower, const float dmgPower );
};
#endif // __AI_FIRESTORM_H__

44
game/projectiles/Soul.cpp Normal file
View file

@ -0,0 +1,44 @@
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
const float SOUL_SPEED = 1000.0f;
CLASS_DECLARATION( idProjectile, idProj_Soul )
END_CLASS
void idProj_Soul::init() {
dieTime = 2000 + gameLocal.time;
// spawn the effect around the wraith model
idDict effectArgs;
effectArgs.Set( "classname", "blank_item" );
effectArgs.Set("model", spawnArgs.GetString("def_projectile"));
effectArgs.SetVector("origin", GetPhysics()->GetOrigin());
effectArgs.SetBool("nonsolid", true);
effectArgs.SetBool("nocollide", true);
gameLocal.SpawnEntityDef(effectArgs, &effect, true);
effect->Bind(this, true);
GetPhysics()->SetGravity( idVec3(0,0,0.000001f) );
rnd = gameLocal.random.RandomInt(360);
}
void idProj_Soul::Think() {
idProjectile::Think();
if ( gameLocal.time >= dieTime ) {
PostEventMS( &EV_Remove, 0.0 );
}
ang.yaw = (( gameLocal.time / 1000 ) * 360) + rnd;
dir = ang.ToForward(); dir.Normalize();
dir = dir + idVec3(0,0,0.66f); dir.Normalize();
SetAngles( ang );
GetPhysics()->SetLinearVelocity(SOUL_SPEED * dir);
}

18
game/projectiles/Soul.h Normal file
View file

@ -0,0 +1,18 @@
#ifndef __AI_SOUL_H__
#define __AI_SOUL_H__
class idProj_Soul : public idProjectile {
public:
CLASS_PROTOTYPE( idProj_Soul );
void init( void );
void Think( void );
private:
idEntity *effect;
idVec3 dir;
float dieTime;
idAngles ang;
float rnd;
};
#endif // __AI_SOUL_H__

View file

@ -0,0 +1,366 @@
#include "../../idlib/precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
const int PROJ_WRAITH_CHASE_RANGE = 768;
const int PROJ_WRAITH_SPAWN_DELAY = 400;
const int PROJ_WRAITH_NUM = 2;
const int PROJ_WRAITH_NUM_TOME = 2;
const int PROJ_WRAITH_CHECK_DELAY = 300;
CLASS_DECLARATION( idProjectile, idProj_Wraith )
END_CLASS
void idProj_Wraith::Spawn( void ) {
tome = false;
if ( spawnArgs.GetBool("tome") ) { // if ( owner.GetEntity() && owner.GetEntity()->IsType( idPlayer::Type ) && ( static_cast< idPlayer * >( owner.GetEntity() )->GetPowerTome() ) ) {
tome = true;
spawnArgs.Set( "def_damage", "damage_wraithverge_tome" );
}
}
void idProj_Wraith::Think( void ) {
if ( wraithSpun == true ) {
//gameLocal.entities[this->entityNumber] = NULL;
PostEventSec( &EV_Explode, 0.0f );
return;
}
idProjectile::Think();
/* current projectile doesnt need spinning, turning this off
// do spinning
ang = forw.ToAngles();
ang.roll = gameLocal.time * 360;
SetAngles( ang );
*/
// delay until spawn new wraiths
if ( gameLocal.time >= spinTime ) {
if ( tome ) {
wraithSpun = true;
SpawnSubWraiths( PROJ_WRAITH_NUM_TOME );
} else {
wraithSpun = true;
SpawnSubWraiths( PROJ_WRAITH_NUM );
}
}
}
void idProj_Wraith::Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire, const float launchPower, const float dmgPower ) {
forw = dir;
wraithInitialized=false;
wraithSpun = false;
spinTime = gameLocal.time + PROJ_WRAITH_SPAWN_DELAY;
#if 0
// this was used when we had an actual shadowspawn model for the projectile
// spawn the effect around the wraith model
spawnArgs.Set("model", spawnArgs.GetString("def_projectile"));
spawnArgs.SetVector("origin", GetPhysics()->GetOrigin());
spawnArgs.Set("nonsolid", "1");
spawnArgs.Set("nocollide", "1");
const idDict *blank = gameLocal.FindEntityDefDict("blank_item");
effect = gameLocal.SpawnEntityType( idEntity::Type, blank );
effect->Bind( this, 1 );
#endif
idProjectile::Launch( start, dir, pushVelocity, timeSinceFire, launchPower, dmgPower );
}
void idProj_Wraith::SpawnSubWraiths( int num ) {
idProj_HomingWraith *newWraith = NULL;
idEntity *ent = NULL;
idVec3 rnd;
idVec3 dir2;
float rndf=0;
idDict newWraithDict;
if ( tome ) {
newWraithDict.Set( "classname", "projectile_HomingWraith_Tome" );
} else {
newWraithDict.Set( "classname", "projectile_HomingWraith" );
}
rnd.z = 0;
// spawn some wraiths
for (int i=0; i < num; i++) {
// alternate left & right
if ( rndf > 0 ) {
rndf = -1;
// perpendicular vector counterclockwise
rnd.x = -forw.y;
rnd.y = forw.x;
} else {
// perpendicular vector clockwise
rndf = 1;
rnd.x = forw.y;
rnd.y = -forw.x;
}
dir2.Set(forw.x, forw.y, 0);
dir2.Normalize();
float cval = gameLocal.random.RandomFloat();
dir2 = ( dir2 * cval ) + ( rnd * ( 1 - cval ) );
dir2.Normalize();
newWraithDict.SetAngles( "wraithAngles", dir2.ToAngles() );
newWraithDict.SetVector( "wraithVelocity", defVel * dir2 );
newWraithDict.SetVector( "wraithOrigin", GetPhysics()->GetOrigin() );
newWraithDict.SetVector( "wraithDir", dir2 );
newWraithDict.SetBool( "wraithTome", tome );
gameLocal.SpawnEntityDef( newWraithDict, &ent );
if ( !ent ) {
return;
}
newWraith = static_cast< idProj_HomingWraith* >( ent );
}
}
/*************************************************************************
Homing Wraith
*************************************************************************/
CLASS_DECLARATION( idProjectile, idProj_HomingWraith )
END_CLASS
void idProj_HomingWraith::Spawn( void ) {
GetPhysics()->SetLinearVelocity( spawnArgs.GetVector( "wraithVelocity" ) );
GetPhysics()->SetGravity( idVec3(0, 0, 0.000001f ) ); // grav can't be zero. //z.todo: try this in def
GetPhysics()->SetOrigin( spawnArgs.GetVector( "wraithOrigin" ) );
SetAngles( spawnArgs.GetAngles( "wraithAngles" ) );
target = NULL;
tome = spawnArgs.GetBool( "wraithTome" );
dir = spawnArgs.GetVector( "wraithDir" );
defVel = spawnArgs.GetFloat("velocity");
dieTime = SEC2MS( spawnArgs.GetFloat("fuse") ) + gameLocal.time; // not working???
nextSearch = 0;
hits = 0;
}
void idProj_HomingWraith::Think() {
if ( state == EXPLODED ) {
return;
}
if ( target ) {
// move to the head of the enemy, not the origin (feet)
targOrigin = target->GetPhysics()->GetOrigin();
targOrigin.z = targOrigin.z + ( targSize.z );
dir = targOrigin -GetPhysics()->GetOrigin();
if ( dir.Length() < 10 ) { // target distance
//z.todo startSound("snd_explode", SND_CHANNEL_ANY, false );
// target->GetPhysics()->SetLinearVelocity(target->GetPhysics()->GetLinearVelocity() + dir * 150 ); // push
//radiusDamage(target->GetPhysics()->GetOrigin()(), this, this, this, "damage_wraithverge", 1); // damage //Z.TODO: make player the attacker
DirectDamage( spawnArgs.GetString("def_damage"), target );
target->spawnArgs.Set("wraithChased", "0");
//get off this target, keep flying for a bit, and find a new one
target = NULL;
if ( tome ) {
nextSearch = gameLocal.time + ( PROJ_WRAITH_CHECK_DELAY / 3 );
} else {
nextSearch = gameLocal.time + ( PROJ_WRAITH_CHECK_DELAY );
}
}
dir.Normalize();
} else {
if ( gameLocal.time > dieTime ) {
//gameLocal.entities[this->entityNumber] = NULL;
PostEventSec( &EV_Explode, 0.0f );
}
if ( gameLocal.time > nextSearch ) {
findTarget();
nextSearch = gameLocal.time + 500 + 250 * gameLocal.random.RandomFloat(); // we don't want to search every frame, that will get real expensive.
if ( target ) {
targSize = target->spawnArgs.GetVector("size");
}
}
}
GetPhysics()->SetLinearVelocity(defVel * dir); // chase target, apply velocity here, this way we maintain speed each frameall the time (it likes to slow down)
SetAngles( dir.ToAngles() );
idProjectile::Think();
}
void idProj_HomingWraith::DirectDamage( const char *meleeDefName, idEntity *ent ) {
const idDict *meleeDef;
const char *p;
const idSoundShader *shader;
meleeDef = gameLocal.FindEntityDefDict( meleeDefName, false );
if ( !meleeDef ) {
gameLocal.Error( "Unknown damage def '%s' on '%s'", meleeDefName, name.c_str() );
}
if ( !ent->fl.takedamage ) {
const idSoundShader *shader = declManager->FindSound(meleeDef->GetString( "snd_miss" ));
StartSoundShader( shader, SND_CHANNEL_DAMAGE, 0, false, NULL );
return;
}
//
// do the damage
//
p = meleeDef->GetString( "snd_hit" );
if ( p && *p ) {
shader = declManager->FindSound( p );
StartSoundShader( shader, SND_CHANNEL_DAMAGE, 0, false, NULL );
}
ent->Damage( this, this, idVec3(0,0,0), meleeDefName, 1.0f, INVALID_JOINT, idVec3(0,0,0) );
hits++;
if ( tome && hits >= 4) {
target->spawnArgs.Set("wraithChased", "0");
Explode( owner.GetEntity() );
}
}
void idProj_HomingWraith::Explode( idEntity *ignore ) {
trace_t collision;
memset( &collision, 0, sizeof( collision ) );
collision.endAxis = GetPhysics()->GetAxis();
collision.endpos = GetPhysics()->GetOrigin();
collision.c.point = GetPhysics()->GetOrigin();
collision.c.normal.Set( 0, 0, 1 );
AddDefaultDamageEffect( collision, collision.c.normal );
idProjectile::Explode( collision, ignore );
}
void idProj_HomingWraith::findTarget() {
int hash, i, j;
const char *cname=NULL;
for ( j=0; j<3; j++ ) {
switch (j) {
case 0:
cname = idAI::Type.classname;
break;
case 1:
cname = idAI_Golem::Type.classname;
break;
case 2:
cname = idAI_Veloxite::Type.classname;
break;/*
case 3:
cname = idAI_Shadowspawn::Type.classname;
break;*/
default:
cname = idAI::Type.classname;
break;
}
hash = gameLocal.entypeHash.GenerateKey( cname, true );
for ( i = gameLocal.entypeHash.First( hash ); i != -1; i = gameLocal.entypeHash.Next( i ) ) {
if ( gameLocal.entities[i] && !strcmp(gameLocal.entities[i]->GetClassname(), cname ) ) {
target = static_cast< idAI* >( gameLocal.entities[i] );
if ( target->IsHidden() ) {
continue;
}
if ( target->health <= 0 ) {
continue;
}
if ( target->spawnArgs.GetFloat("wraithChased") ) {
continue;
}
// check distance
if ( idVec3( gameLocal.entities[i]->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin() ).Length() > 768 /* wraith chase range */ ) {
continue;
}
target->spawnArgs.Set("wraithChased", "1");
return;
}
}
}
target = NULL;
}
#if 0
/*************************************************************************
Pulling Wraith
*************************************************************************/
// pulling wraith was a neat idea, but wraiths come out of the wraithverge. let's stick to the story here...
void proj_PullingWraith::Think() {
startSound("snd_split", SND_CHANNEL_ANY, false );
findTarget();
if (! (!target)) {
targSize = target->spawnArgs.GetVector("size");
SetOrigin(target->GetPhysics()->GetOrigin() - idVec3(0, 0, 125);
while (1) {
// move to the head of the enemy, not the origin (feet)
targOrigin = target->GetPhysics()->GetOrigin();
targOrigin.z = targOrigin.z + ( targSize.z );
dir = targOrigin -GetPhysics()->GetOrigin();
targetDist = dir.Length();
if (targetDist < 10) { // drag enemy down
startSound("snd_explode", SND_CHANNEL_ANY, false );
//target->bind(this);
dieTime = gameLocal.time + 2;
defVel = defVel * 0.5;
target->becomeRagdoll();
while (gameLocal.time < dieTime) {
target->GetPhysics()->SetOrigin()(GetPhysics()->GetOrigin());
GetPhysics()->SetLinearVelocity(defVel * idVec3(0, 0, -1) );
waitFrame();
}
target->Set("wraithChased", "0");
target->remove();
break;
}
dir = sys.vecNormalize(dir);
GetPhysics()->SetLinearVelocity(defVel * dir); // chase target
GetPhysics()->SetAngles(sys.VecToAngles(dir));
waitFrame();
}
}
}
#endif

View file

@ -0,0 +1,64 @@
#ifndef __AI_WRAITHVERGE_H__
#define __AI_WRAITHVERGE_H__
/*************************************************************************
WraithVerge Projectile (spawns other wraith types)
*************************************************************************/
class idProj_Wraith : public idProjectile {
public:
CLASS_PROTOTYPE( idProj_Wraith );
void Think( void );
void Spawn( void );
void Launch( const idVec3 &start, const idVec3 &dir, const idVec3 &pushVelocity, const float timeSinceFire = 0.0f, const float launchPower = 1.0f, const float dmgPower = 1.0f );
private:
void SpawnSubWraiths( int num );
private:
bool tome;
bool wraithSpun;
idVec3 forw;
float defVel;
float dieTime;
bool wraithInitialized;
float spinTime;
idAngles ang;
};
class idProj_HomingWraith : public idProjectile {
public:
CLASS_PROTOTYPE( idProj_HomingWraith );
private:
void Think( void );
void Explode( idEntity *ignore );
void Spawn( void );
void DirectDamage( const char *meleeDefName, idEntity *ent );
public:
bool ready;
private:
void findTarget();
void homingWraith();
void pullingWraith();
private:
float gravTime;
idVec3 dir;
float defVel;
int dieTime;
bool tome;
idAI *target;
idVec3 targOrigin;
idVec3 targSize;
float nextSearch;
float nextWallCollideCheck;
int hits;
};
#endif // __AI_WRAITHVERGE_H__

View file

@ -673,6 +673,7 @@ void idInterpreter::LeaveFunction( idVarDef *returnDef ) {
// all done
doneProcessing = true;
threadDying = true;
//stackEmpty = true; // HEXEN : Zeroth
currentFunction = 0;
}
}

View file

@ -64,6 +64,8 @@ const idEventDef EV_Thread_SpawnFloat( "SpawnFloat", "sf", 'f' );
const idEventDef EV_Thread_SpawnVector( "SpawnVector", "sv", 'v' );
const idEventDef EV_Thread_ClearPersistantArgs( "clearPersistantArgs" );
const idEventDef EV_Thread_SetPersistantArg( "setPersistantArg", "ss" );
const idEventDef EV_Thread_SetPersistantMapArg( "setPersistantMapArg", "ss" );
const idEventDef EV_Thread_GetPersistantMapFloat( "getPersistantMapFloat", "ss", 'f' );
const idEventDef EV_Thread_GetPersistantString( "getPersistantString", "s", 's' );
const idEventDef EV_Thread_GetPersistantFloat( "getPersistantFloat", "s", 'f' );
const idEventDef EV_Thread_GetPersistantVector( "getPersistantVector", "s", 'v' );
@ -113,6 +115,17 @@ const idEventDef EV_Thread_DebugCircle( "debugCircle", "vvvfdf" );
const idEventDef EV_Thread_DebugBounds( "debugBounds", "vvvf" );
const idEventDef EV_Thread_DrawText( "drawText", "svfvdf" );
const idEventDef EV_Thread_InfluenceActive( "influenceActive", NULL, 'd' );
// HEXEN : Zeroth
//const idEventDef EV_Thread_SoundMute( "SoundMute", "f" );
const idEventDef EV_Thread_ASin( "ASin", "f", 'f' );
const idEventDef EV_Thread_ACos( "ACos", "f", 'f' );
const idEventDef EV_Thread_ATan( "ATan", "f", 'f' );
const idEventDef EV_Thread_GetRandomBanishLocation( "GetRandomBanishLocation", NULL, 'v' );
const idEventDef EV_Thread_GetEntityNum( "GetEntityNum", "e", 'f' );
const idEventDef EV_Thread_GetEntityNumFromName( "GetEntityNumFromName", "s", 'f' );
const idEventDef EV_Thread_TraceSurfaceNormal( "TraceSurfaceNormal", "vvfe", 'v' );
const idEventDef EV_Thread_GetWorldGravity( "GetWorldGravity", NULL, 'v' );
const idEventDef EV_Thread_SpawnParticle( "spawnParticle", "sv" );
CLASS_DECLARATION( idClass, idThread )
EVENT( EV_Thread_Execute, idThread::Event_Execute )
@ -142,6 +155,8 @@ CLASS_DECLARATION( idClass, idThread )
EVENT( EV_Thread_SpawnVector, idThread::Event_SpawnVector )
EVENT( EV_Thread_ClearPersistantArgs, idThread::Event_ClearPersistantArgs )
EVENT( EV_Thread_SetPersistantArg, idThread::Event_SetPersistantArg )
EVENT( EV_Thread_SetPersistantMapArg, idThread::Event_SetPersistantMapArg )
EVENT( EV_Thread_GetPersistantMapFloat, idThread::Event_GetPersistantMapFloat )
EVENT( EV_Thread_GetPersistantString, idThread::Event_GetPersistantString )
EVENT( EV_Thread_GetPersistantFloat, idThread::Event_GetPersistantFloat )
EVENT( EV_Thread_GetPersistantVector, idThread::Event_GetPersistantVector )
@ -193,6 +208,17 @@ CLASS_DECLARATION( idClass, idThread )
EVENT( EV_Thread_DebugBounds, idThread::Event_DebugBounds )
EVENT( EV_Thread_DrawText, idThread::Event_DrawText )
EVENT( EV_Thread_InfluenceActive, idThread::Event_InfluenceActive )
// HEXEN : Zeroth
// EVENT( EV_Thread_SoundMute, idThread::Event_SoundMute )
EVENT( EV_Thread_ASin, idThread::Event_ASin )
EVENT( EV_Thread_ACos, idThread::Event_ACos )
EVENT( EV_Thread_ATan, idThread::Event_ATan )
EVENT( EV_Thread_GetRandomBanishLocation, idThread::Event_GetRandomBanishLocation )
EVENT( EV_Thread_GetEntityNum, idThread::Event_GetEntityNum )
EVENT( EV_Thread_GetEntityNumFromName, idThread::Event_GetEntityNumFromName )
EVENT( EV_Thread_TraceSurfaceNormal, idThread::Event_TraceSurfaceNormal )
EVENT( EV_Thread_GetWorldGravity, idThread::Event_GetWorldGravity )
EVENT( EV_Thread_SpawnParticle, idThread::Event_SpawnParticle )
END_CLASS
idThread *idThread::currentThread = NULL;
@ -558,6 +584,22 @@ bool idThread::Start( void ) {
return result;
}
#if 0
/*
================
HEXEN
idThread::Event_SoundMute
================
*/
void idThread::Event_SoundMute( float yesorno ) {
if ( yesorno ) {
soundSystem->SetMute( true );
} else {
soundSystem->SetMute( false );
}
}
#endif
/*
================
idThread::SetThreadName
@ -1125,6 +1167,23 @@ void idThread::Event_Spawn( const char *classname ) {
spawnArgs.Clear();
}
/*
================
Zeroth
idThread::Event_SpawnParticle
================
*/
void idThread::Event_SpawnParticle( const char *particleName, const idVec3 &origin ) {
const idDecl *dec;
dec = declManager->FindType( DECL_PARTICLE, particleName );
if ( !dec ) {
return;
}
//gameLocal.smokeParticles->EmitSmoke( static_cast<const idDeclParticle *>( dec ), gameLocal.time+1, gameLocal.random.CRandomFloat(), origin, idMat3() );
gameLocal.smokeParticles->EmitSmoke( static_cast<const idDeclParticle *>( dec ), gameLocal.time, gameLocal.random.RandomFloat(), origin, idMat3( 1, 0, 0, 0, 0, 0, 0, 0, 0 ) );
}
/*
================
idThread::Event_CopySpawnArgs
@ -1198,6 +1257,39 @@ void idThread::Event_SetPersistantArg( const char *key, const char *value ) {
gameLocal.persistentLevelInfo.Set( key, value );
}
/*
================
HEXEN
idThread::Event_SetPersistantMapArg
================
*/
void idThread::Event_SetPersistantMapArg( const char *key, const char *value ) {
idStr name_str;
name_str = gameLocal.GetMapName();
name_str += "_";
name_str += key;
gameLocal.persistentLevelInfo.Set( name_str, value );
}
/*
================
HEXEN
idThread::Event_GetPersistantMapFloat
================
*/
void idThread::Event_GetPersistantMapFloat( const char *key, const char *defaultvalue ) {
float result;
idStr name_str;
name_str = gameLocal.GetMapName();
name_str += "_";
name_str += key;
gameLocal.persistentLevelInfo.GetFloat( name_str, defaultvalue, result );
ReturnFloat( result );
}
/*
================
idThread::Event_GetPersistantString
@ -1841,3 +1933,119 @@ void idThread::Event_InfluenceActive( void ) {
idThread::ReturnInt( false );
}
}
/*
================
Zeroth
idThread::Event_ASin
================
*/
void idThread::Event_ASin( const float angle ) {
ReturnFloat( idMath::ASin( angle ) );
}
/*
================
Zeroth
idThread::Event_ACos
================
*/
void idThread::Event_ACos( const float angle ) {
ReturnFloat( idMath::ACos( angle ) );
}
/*
================
Zeroth
idThread::Event_ATan
================
*/
void idThread::Event_ATan( const float angle ) {
gameLocal.Printf( "RETURNING: %f from %f\n", atan( angle ), angle );
ReturnFloat( atan( angle ) );
}
/*
================
Zeroth
idThread::Event_GetRandomBanishLocation
================
*/
void idThread::Event_GetRandomBanishLocation( void ) {
int i;
if ( gameLocal.BanishLocationList.Num() < 1 ) {
gameLocal.Error( "There are no Banish Locations\n." );
idThread::ReturnVector( idVec3() );
return;
}
i = gameLocal.random.RandomInt( gameLocal.BanishLocationList.Num() );
idThread::ReturnVector( *gameLocal.BanishLocationList[i] );
}
/*
================
Zeroth
idThread::Event_GetEntityNum
================
*/
void idThread::Event_GetEntityNum( const idEntity *ent1 ) {
if ( ent1 ) {
idThread::ReturnFloat( ent1->entityNumber );
} else {
idThread::ReturnFloat( -1 );
}
}
/*
================
Zeroth
idThread::Event_GetEntityNumFromName
================
*/
void idThread::Event_GetEntityNumFromName( const idStr entName ) {
for ( int i = 0; i < MAX_GENTITIES; i++ ) {
idEntity *ent = gameLocal.entities[i];
if ( ent && !idStr::Cmp( ent->name, entName ) ) {
idThread::ReturnFloat( i );
return;
}
}
idThread::ReturnFloat( -1 );
return;
}
/*
================
Zeroth
idThread::Event_TraceSurfaceNormal
================
*/
void idThread::Event_TraceSurfaceNormal( const idVec3 &A, const idVec3 &B, const float clipMask, const idEntity *pass ) {
trace_t trace;
idEntity *ent;
gameLocal.clip.TracePoint( trace, A, B, MASK_PLAYERSOLID, pass );
// if near a surface
if ( trace.fraction < 1.0f ) {
idVec3 bub = trace.c.normal;
ent = gameLocal.GetTraceEntity( trace );
idThread::ReturnVector( trace.c.normal );
} else {
idThread::ReturnVector( idVec3( 0, 0, 0 ) );
}
}
/*
================
Zeroth
idThread::Event_GetWorldGravity
================
*/
void idThread::Event_GetWorldGravity( void ) {
idThread::ReturnVector( gameLocal.GetGravity() );
}

View file

@ -136,6 +136,8 @@ private:
void Event_SpawnVector( const char *key, idVec3 &defaultvalue );
void Event_ClearPersistantArgs( void );
void Event_SetPersistantArg( const char *key, const char *value );
void Event_SetPersistantMapArg( const char *key, const char *value );
void Event_GetPersistantMapFloat( const char *key, const char *defaultvalue );
void Event_GetPersistantString( const char *key );
void Event_GetPersistantFloat( const char *key );
void Event_GetPersistantVector( const char *key );
@ -188,6 +190,19 @@ private:
void Event_DrawText( const char *text, const idVec3 &origin, float scale, const idVec3 &color, const int align, const float lifetime );
void Event_InfluenceActive( void );
// HEXEN : Zeroth
private:
// void Event_SoundMute( float yesorno );
void Event_ASin( const float angle );
void Event_ACos( const float angle );
void Event_ATan( const float angle );
void Event_GetRandomBanishLocation( void );
void Event_GetEntityNum( const idEntity *ent );
void Event_GetEntityNumFromName( const idStr entName );
void Event_TraceSurfaceNormal( const idVec3 &A, const idVec3 &B, const float clipMask, const idEntity *pass );
void Event_GetWorldGravity( void );
void Event_SpawnParticle( const char *particleName, const idVec3 &origin );
public:
CLASS_PROTOTYPE( idThread );
@ -228,6 +243,7 @@ public:
static idList<idThread*>& GetThreads ( void );
bool IsDoneProcessing ( void );
//bool IsBusy( void ); // HEXEN : Zeroth - this will be true if the script is in a function - whether paused or not.
bool IsDying ( void );
void End( void );
@ -321,6 +337,22 @@ ID_INLINE bool idThread::IsDoneProcessing ( void ) {
return interpreter.doneProcessing;
}
#if 0
/*
================
Zeroth
idThread::IsBusy
================
*/
ID_INLINE bool idThread::IsBusy ( void ) {
if ( interpreter.GetCallstackDepth() == 0 ) {
return false;
} else {
return true;
}
}
#endif
/*
================
idThread::IsDying