mirror of
https://github.com/dhewm/dhewm3-sdk.git
synced 2025-04-22 09:10:57 +00:00
Convert the new added files from CRLF into LF and add modified source code in game directory (final part)
This commit is contained in:
parent
0e0bdc0ac8
commit
b1176b99fb
38 changed files with 3680 additions and 1966 deletions
File diff suppressed because it is too large
Load diff
|
@ -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" );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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_
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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__
|
||||
|
|
15
game/objects/ChaosDeviceModel.cpp
Normal file
15
game/objects/ChaosDeviceModel.cpp
Normal 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();
|
||||
}
|
14
game/objects/ChaosDeviceModel.h
Normal file
14
game/objects/ChaosDeviceModel.h
Normal 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
85
game/objects/Leaf.cpp
Normal 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
29
game/objects/Leaf.h
Normal 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__
|
42
game/objects/LeafEmitter.cpp
Normal file
42
game/objects/LeafEmitter.cpp
Normal 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;
|
||||
}
|
||||
}
|
17
game/objects/LeafEmitter.h
Normal file
17
game/objects/LeafEmitter.h
Normal 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
77
game/objects/Tree.cpp
Normal 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
31
game/objects/Tree.h
Normal 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__
|
|
@ -1670,3 +1670,13 @@ bool idClip::DrawModelContactFeature( const contactInfo_t &contact, const idClip
|
|||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
============
|
||||
Zeroth
|
||||
idClipModel::GetRenderModelHandle
|
||||
============
|
||||
*/
|
||||
int idClipModel::GetRenderModelHandle( void ) {
|
||||
return renderModelHandle;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -110,6 +110,11 @@ protected:
|
|||
|
||||
// results of last evaluate
|
||||
idEntityPtr<idEntity> groundEntityPtr;
|
||||
|
||||
// HEXEN : Zeroth
|
||||
protected:
|
||||
bool IsStuckToSurface;
|
||||
idVec3 SurfaceNormal;
|
||||
};
|
||||
|
||||
#endif /* !__PHYSICS_ACTOR_H__ */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
266
game/projectiles/FireStorm.cpp
Normal file
266
game/projectiles/FireStorm.cpp
Normal 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 );
|
||||
}
|
41
game/projectiles/FireStorm.h
Normal file
41
game/projectiles/FireStorm.h
Normal 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
44
game/projectiles/Soul.cpp
Normal 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
18
game/projectiles/Soul.h
Normal 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__
|
366
game/projectiles/Wraithverge.cpp
Normal file
366
game/projectiles/Wraithverge.cpp
Normal 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
|
64
game/projectiles/Wraithverge.h
Normal file
64
game/projectiles/Wraithverge.h
Normal 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__
|
|
@ -673,6 +673,7 @@ void idInterpreter::LeaveFunction( idVarDef *returnDef ) {
|
|||
// all done
|
||||
doneProcessing = true;
|
||||
threadDying = true;
|
||||
//stackEmpty = true; // HEXEN : Zeroth
|
||||
currentFunction = 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue