Switched Doom 3 weapons to native.

This commit is contained in:
Justin Marshall
2026-05-19 08:28:43 -07:00
parent b841fcb33b
commit b97127f038
82 changed files with 20023 additions and 1371 deletions
+14 -1
View File
@@ -2174,7 +2174,20 @@ void idActor::Damage( idEntity *inflictor, idEntity *attacker, const idVec3 &dir
gameLocal.Error( "Unknown damageDef '%s'", damageDefName );
}
int damage = damageDef->GetInt( "damage" ) * damageScale;
// jmarshall - added min/max damage support.
//int damage = damageDef->GetInt( "damage" ) * damageScale;
int minDamage = damageDef->GetInt("minDamage", "-1");
int maxDamage = damageDef->GetInt("maxDamage", "-1");
int damage = -1;
if (minDamage == -1 || maxDamage == -1) {
int damageBase = damageDef->GetInt("damage");
minDamage = damageBase - (damageBase * 0.2f);
maxDamage = damageBase + (damageBase * 0.2f);
}
damage = rvRandom::irand(minDamage, maxDamage) * damageScale;
// jmarshall
damage = GetDamageForLocation( damage, location );
// inform the attacker that they hit someone
+46 -2
View File
@@ -248,6 +248,8 @@ public:
bool GetMasterPosition( idVec3 &masterOrigin, idMat3 &masterAxis ) const;
void GetWorldVelocities( idVec3 &linearVelocity, idVec3 &angularVelocity ) const;
virtual void CallNativeEvent(idStr& name) {};
// physics
// set a new physics object to be used by this entity
void SetPhysics( idPhysics *phys );
@@ -351,6 +353,48 @@ public:
void ServerSendEvent( int eventId, const idBitMsg *msg, bool saveEvent, int excludeClient ) const;
void ClientSendEvent( int eventId, const idBitMsg *msg ) const;
int GetIntKey(const char* key)
{
int value;
spawnArgs.GetInt(key, "0", value);
return value;
}
float GetFloatKey(const char* key)
{
float value;
spawnArgs.GetFloat(key, "0", value);
return value;
}
const char* GetKey(const char* key)
{
const char* value;
spawnArgs.GetString(key, "", &value);
return value;
}
float idEntity::GetFloat(const char* key)
{
return spawnArgs.GetFloat(key, "0");
}
int idEntity::GetInt(const char* key)
{
return spawnArgs.GetInt(key, "0");
}
bool idEntity::GetBool(const char* key)
{
return spawnArgs.GetBool(key, "0");
}
idVec3 idEntity::GetOrigin(void)
{
return GetLocalCoordinates(GetPhysics()->GetOrigin());
}
protected:
renderEntity_t renderEntity; // used to present a model to the renderer
int modelDefHandle; // handle to static renderer model
@@ -390,7 +434,7 @@ private:
void QuitTeam( void ); // leave the current team
void UpdatePVSAreas( void );
public:
// events
void Event_GetName( void );
void Event_SetName( const char *name );
@@ -511,7 +555,7 @@ protected:
idAnimator animator;
damageEffect_t * damageEffects;
private:
public:
void Event_GetJointHandle( const char *jointname );
void Event_ClearAllJoints( void );
void Event_ClearJoint( jointHandle_t jointnum );
+36
View File
@@ -2171,6 +2171,15 @@ gameReturn_t idGameLocal::RunFrame( const usercmd_t *clientCmds ) {
player = GetLocalPlayer();
for (int i = 0; i < delayRemoveEntities.Num(); i++)
{
if (gameLocal.time > delayRemoveEntities[i].removeTime)
{
delayRemoveEntities[i].entity->PostEventMS(&EV_Remove, 0);
delayRemoveEntities.RemoveIndex(i);
}
}
if ( !isMultiplayer && g_stopTime.GetBool() ) {
// clear any debug lines from a previous frame
gameRenderWorld->DebugClearLines( time + 1 );
@@ -4362,3 +4371,30 @@ void idGameLocal::GetMapLoadingGUI( char gui[ MAX_STRING_CHARS ] ) {
sprintf(gui, "guis/loadscreenbeta.gui");
}
/*
===============
idGameLocal::DelayRemoveEntity
===============
*/
void idGameLocal::DelayRemoveEntity(idEntity* entity, int delay)
{
rvmGameDelayRemoveEntry_t entry;
entry.entity = entity;
entry.removeTime = gameLocal.time + delay;
delayRemoveEntities.Append(entry);
}
/*
================
idGameLocal::Spawn
================
*/
idEntity* idGameLocal::Spawn(const char* classname)
{
idEntity* ent;
idDict dict;
dict.Set("classname", classname);
gameLocal.SpawnEntityDef(dict, &ent);
return ent;
}
+36
View File
@@ -60,6 +60,7 @@ extern idSoundWorld * gameSoundWorld;
// the "gameversion" client command will print this plus compile date
#define GAME_VERSION "baseDOOM-1"
#define GAME_FRAMETIME 0.016 // 16 milliseconds
// classes used by idGameLocal
class idEntity;
@@ -238,6 +239,12 @@ private:
int spawnId;
};
struct rvmGameDelayRemoveEntry_t
{
int32_t removeTime;
idEntity* entity;
};
//============================================================================
class idGameLocal : public idGame {
@@ -369,15 +376,27 @@ public:
// Initializes all map variables common to both save games and spawned games
void LoadMap( const char *mapName, int randseed );
void DelayRemoveEntity(idEntity* entity, int delay);
void LocalMapRestart( void );
void MapRestart( void );
static void MapRestart_f( const idCmdArgs &args );
float SysScriptTime(void) const
{
return MS2SEC(realClientTime);
}
float SysScriptFrameTime(void) const
{
return MS2SEC(time - previousTime);
}
bool NextMap( void ); // returns wether serverinfo settings have been modified
static void NextMap_f( const idCmdArgs &args );
idMapFile * GetLevelMap( void );
const char * GetMapName( void ) const;
idEntity* Spawn(const char* classname);
int NumAAS( void ) const;
idAAS * GetAAS( int num ) const;
idAAS * GetAAS( const char *name ) const;
@@ -572,6 +591,8 @@ private:
void UpdateLagometer( int aheadOfServer, int dupeUsercmds );
void GetMapLoadingGUI( char gui[ MAX_STRING_CHARS ] );
idList<rvmGameDelayRemoveEntry_t> delayRemoveEntities;
};
//============================================================================
@@ -741,4 +762,19 @@ const int CINEMATIC_SKIP_DELAY = SEC2MS( 2.0f );
#include "script/Script_Interpreter.h"
#include "script/Script_Thread.h"
#include "weapons/Weapon_fist.h"
#include "weapons/Weapon_pistol.h"
#include "weapons/Weapon_flashlight.h"
#include "weapons/Weapon_pda.h"
#include "weapons/Weapon_shotgun.h"
#include "weapons/Weapon_double_shotgun.h"
#include "weapons/Weapon_machinegun.h"
#include "weapons/Weapon_plasmagun.h"
#include "weapons/Weapon_chaingun.h"
#include "weapons/Weapon_rocketlauncher.h"
#include "weapons/Weapon_bfg.h"
#include "weapons/Weapon_handgrenade.h"
#include "weapons/Weapon_chainsaw.h"
#include "weapons/Weapon_grabber.h"
#endif /* !__GAME_LOCAL_H__ */
+1
View File
@@ -674,6 +674,7 @@ private:
void Event_GetPreviousWeapon( void );
void Event_SelectWeapon( const char *weaponName );
void Event_GetWeaponEntity( void );
public:
void Event_OpenPDA( void );
void Event_InPDA( void );
void Event_ExitTeleporter( void );
+82
View File
@@ -0,0 +1,82 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef PREDICTED_VALUE_H_
#define PREDICTED_VALUE_H_
#include "Game_local.h"
/*
================================================
A simple class to handle simple predictable values
on multiplayer clients.
The class encapsulates the actual value to be stored
as well as the client frame number on which it is set.
When reading predicted values from a snapshot, the actual
value is only updated if the server has processed the client's
usercmd for the frame in which the client predicted the value.
Got that?
================================================
*/
template< class type_ >
class idPredictedValue
{
public:
explicit idPredictedValue();
explicit idPredictedValue( const type_ & value_ );
void Set( const type_ & newValue );
idPredictedValue< type_ >& operator=( const type_ & value );
idPredictedValue< type_ >& operator+=( const type_ & toAdd );
idPredictedValue< type_ >& operator-=( const type_ & toSubtract );
bool UpdateFromSnapshot( const type_ & valueFromSnapshot, int clientNumber );
type_ Get() const
{
return value;
}
private:
// Noncopyable
idPredictedValue( const idPredictedValue< type_ >& other );
idPredictedValue< type_ >& operator=( const idPredictedValue< type_ >& other );
type_ value;
int clientPredictedMilliseconds; // The time in which the client predicted the value.
void UpdatePredictionTime();
};
#endif
+237
View File
@@ -0,0 +1,237 @@
/*
===========================================================================
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
#ifndef PREDICTED_VALUE_IMPL_H_
#define PREDICTED_VALUE_IMPL_H_
#include "PredictedValue.h"
#include "Player.h"
/*
===============
idPredictedValue::idPredictedValue
===============
*/
template< class type_ >
idPredictedValue< type_ >::idPredictedValue() :
value(),
clientPredictedMilliseconds( 0 )
{
}
/*
===============
idPredictedValue::idPredictedValue
===============
*/
template< class type_ >
idPredictedValue< type_ >::idPredictedValue( const type_ & value_ ) :
value( value_ ),
clientPredictedMilliseconds( 0 )
{
}
/*
===============
idPredictedValue::UpdatePredictionTime
===============
*/
template< class type_ >
void idPredictedValue< type_ >::UpdatePredictionTime()
{
//if( gameLocal.GetLocalPlayer() != NULL )
//{
// clientPredictedMilliseconds = gameLocal.GetLocalPlayer()->usercmd.clientGameMilliseconds;
//}
}
/*
===============
idPredictedValue::Set
===============
*/
template< class type_ >
void idPredictedValue< type_ >::Set( const type_ & newValue )
{
value = newValue;
UpdatePredictionTime();
}
/*
===============
idPredictedValue::operator=
===============
*/
template< class type_ >
idPredictedValue< type_ >& idPredictedValue< type_ >::operator=( const type_ & newValue )
{
Set( newValue );
return *this;
}
/*
===============
idPredictedValue::operator+=
===============
*/
template< class type_ >
idPredictedValue< type_ >& idPredictedValue< type_ >::operator+=( const type_ & toAdd )
{
Set( value + toAdd );
return *this;
}
/*
===============
idPredictedValue::operator-=
===============
*/
template< class type_ >
idPredictedValue< type_ >& idPredictedValue< type_ >::operator-=( const type_ & toSubtract )
{
Set( value - toSubtract );
return *this;
}
/*
===============
idPredictedValue::UpdateFromSnapshot
Always updates the value for remote clients.
Only updates the actual value if the snapshot usercmd frame is newer than the one in which
the client predicted this value.
Returns true if the value was set, false if not.
===============
*/
template< class type_ >
bool idPredictedValue< type_ >::UpdateFromSnapshot( const type_ & valueFromSnapshot, int clientNumber )
{
//if( clientNumber != gameLocal.GetLocalClientNum() )
//{
// value = valueFromSnapshot;
// return true;
//}
//
//if( gameLocal.GetLastClientUsercmdMilliseconds( clientNumber ) >= clientPredictedMilliseconds )
//{
// value = valueFromSnapshot;
// return true;
//}
return false;
}
/*
===============
operator==
Overload for idPredictedValue.
We only care if the values are equal, not the frame number.
===============
*/
template< class firstType_, class secondType_ >
bool operator==( const idPredictedValue< firstType_ >& lhs, const idPredictedValue< secondType_ >& rhs )
{
return lhs.Get() == rhs.Get();
}
/*
===============
operator!=
Overload for idPredictedValue.
We only care if the values are equal, not the frame number.
===============
*/
template< class firstType_, class secondType_ >
bool operator!=( const idPredictedValue< firstType_ >& lhs, const idPredictedValue< secondType_ >& rhs )
{
return lhs.Get() != rhs.Get();
}
/*
===============
operator==
Overload for idPredictedValue.
We only care if the values are equal, not the frame number.
===============
*/
template< class firstType_, class secondType_ >
bool operator==( const idPredictedValue< firstType_ >& lhs, const secondType_ & rhs )
{
return lhs.Get() == rhs;
}
/*
===============
operator==
Overload for idPredictedValue.
We only care if the values are equal, not the frame number.
===============
*/
template< class firstType_, class secondType_ >
bool operator==( const firstType_ lhs, const idPredictedValue< secondType_ >& rhs )
{
return lhs == rhs.Get();
}
/*
===============
operator!=
Overload for idPredictedValue.
We only care if the values are equal, not the frame number.
===============
*/
template< class firstType_, class secondType_ >
bool operator!=( const idPredictedValue< firstType_ >& lhs, const secondType_ & rhs )
{
return lhs.Get() != rhs;
}
/*
===============
operator!=
Overload for idPredictedValue.
We only care if the values are equal, not the frame number.
===============
*/
template< class firstType_, class secondType_ >
bool operator!=( const firstType_ lhs, const idPredictedValue< secondType_ >& rhs )
{
return lhs != rhs.Get();
}
#endif
+2031 -1056
View File
File diff suppressed because it is too large Load Diff
+306 -166
View File
@@ -1,27 +1,27 @@
/*
===========================================================================
IceTech GPL Source Code
Copyright (C) 2026 Justin Marshall
Doom 3 BFG Edition GPL Source Code
Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company.
This file is part of the IceTech GPL Source Code (?IceTech Source Code?).
This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code").
IceTech Source Code is free software: you can redistribute it and/or modify
Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
IceTech Source Code is distributed in the hope that it will be useful,
Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with IceTech Source Code. If not, see <http://www.gnu.org/licenses/>.
along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>.
In addition, the IceTech Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the IceTech Source Code. If not, please request a copy in writing from id Software at the address below.
In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below.
If you have questions concerning this license or the applicable additional terms, you may contact in writing Justin Marshall, justinmarshall20@gmail.com
If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
===========================================================================
*/
@@ -29,22 +29,18 @@ If you have questions concerning this license or the applicable additional terms
#ifndef __GAME_WEAPON_H__
#define __GAME_WEAPON_H__
#include "PredictedValue.h"
class idWeapon;
/*
===============================================================================
Player Weapon
===============================================================================
*/
typedef enum {
WP_READY,
WP_OUTOFAMMO,
WP_RELOAD,
WP_HOLSTERED,
WP_RISING,
WP_LOWERING
} weaponStatus_t;
extern const idEventDef EV_Weapon_State;
typedef int ammo_t;
static const int AMMO_NUMTYPES = 16;
@@ -56,124 +52,276 @@ static const int LIGHTID_VIEW_MUZZLE_FLASH = 100;
class idMoveableItem;
class idWeapon : public idAnimatedEntity {
public:
CLASS_PROTOTYPE( idWeapon );
typedef struct
{
char name[64];
char particlename[128];
bool active;
int startTime;
jointHandle_t joint; //The joint on which to attach the particle
bool smoke; //Is this a smoke particle
const idDeclParticle* particle; //Used for smoke particles
idFuncEmitter* emitter; //Used for non-smoke particles
} WeaponParticle_t;
idWeapon();
typedef struct
{
char name[64];
bool active;
int startTime;
jointHandle_t joint;
int lightHandle;
renderLight_t light;
} WeaponLight_t;
class rvmWeaponObject : public idClass
{
public:
CLASS_PROTOTYPE(rvmWeaponObject);
virtual void Init(idWeapon* weapon);
void SetState(const char* state)
{
stateThread.SetState(state);
}
void AppendState(const char* state)
{
stateThread.PostState(state);
}
void Execute(void)
{
stateThread.Execute();
}
bool IsRunning(void)
{
return stateThread.IsExecuting();
}
bool IsStateRunning(const char* name)
{
return stateThread.CurrentStateIs(name);
}
virtual void OwnerDied(void) {}
bool IsFiring();
bool IsReloading();
stateResult_t Holstered(stateParms_t* parms)
{
return SRESULT_WAIT;
}
virtual bool IsHolstered(void)
{
return IsStateRunning("Holstered");
}
protected:
idWeapon* owner;
const idSoundShader* FindSound(const char* name);
protected:
rvStateThread stateThread;
float next_attack;
};
class idWeapon : public idAnimatedEntity
{
public:
CLASS_PROTOTYPE(idWeapon);
idWeapon();
virtual ~idWeapon();
// Init
void Spawn( void );
void SetOwner( idPlayer *owner );
idPlayer* GetOwner( void );
virtual bool ShouldConstructScriptObjectAtSpawn( void ) const;
void Spawn();
void SetOwner(idPlayer* owner);
idPlayer* GetOwner();
virtual bool ShouldConstructScriptObjectAtSpawn() const;
void SetFlashlightOwner(idPlayer* owner);
static void CacheWeapon( const char *weaponName );
virtual idClass* InvokeChild() override
{
return currentWeaponObject;
}
static void CacheWeapon(const char* weaponName);
// save games
void Save( idSaveGame *savefile ) const; // archives object for save game file
void Restore( idRestoreGame *savefile ); // unarchives object from save game file
void Save(idSaveGame* savefile) const; // archives object for save game file
void Restore(idRestoreGame* savefile); // unarchives object from save game file
// Weapon definition management
void Clear( void );
void GetWeaponDef( const char *objectname, int ammoinclip );
bool IsLinked( void );
bool IsWorldModelReady( void );
void Clear();
void GetWeaponDef(const char* objectname, int ammoinclip);
bool IsWorldModelReady();
// GUIs
const char * Icon( void ) const;
void UpdateGUI( void );
const char* Icon() const;
void UpdateGUI();
const char* PdaIcon() const;
const char* DisplayName() const;
const char* Description() const;
virtual void SetModel( const char *modelname );
bool GetGlobalJointTransform( bool viewModel, const jointHandle_t jointHandle, idVec3 &offset, idMat3 &axis );
void SetPushVelocity( const idVec3 &pushVelocity );
bool UpdateSkin( void );
virtual void SetModel(const char* modelname);
bool GetGlobalJointTransform(bool viewModel, const jointHandle_t jointHandle, idVec3& offset, idMat3& axis);
void SetPushVelocity(const idVec3& pushVelocity);
bool UpdateSkin();
bool IsFiring()
{
return isFiring;
}
// State control/player interface
void Think( void );
void Raise( void );
void PutAway( void );
void Reload( void );
void LowerWeapon( void );
void RaiseWeapon( void );
void HideWeapon( void );
void ShowWeapon( void );
void HideWorldModel( void );
void ShowWorldModel( void );
void OwnerDied( void );
void BeginAttack( void );
void EndAttack( void );
bool IsReady( void ) const;
bool IsReloading( void ) const;
bool IsHolstered( void ) const;
bool ShowCrosshair( void ) const;
idEntity * DropItem( const idVec3 &velocity, int activateDelay, int removeDelay, bool died );
bool CanDrop( void ) const;
void WeaponStolen( void );
// Script state management
virtual idThread * ConstructScriptObject( void );
virtual void DeconstructScriptObject( void );
void SetState( const char *statename, int blendFrames );
void UpdateScript( void );
void EnterCinematic( void );
void ExitCinematic( void );
void NetCatchup( void );
void Think();
void Raise();
void PutAway();
void Reload();
void LowerWeapon();
void RaiseWeapon();
void HideWeapon();
void ShowWeapon();
void HideWorldModel();
void ShowWorldModel();
void OwnerDied();
void BeginAttack();
void EndAttack();
bool IsReady() const;
bool IsReloading() const;
bool IsHolstered() const;
bool ShowCrosshair() const;
idEntity* DropItem(const idVec3& velocity, int activateDelay, int removeDelay, bool died);
bool CanDrop() const;
void WeaponStolen();
void ForceAmmoInClip();
// Visual presentation
void PresentWeapon( bool showViewModel );
int GetZoomFov( void );
void GetWeaponAngleOffsets( int *average, float *scale, float *max );
void GetWeaponTimeOffsets( float *time, float *scale );
bool BloodSplat( float size );
void PresentWeapon(bool showViewModel);
int GetZoomFov();
void GetWeaponAngleOffsets(int* average, float* scale, float* max);
void GetWeaponTimeOffsets(float* time, float* scale);
bool BloodSplat(float size);
void SetIsPlayerFlashlight(bool bl)
{
isPlayerFlashlight = bl;
}
void FlashlightOn();
void FlashlightOff();
// Ammo
static ammo_t GetAmmoNumForName( const char *ammoname );
static const char *GetAmmoNameForNum( ammo_t ammonum );
static const char *GetAmmoPickupNameForNum( ammo_t ammonum );
ammo_t GetAmmoType( void ) const;
int AmmoAvailable( void ) const;
int AmmoInClip( void ) const;
void ResetAmmoClip( void );
int ClipSize( void ) const;
int LowAmmo( void ) const;
int AmmoRequired( void ) const;
static ammo_t GetAmmoNumForName(const char* ammoname);
static const char* GetAmmoNameForNum(ammo_t ammonum);
static const char* GetAmmoPickupNameForNum(ammo_t ammonum);
ammo_t GetAmmoType() const;
int AmmoAvailable() const;
int AmmoInClip() const;
void ResetAmmoClip();
int ClipSize() const;
int LowAmmo() const;
int AmmoRequired() const;
int AmmoCount() const;
int GetGrabberState() const;
virtual void WriteToSnapshot( idBitMsgDelta &msg ) const;
virtual void ReadFromSnapshot( const idBitMsgDelta &msg );
// Flashlight
idAnimatedEntity* GetWorldModel()
{
return worldModel.GetEntity();
}
enum {
virtual void WriteToSnapshot(idBitMsg& msg) const;
virtual void ReadFromSnapshot(const idBitMsg& msg);
enum
{
EVENT_RELOAD = idEntity::EVENT_MAXEVENTS,
EVENT_ENDRELOAD,
EVENT_CHANGESKIN,
EVENT_MAXEVENTS
};
virtual bool ClientReceiveEvent( int event, int time, const idBitMsg &msg );
virtual bool ClientReceiveEvent(int event, int time, const idBitMsg& msg);
virtual void ClientPredictionThink( void );
virtual void ClientPredictionThink();
virtual void ClientThink(const int curTime, const float fraction, const bool predict);
void MuzzleFlashLight();
void RemoveMuzzleFlashlight();
// Get a global origin and axis suitable for the laser sight or bullet tracing
// Returns false for hands, grenades, and chainsaw.
// Can't be const because a frame may need to be created.
bool GetMuzzlePositionWithHacks(idVec3& origin, idMat3& axis);
void GetProjectileLaunchOriginAndAxis(idVec3& origin, idMat3& axis);
const idDeclEntityDef* GetDeclEntityDef()
{
return weaponDef;
}
friend class idPlayer;
public:
virtual void CallNativeEvent(idStr& name) override;
void Event_SetLightParm(int parmnum, float value);
void Event_SetLightParms(float parm0, float parm1, float parm2, float parm3);
// script events
void Event_Clear();
void Event_GetOwner();
void Event_SetWeaponStatus(float newStatus);
void Event_WeaponReady();
void Event_WeaponOutOfAmmo();
void Event_WeaponReloading();
void Event_WeaponHolstered();
void Event_WeaponRising();
void Event_WeaponLowering();
void Event_UseAmmo(int amount);
void Event_AddToClip(int amount);
void Event_AmmoInClip();
int AmmoAvailable();
void Event_AmmoAvailable();
void Event_TotalAmmoCount();
void Event_ClipSize();
void Event_PlayAnim(int channel, const char* animname, bool loop);
void Event_PlayCycle(int channel, const char* animname);
bool Event_AnimDone(int channel, int blendFrames);
void Event_SetBlendFrames(int channel, int blendFrames);
void Event_GetBlendFrames(int channel);
void Event_Next();
void Event_SetSkin(const char* skinname);
void Event_Flashlight(int enable);
void Event_GetLightParm(int parmnum);
void Event_LaunchProjectiles(int num_projectiles, float spread, float fuseOffset, float launchPower, float dmgPower);
idEntity* CreateProjectile();
void Event_CreateProjectile();
void Event_EjectBrass();
void Event_Melee();
void Event_GetWorldModel();
void Event_AllowDrop(int allow);
void Event_AutoReload();
void Event_NetReload();
bool Event_IsInvisible();
void Event_NetEndReload();
void EnterCinematic();
void ExitCinematic();
void NetCatchup();
bool IsLinked()
{
return currentWeaponObject != NULL;
}
private:
// script control
idScriptBool WEAPON_ATTACK;
idScriptBool WEAPON_RELOAD;
idScriptBool WEAPON_NETRELOAD;
idScriptBool WEAPON_NETENDRELOAD;
idScriptBool WEAPON_NETFIRING;
idScriptBool WEAPON_RAISEWEAPON;
idScriptBool WEAPON_LOWERWEAPON;
weaponStatus_t status;
idThread * thread;
idStr state;
idStr idealState;
int animBlendFrames;
int animDoneTime;
bool isPlayerFlashlight;
bool isLinked;
// precreated projectile
idEntity *projectileEnt;
idEntity* projectileEnt;
idPlayer * owner;
idPlayer* owner;
idEntityPtr<idAnimatedEntity> worldModel;
// hiding (for GUIs and NPCs)
@@ -186,6 +334,8 @@ private:
bool hide;
bool disabled;
bool isFlashLight;
// berserk
int berserk;
@@ -196,7 +346,7 @@ private:
// the view weapon render entity parms
idVec3 viewWeaponOrigin;
idMat3 viewWeaponAxis;
// the muzzle bone's position, used for launching projectiles and trailing smoke
idVec3 muzzleOrigin;
idMat3 muzzleAxis;
@@ -206,14 +356,17 @@ private:
// weapon definition
// we maintain local copies of the projectile and brass dictionaries so they
// do not have to be copied across the DLL boundary when entities are spawned
const idDeclEntityDef * weaponDef;
const idDeclEntityDef * meleeDef;
const idDeclEntityDef* weaponDef;
const idDeclEntityDef* meleeDef;
idDict projectileDict;
float meleeDistance;
idStr meleeDefName;
idDict brassDict;
int brassDelay;
idStr icon;
idStr pdaIcon;
idStr displayName;
idStr itemDesc;
// view weapon gui light
renderLight_t guiLight;
@@ -226,6 +379,9 @@ private:
renderLight_t worldMuzzleFlash; // positioned on world weapon bone
int worldMuzzleFlashHandle;
float fraccos;
float fraccos2;
idVec3 flashColor;
int muzzleFlashEnd;
int flashTime;
@@ -247,15 +403,15 @@ private:
ammo_t ammoType;
int ammoRequired; // amount of ammo to use each shot. 0 means weapon doesn't need ammo.
int clipSize; // 0 means no reload
int ammoClip;
idPredictedValue< int > ammoClip;
int lowAmmo; // if ammo in clip hits this threshold, snd_
bool powerAmmo; // true if the clip reduction is a factor of the power setting when
// a projectile is launched
// a projectile is launched
// mp client
bool isFiring;
// zoom
int zoomFov; // variable zoom fov per weapon
int zoomFov; // variable zoom fov per weapon
// joints from models
jointHandle_t barrelJointView;
@@ -268,29 +424,34 @@ private:
jointHandle_t barrelJointWorld;
jointHandle_t ejectJointWorld;
jointHandle_t smokeJointView;
idHashTable<WeaponParticle_t> weaponParticles;
idHashTable<WeaponLight_t> weaponLights;
// sound
const idSoundShader * sndHum;
const idSoundShader* sndHum;
// new style muzzle smokes
const idDeclParticle * weaponSmoke; // null if it doesn't smoke
const idDeclParticle* weaponSmoke; // null if it doesn't smoke
int weaponSmokeStartTime; // set to gameLocal.time every weapon fire
bool continuousSmoke; // if smoke is continuous ( chainsaw )
const idDeclParticle * strikeSmoke; // striking something in melee
int strikeSmokeStartTime; // timing
idVec3 strikePos; // position of last melee strike
const idDeclParticle* strikeSmoke; // striking something in melee
int strikeSmokeStartTime; // timing
idVec3 strikePos; // position of last melee strike
idMat3 strikeAxis; // axis of last melee strike
int nextStrikeFx; // used for sound and decal ( may use for strike smoke too )
// nozzle effects
bool nozzleFx; // does this use nozzle effects ( parm5 at rest, parm6 firing )
// this also assumes a nozzle light atm
// this also assumes a nozzle light atm
int nozzleFxFade; // time it takes to fade between the effects
int lastAttack; // last time an attack occured
renderLight_t nozzleGlow; // nozzle light
int nozzleGlowHandle; // handle for nozzle light
idVec3 nozzleGlowColor; // color of the nozzle glow
const idMaterial * nozzleGlowShader; // shader for glow light
const idMaterial* nozzleGlowShader; // shader for glow light
float nozzleGlowRadius; // radius of glow light
// weighting for viewmodel angles
@@ -301,65 +462,44 @@ private:
float weaponOffsetScale;
// flashlight
void AlertMonsters( void );
void AlertMonsters();
// Visual presentation
void InitWorldModel( const idDeclEntityDef *def );
void MuzzleFlashLight( void );
void MuzzleRise( idVec3 &origin, idMat3 &axis );
void UpdateNozzleFx( void );
void UpdateFlashPosition( void );
void InitWorldModel(const idDeclEntityDef* def);
void MuzzleRise(idVec3& origin, idMat3& axis);
void UpdateNozzleFx();
void UpdateFlashPosition();
// script events
void Event_Clear( void );
void Event_GetOwner( void );
void Event_WeaponState( const char *statename, int blendFrames );
void Event_SetWeaponStatus( float newStatus );
void Event_WeaponReady( void );
void Event_WeaponOutOfAmmo( void );
void Event_WeaponReloading( void );
void Event_WeaponHolstered( void );
void Event_WeaponRising( void );
void Event_WeaponLowering( void );
void Event_UseAmmo( int amount );
void Event_AddToClip( int amount );
void Event_AmmoInClip( void );
void Event_AmmoAvailable( void );
void Event_TotalAmmoCount( void );
void Event_ClipSize( void );
void Event_PlayAnim( int channel, const char *animname );
void Event_PlayCycle( int channel, const char *animname );
void Event_AnimDone( int channel, int blendFrames );
void Event_SetBlendFrames( int channel, int blendFrames );
void Event_GetBlendFrames( int channel );
void Event_Next( void );
void Event_SetSkin( const char *skinname );
void Event_Flashlight( int enable );
void Event_GetLightParm( int parmnum );
void Event_SetLightParm( int parmnum, float value );
void Event_SetLightParms( float parm0, float parm1, float parm2, float parm3 );
void Event_LaunchProjectiles( int num_projectiles, float spread, float fuseOffset, float launchPower, float dmgPower );
void Event_CreateProjectile( void );
void Event_EjectBrass( void );
void Event_Melee( void );
void Event_GetWorldModel( void );
void Event_AllowDrop( int allow );
void Event_AutoReload( void );
void Event_NetReload( void );
void Event_IsInvisible( void );
void Event_NetEndReload( void );
//idGrabber grabber;
int grabberState;
public:
void Event_Grabber(int enable);
int Event_GrabberHasTarget();
void Event_GrabberSetGrabDistance(float dist);
void Event_LaunchProjectilesEllipse(int num_projectiles, float spreada, float spreadb, float fuseOffset, float power);
void Event_LaunchPowerup(const char* powerup, float duration, int useAmmo);
void Event_StartWeaponSmoke();
void Event_StopWeaponSmoke();
void Event_StartWeaponParticle(const char* name);
void Event_StopWeaponParticle(const char* name);
void Event_StartWeaponLight(const char* name);
void Event_StopWeaponLight(const char* name);
private:
rvmWeaponObject* currentWeaponObject;
bool OutOfAmmo;
};
ID_INLINE bool idWeapon::IsLinked( void ) {
return isLinked;
ID_INLINE bool idWeapon::IsWorldModelReady()
{
return (worldModel.GetEntity() != NULL);
}
ID_INLINE bool idWeapon::IsWorldModelReady( void ) {
return ( worldModel.GetEntity() != NULL );
}
ID_INLINE idPlayer* idWeapon::GetOwner( void ) {
ID_INLINE idPlayer* idWeapon::GetOwner()
{
return owner;
}
#endif /* !__GAME_WEAPON_H__ */
#endif /* !__GAME_WEAPON_H__ */
+413
View File
@@ -0,0 +1,413 @@
// Bot.cpp
//
#include "precompiled.h"
#include "../Game_local.h"
idCVar bot_pathdebug( "bot_pathdebug", "0", CVAR_BOOL | CVAR_CHEAT, "force the bot to path to player" );
idCVar bot_goaldist( "bot_goaldist", "20", CVAR_INTEGER | CVAR_CHEAT, "" );
idCVar bot_debugnav( "bot_debugnav", "0", CVAR_BOOL | CVAR_CHEAT, "draws navmesh paths for the bot" );
idCVar bot_showstate( "bot_showstate", "0", CVAR_BOOL | CVAR_CHEAT, "draws the bot state above the bot" );
idCVar bot_debug( "bot_debug", "0", CVAR_BOOL, "shows debug info for the bot" );
idCVar bot_skill("bot_skill", "3", CVAR_INTEGER, "");
CLASS_DECLARATION( idPlayer, rvmBot )
END_CLASS
/*
===================
rvmBot::rvmBot
===================
*/
rvmBot::rvmBot()
{
//bs.action = NULL;
hasSpawned = false;
gameLocal.RegisterBot( this );
}
/*
===================
rvmBot::~rvmBot
===================
*/
rvmBot::~rvmBot()
{
gameLocal.UnRegisterBot( this );
}
/*
==================
rvmBot::SetEnemy
==================
*/
void rvmBot::SetEnemy( idPlayer* player, idVec3 origin)
{
if(bs.enemy == -1)
{
bs.enemy = player->entityNumber;
bs.aggressiveAttackTime = gameLocal.SysScriptTime() + 2.0f;
bs.lastenemyorigin = origin;
//bs.action = &botAIBattleRetreat;
stateThread.SetState("state_Attacked");
}
}
/*
==================
rvmBot::BotUpdateInventory
==================
*/
void rvmBot::BotUpdateInventory( void )
{
bs.inventory[INVENTORY_ARMOR] = inventory.armor;
bs.inventory[INVENTORY_GAUNTLET] = 1;
bs.inventory[INVENTORY_SHOTGUN] = HasWeapon( weapon_shotgun );
bs.inventory[INVENTORY_MACHINEGUN] = HasWeapon( weapon_machinegun );
bs.inventory[INVENTORY_GRENADELAUNCHER] = 0;
bs.inventory[INVENTORY_ROCKETLAUNCHER] = HasWeapon( weapon_rocketlauncher );
bs.inventory[INVENTORY_LIGHTNING] = 0;
bs.inventory[INVENTORY_RAILGUN] = 0;
bs.inventory[INVENTORY_PLASMAGUN] = HasWeapon( weapon_plasmagun );
bs.inventory[INVENTORY_BFG10K] = 0;
bs.inventory[INVENTORY_GRAPPLINGHOOK] = 0;
bs.inventory[INVENTORY_SHELLS] = inventory.ammo[idWeapon::GetAmmoNumForName( "ammo_shells" )].Get();
bs.inventory[INVENTORY_BULLETS] = inventory.ammo[idWeapon::GetAmmoNumForName( "ammo_clip" )].Get();
bs.inventory[INVENTORY_GRENADES] = 0;
bs.inventory[INVENTORY_CELLS] = inventory.ammo[idWeapon::GetAmmoNumForName( "ammo_cells" )].Get();
bs.inventory[INVENTORY_LIGHTNINGAMMO] = 0;
bs.inventory[INVENTORY_ROCKETS] = inventory.ammo[idWeapon::GetAmmoNumForName( "ammo_rockets" )].Get();
bs.inventory[INVENTORY_SLUGS] = 0;
bs.inventory[INVENTORY_BFGAMMO] = 0;
bs.inventory[INVENTORY_HEALTH] = health;
bs.inventory[INVENTORY_TELEPORTER] = 0;
bs.inventory[INVENTORY_MEDKIT] = 0;
bs.inventory[INVENTORY_QUAD] = 0;
bs.inventory[INVENTORY_ENVIRONMENTSUIT] = 0;
bs.inventory[INVENTORY_HASTE] = 0;
bs.inventory[INVENTORY_INVISIBILITY] = 0;
bs.inventory[INVENTORY_REGEN] = 0;
bs.inventory[INVENTORY_FLIGHT] = 0;
bs.inventory[INVENTORY_REDFLAG] = 0;
bs.inventory[INVENTORY_BLUEFLAG] = 0;
}
/*
===================
rvmBot::Spawn
===================
*/
void rvmBot::Spawn( void )
{
idStr botName;
char filename[256];
int errnum;
stateThread.SetOwner(this);
idPlayer::Spawn();
if( common->IsServer() )
{
weapon_machinegun = SlotForWeapon( "weapon_machinegun" );
weapon_shotgun = SlotForWeapon( "weapon_shotgun" );
weapon_plasmagun = SlotForWeapon( "weapon_plasmagun" );
weapon_rocketlauncher = SlotForWeapon( "weapon_rocketlauncher" );
WP_MACHINEGUN = weapon_machinegun;
WP_SHOTGUN = weapon_shotgun;
WP_PLASMAGUN = weapon_plasmagun;
WP_ROCKET_LAUNCHER = weapon_rocketlauncher;
botName = spawnArgs.GetString( "botname" );
aas = gameLocal.GetBotAAS();
if( aas == NULL )
{
gameLocal.Error( "Missing AAS\n" );
return;
}
// Load in the bot character.
bs.character = botCharacterStatsManager.BotLoadCharacterFromFile( va( "bots/%s_c.c", botName.c_str() ), 1 );
if( !bs.character )
{
gameLocal.Error( "Failed to load character file for bot %s\n", botName.c_str() );
}
// Allocate the goal state.
bs.gs = botGoalManager.BotAllocGoalState( entityNumber );
// Get the bot items weights file name.
botCharacterStatsManager.Characteristic_String( bs.character, CHARACTERISTIC_ITEMWEIGHTS, filename, 256 );
errnum = botGoalManager.BotLoadItemWeights( bs.gs, filename );
if( errnum != BLERR_NOERROR )
{
gameLocal.Error( "Failed to load bot item weights!" );
botGoalManager.BotFreeGoalState( bs.gs );
return;
}
//allocate a weapon state
bs.ws = botWeaponInfoManager.BotAllocWeaponState();
//load the weapon weights
botCharacterStatsManager.Characteristic_String( bs.character, CHARACTERISTIC_WEAPONWEIGHTS, filename, 256 );
errnum = botWeaponInfoManager.BotLoadWeaponWeights( bs.ws, filename );
if( errnum != BLERR_NOERROR )
{
// trap_BotFreeGoalState(bs->gs);
botWeaponInfoManager.BotFreeWeaponState( bs.ws );
return;
}
bs.client = entityNumber;
bs.entitynum = entityNumber;
bs.setupcount = 4;
bs.entergame_time = Bot_Time();
hasSpawned = true;
bs.botinput.respawn = true;
stateThread.SetState("state_Respawn");
}
}
/*
===================
rvmBot::Think
===================
*/
void rvmBot::BotMoveToGoalOrigin(idVec3 goalOrigin)
{
bs.botinput.dir = (goalOrigin - firstPersonViewOrigin);
idAngles desiredAngles = bs.botinput.dir.ToAngles();
if( bs.enemy >= 0 )
{
idPlayer* enemy = gameLocal.entities[bs.enemy]->Cast<idPlayer>();
if( enemy )
{
desiredAngles = (enemy->firstPersonViewOrigin - firstPersonViewOrigin).ToAngles();
}
}
bs.botinput.viewangles = desiredAngles;
bs.botinput.speed = pm_runspeed.GetInteger();
bs.botinput.dir.Normalize();
}
/*
===================
rvmBot::SpawnToPoint
===================
*/
void rvmBot::SpawnToPoint( const idVec3& spawn_origin, const idAngles& spawn_angles )
{
idPlayer::SpawnToPoint( spawn_origin, spawn_angles );
if( common->IsServer() )
{
bs.ltg_time = 0;
stateThread.SetState("state_SeekLTG");
}
}
/*
===================
rvmBot::StateThreadChanged
===================
*/
void rvmBot::StateThreadChanged(void) {
// Ensure if we are switching states, pop the last goal.
bs.ltg_time = 0;
}
/*
===================
rvmBot::ServerThink
===================
*/
void rvmBot::ServerThink( void )
{
bs.origin = GetPhysics()->GetOrigin();
bs.eye = GetEyePosition();
bs.thinktime = Bot_Time();
bs.botinput.actionflags = 0;
BotUpdateInventory();
if( bot_pathdebug.IsModified() )
{
if( bot_pathdebug.GetBool() )
{
bs.currentGoal.origin = gameLocal.GetLocalPlayer()->GetPhysics()->GetOrigin();
bs.currentGoal.framenum = gameLocal.framenum;
}
bot_pathdebug.ClearModified();
bot_pathdebug.SetBool( false );
}
stateThread.Execute();
// If we are moving along a set of waypoints, let's move along.
aasPath_t path;
//int myArea = aas->PointAreaNum(GetOrigin());
int goalArea = aas->PointAreaNum( bs.currentGoal.origin );
idVec3 org = bs.origin;
int curAreaNum = aas->AdjustPositionAndGetArea( org );
if( bot_debug.GetBool() )
{
if (bs.useRandomPosition)
{
aas->ShowWalkPath(GetOrigin(), goalArea, bs.random_move_position);
}
else
{
aas->ShowWalkPath(GetOrigin(), goalArea, bs.currentGoal.origin);
}
aas->ShowArea( GetOrigin() );
}
if (bs.useRandomPosition)
{
aas->WalkPathToGoal(path, curAreaNum, org, goalArea, bs.random_move_position, TFL_WALK | TFL_AIR);
}
else
{
aas->WalkPathToGoal(path, curAreaNum, org, goalArea, bs.currentGoal.origin, TFL_WALK | TFL_AIR);
}
idVec3 moveGoal = path.moveGoal;
BotMoveToGoalOrigin(path.moveGoal);
bs.viewangles = bs.botinput.viewangles;
bs.useRandomPosition = false;
bs.attackerEntity = NULL; // Has to be consumed immedaitly.
bs.botinput.weapon = bs.weaponnum;
}
/*
=======================
rvmBot::Damage
=======================
*/
void rvmBot::Damage( idEntity* inflictor, idEntity* attacker, const idVec3& dir, const char* damageDefName, const float damageScale, const int location )
{
idPlayer::Damage( inflictor, attacker, dir, damageDefName, damageScale, location );
idPlayer* player = attacker->Cast<idPlayer>();
if (health <= 0)
{
if (player)
{
BotSendChatMessage(DEATH, player->netname );
}
}
if (attacker == NULL) {
return;
}
//bs.attackerEntity = attacker;
SetEnemy(player, attacker->GetOrigin());
}
/*
=======================
rvmBot::InflictedDamageEvent
=======================
*/
void rvmBot::InflictedDamageEvent(idEntity* target) {
idPlayer* player = target->Cast<idPlayer>();
// Don't flood the chat with death and insults.
if (!player->IsBot() && player->health <= 0)
{
BotSendChatMessage(KILL, player->netname);
}
}
/*
=======================
rvmBot::PresenceTypeBoundingBox
=======================
*/
void rvmBot::PresenceTypeBoundingBox( int presencetype, idVec3& mins, idVec3& maxs )
{
int index;
//bounding box size for each presence type
//idVec3 boxmins[3] = { {0, 0, 0}, {-15, -15, -24}, {-15, -15, -24} };
//idVec3 boxmaxs[3] = { {0, 0, 0}, { 15, 15, 32}, { 15, 15, 8} };
idVec3 boxmins[3];
idVec3 boxmaxs[3];
boxmins[0] = idVec3( 0, 0, 0 );
boxmins[1] = idVec3( -15, -15, -24 );
boxmins[2] = idVec3( -15, -15, -24 );
boxmaxs[0] = idVec3( 0, 0, 0 );
boxmaxs[1] = idVec3( 15, 15, 32 );
boxmaxs[2] = idVec3( 15, 15, 8 );
if( presencetype == PRESENCE_NORMAL )
{
index = 1;
}
else if( presencetype == PRESENCE_CROUCH )
{
index = 2;
}
else
{
//botimport.Print(PRT_FATAL, "AAS_PresenceTypeBoundingBox: unknown presence type\n");
index = 2;
}
mins = boxmins[index];
maxs = boxmaxs[index];
}
/*
===================
rvmBot::Think
===================
*/
void rvmBot::Think( void )
{
if( !hasSpawned )
{
return;
}
if( common->IsServer() )
{
ServerThink();
if( bot_debug.GetBool() )
{
idVec4 color;
color = idVec4(1, 1, 1, 1);
if (bs.enemy >= 0)
color = idVec4(1, 0, 0, 1);
idBounds bounds = idBounds( idVec3( -10, -10, -10 ), idVec3( 10, 10, 10 ) );
common->RW()->DebugBounds( color, bounds, GetOrigin() );
idMat3 axis = viewAngles.ToMat3();
common->RW()->DrawTextA(stateThread.GetState()->state.c_str(), GetOrigin(), 1.0f, color, axis);
}
}
deltaViewAngles.Zero();
idPlayer::Think();
}
+920
View File
@@ -0,0 +1,920 @@
// Bot.h
//
class rvmBotAIBotActionBase;
// These need to match items.def
#define INVENTORY_ARMOR 1
#define INVENTORY_GAUNTLET 4
#define INVENTORY_SHOTGUN 5
#define INVENTORY_MACHINEGUN 6
#define INVENTORY_GRENADELAUNCHER 7
#define INVENTORY_ROCKETLAUNCHER 8
#define INVENTORY_LIGHTNING 9
#define INVENTORY_RAILGUN 10
#define INVENTORY_PLASMAGUN 11
#define INVENTORY_BFG10K 13
#define INVENTORY_GRAPPLINGHOOK 14
#define INVENTORY_NAILGUN 15
#define INVENTORY_PROXLAUNCHER 16
#define INVENTORY_CHAINGUN 17
#define INVENTORY_SHELLS 18
#define INVENTORY_BULLETS 19
#define INVENTORY_GRENADES 20
#define INVENTORY_CELLS 21
#define INVENTORY_LIGHTNINGAMMO 22
#define INVENTORY_ROCKETS 23
#define INVENTORY_SLUGS 24
#define INVENTORY_BFGAMMO 25
#define INVENTORY_NAILS 26
#define INVENTORY_MINES 27
#define INVENTORY_BELT 28
#define INVENTORY_HEALTH 29
#define INVENTORY_TELEPORTER 30
#define INVENTORY_MEDKIT 31
#define INVENTORY_KAMIKAZE 32
#define INVENTORY_PORTAL 33
#define INVENTORY_INVULNERABILITY 34
#define INVENTORY_QUAD 35
#define INVENTORY_ENVIRONMENTSUIT 36
#define INVENTORY_HASTE 37
#define INVENTORY_INVISIBILITY 38
#define INVENTORY_REGEN 39
#define INVENTORY_FLIGHT 40
#define INVENTORY_SCOUT 41
#define INVENTORY_GUARD 42
#define INVENTORY_DOUBLER 43
#define INVENTORY_AMMOREGEN 44
#define INVENTORY_REDFLAG 45
#define INVENTORY_BLUEFLAG 46
#define INVENTORY_NEUTRALFLAG 47
#define INVENTORY_REDCUBE 48
#define INVENTORY_BLUECUBE 49
#define INVENTORY_DOUBLESHOTGUN 50
#define MODELINDEX_DEFAULT 0
#define MODELINDEX_ARMORSHARD 1
#define MODELINDEX_ARMORCOMBAT 2
#define MODELINDEX_ARMORBODY 3
#define MODELINDEX_HEALTHSMALL 4
#define MODELINDEX_HEALTH 5
#define MODELINDEX_HEALTHLARGE 6
#define MODELINDEX_HEALTHMEGA 7
#define MODELINDEX_GAUNTLET 8
#define MODELINDEX_SHOTGUN 9
#define MODELINDEX_MACHINEGUN 10
#define MODELINDEX_GRENADELAUNCHER 11
#define MODELINDEX_ROCKETLAUNCHER 12
#define MODELINDEX_LIGHTNING 13
#define MODELINDEX_RAILGUN 14
#define MODELINDEX_PLASMAGUN 15
#define MODELINDEX_BFG10K 16
#define MODELINDEX_GRAPPLINGHOOK 17
#define MODELINDEX_SHELLS 18
#define MODELINDEX_BULLETS 19
#define MODELINDEX_GRENADES 20
#define MODELINDEX_CELLS 21
#define MODELINDEX_LIGHTNINGAMMO 22
#define MODELINDEX_ROCKETS 23
#define MODELINDEX_SLUGS 24
#define MODELINDEX_BFGAMMO 25
#define MODELINDEX_TELEPORTER 26
#define MODELINDEX_MEDKIT 27
#define MODELINDEX_QUAD 28
#define MODELINDEX_ENVIRONMENTSUIT 29
#define MODELINDEX_HASTE 30
#define MODELINDEX_INVISIBILITY 31
#define MODELINDEX_REGEN 32
#define MODELINDEX_FLIGHT 33
#define MODELINDEX_REDFLAG 34
#define MODELINDEX_BLUEFLAG 35
#define MODELINDEX_KAMIKAZE 36
#define MODELINDEX_PORTAL 37
#define MODELINDEX_INVULNERABILITY 38
#define MODELINDEX_NAILS 39
#define MODELINDEX_MINES 40
#define MODELINDEX_BELT 41
#define MODELINDEX_SCOUT 42
#define MODELINDEX_GUARD 43
#define MODELINDEX_DOUBLER 44
#define MODELINDEX_AMMOREGEN 45
#define MODELINDEX_NEUTRALFLAG 46
#define MODELINDEX_REDCUBE 47
#define MODELINDEX_BLUECUBE 48
#define MODELINDEX_NAILGUN 49
#define MODELINDEX_PROXLAUNCHER 50
#define MODELINDEX_CHAINGUN 51
#define MODELINDEX_POINTABLUE 52
#define MODELINDEX_POINTBBLUE 53
#define MODELINDEX_POINTARED 54
#define MODELINDEX_POINTBRED 55
#define MODELINDEX_POINTAWHITE 56
#define MODELINDEX_POINTBWHITE 57
#define MODELINDEX_POINTWHITE 58
#define MODELINDEX_POINTRED 59
#define MODELINDEX_POINTBLUE 60
#define WEAPONINDEX_GAUNTLET 1
#define WEAPONINDEX_MACHINEGUN 2
#define WEAPONINDEX_SHOTGUN 3
#define WEAPONINDEX_GRENADE_LAUNCHER 4
#define WEAPONINDEX_ROCKET_LAUNCHER 5
#define WEAPONINDEX_LIGHTNING 6
#define WEAPONINDEX_RAILGUN 7
#define WEAPONINDEX_PLASMAGUN 8
#define WEAPONINDEX_BFG 9
#define WEAPONINDEX_GRAPPLING_HOOK 10
#define WEAPONINDEX_NAILGUN 11
#define WEAPONINDEX_PROXLAUNCHER 12
#define WEAPONINDEX_CHAINGUN 13
//enemy stuff
#define ENEMY_HORIZONTAL_DIST 200
#define ENEMY_HEIGHT 201
#define MAX_AVOIDGOALS 256
#define MAX_GOALSTACK 8
#define GFL_NONE 0
#define GFL_ITEM 1
#define GFL_ROAM 2
#define GFL_DROPPED 4
#define BLERR_NOERROR 0 //no error
#define BLERR_LIBRARYNOTSETUP 1 //library not setup
#define BLERR_INVALIDENTITYNUMBER 2 //invalid entity number
#define BLERR_NOAASFILE 3 //no AAS file available
#define BLERR_CANNOTOPENAASFILE 4 //cannot open AAS file
#define BLERR_WRONGAASFILEID 5 //incorrect AAS file id
#define BLERR_WRONGAASFILEVERSION 6 //incorrect AAS file version
#define BLERR_CANNOTREADAASLUMP 7 //cannot read AAS file lump
#define BLERR_CANNOTLOADICHAT 8 //cannot load initial chats
#define BLERR_CANNOTLOADITEMWEIGHTS 9 //cannot load item weights
#define BLERR_CANNOTLOADITEMCONFIG 10 //cannot load item config
#define BLERR_CANNOTLOADWEAPONWEIGHTS 11 //cannot load weapon weights
#define BLERR_CANNOTLOADWEAPONCONFIG 12 //cannot load weapon config
#define WT_BALANCE 1
#define MAX_WEIGHTS 128
//fuzzy seperator
struct fuzzyseperator_t
{
fuzzyseperator_t()
{
Reset();
}
void Reset()
{
inUse = false;
index = 0;
value = 0;
type = 0;
weight = 0;
minweight = 0.0f;
maxweight = 0.0f;
child = nullptr;
next = nullptr;
}
bool inUse;
int index;
int value;
int type;
float weight;
float minweight;
float maxweight;
fuzzyseperator_t* child;
fuzzyseperator_t* next;
};
//fuzzy weight
struct weight_t
{
weight_t()
{
Reset();
}
void Reset()
{
name.Clear();
firstseperator = nullptr;
}
idStr name;
fuzzyseperator_t* firstseperator;
};
//weight configuration
struct weightconfig_t
{
weightconfig_t()
{
Reset();
}
void Reset()
{
inUse = false;
numweights = 0;
filename.Clear();
for( int i = 0; i < MAX_WEIGHTS; i++ )
{
weights[i].Reset();
}
}
bool inUse;
int numweights;
weight_t weights[MAX_WEIGHTS];
idStr filename;
};
// ------------------------------------------------------------------------------------
#define BOTFILESBASEFOLDER "botfiles"
//debug line colors
#define LINECOLOR_NONE -1
#define LINECOLOR_RED 1//0xf2f2f0f0L
#define LINECOLOR_GREEN 2//0xd0d1d2d3L
#define LINECOLOR_BLUE 3//0xf3f3f1f1L
#define LINECOLOR_YELLOW 4//0xdcdddedfL
#define LINECOLOR_ORANGE 5//0xe0e1e2e3L
//Print types
#define PRT_MESSAGE 1
#define PRT_WARNING 2
#define PRT_ERROR 3
#define PRT_FATAL 4
#define PRT_EXIT 5
//console message types
#define CMS_NORMAL 0
#define CMS_CHAT 1
//action flags
#define ACTION_ATTACK 0x0000001
#define ACTION_USE 0x0000002
#define ACTION_RESPAWN 0x0000008
#define ACTION_JUMP 0x0000010
#define ACTION_MOVEUP 0x0000020
#define ACTION_CROUCH 0x0000080
#define ACTION_MOVEDOWN 0x0000100
#define ACTION_MOVEFORWARD 0x0000200
#define ACTION_MOVEBACK 0x0000800
#define ACTION_MOVELEFT 0x0001000
#define ACTION_MOVERIGHT 0x0002000
#define ACTION_DELAYEDJUMP 0x0008000
#define ACTION_TALK 0x0010000
#define ACTION_GESTURE 0x0020000
#define ACTION_WALK 0x0080000
#define ACTION_AFFIRMATIVE 0x0100000
#define ACTION_NEGATIVE 0x0200000
#define ACTION_GETFLAG 0x0800000
#define ACTION_GUARDBASE 0x1000000
#define ACTION_PATROL 0x2000000
#define ACTION_FOLLOWME 0x8000000
//#define DEBUG
#define CTF
#define MAX_ITEMS 256
//bot flags
#define BFL_STRAFERIGHT 1 //strafe to the right
#define BFL_ATTACKED 2 //bot has attacked last ai frame
#define BFL_ATTACKJUMPED 4 //bot jumped during attack last frame
#define BFL_AIMATENEMY 8 //bot aimed at the enemy this frame
#define BFL_AVOIDRIGHT 16 //avoid obstacles by going to the right
#define BFL_IDEALVIEWSET 32 //bot has ideal view angles set
#define BFL_FIGHTSUICIDAL 64 //bot is in a suicidal fight
//long term goal types
#define LTG_TEAMHELP 1 //help a team mate
#define LTG_TEAMACCOMPANY 2 //accompany a team mate
#define LTG_DEFENDKEYAREA 3 //defend a key area
#define LTG_GETFLAG 4 //get the enemy flag
#define LTG_RUSHBASE 5 //rush to the base
#define LTG_RETURNFLAG 6 //return the flag
#define LTG_CAMP 7 //camp somewhere
#define LTG_CAMPORDER 8 //ordered to camp somewhere
#define LTG_PATROL 9 //patrol
#define LTG_GETITEM 10 //get an item
#define LTG_KILL 11 //kill someone
#define LTG_HARVEST 12 //harvest skulls
#define LTG_ATTACKENEMYBASE 13 //attack the enemy base
#define LTG_MAKELOVE_UNDER 14
#define LTG_MAKELOVE_ONTOP 15
//some goal dedication times
#define TEAM_HELP_TIME 60 //1 minute teamplay help time
#define TEAM_ACCOMPANY_TIME 600 //10 minutes teamplay accompany time
#define TEAM_DEFENDKEYAREA_TIME 600 //10 minutes ctf defend base time
#define TEAM_CAMP_TIME 600 //10 minutes camping time
#define TEAM_PATROL_TIME 600 //10 minutes patrolling time
#define TEAM_LEAD_TIME 600 //10 minutes taking the lead
#define TEAM_GETITEM_TIME 60 //1 minute
#define TEAM_KILL_SOMEONE 180 //3 minute to kill someone
#define TEAM_ATTACKENEMYBASE_TIME 600 //10 minutes
#define TEAM_HARVEST_TIME 120 //2 minutes
#define CTF_GETFLAG_TIME 600 //10 minutes ctf get flag time
#define CTF_RUSHBASE_TIME 120 //2 minutes ctf rush base time
#define CTF_RETURNFLAG_TIME 180 //3 minutes to return the flag
#define CTF_ROAM_TIME 60 //1 minute ctf roam time
//patrol flags
#define PATROL_LOOP 1
#define PATROL_REVERSE 2
#define PATROL_BACK 4
//teamplay task preference
#define TEAMTP_DEFENDER 1
#define TEAMTP_ATTACKER 2
//CTF strategy
#define CTFS_AGRESSIVE 1
//copied from the aas file header
#define PRESENCE_NONE 1
#define PRESENCE_NORMAL 2
#define PRESENCE_CROUCH 4
//
#define MAX_PROXMINES 64
#define MAX_CHARACTERISTICS 80
#define CT_INTEGER 1
#define CT_FLOAT 2
#define CT_STRING 3
#define DEFAULT_CHARACTER "bots/default_c.c"
#define MAX_AVOIDGOALS 256
#define MAX_GOALSTACK 8
#define GFL_NONE 0
#define GFL_ITEM 1
#define GFL_ROAM 2
#define GFL_DROPPED 4
#define MAX_EPAIRKEY 128
//characteristic value
struct cvalue
{
cvalue()
{
integer = 0;
_float = 0.0f;
string = "";
}
int integer;
float _float;
idStr string;
};
//a characteristic
struct bot_characteristic_t
{
bot_characteristic_t()
{
type = 0;
}
char type; //characteristic type
cvalue value; //characteristic value
};
//a bot character
struct bot_character_t
{
bot_character_t()
{
filename = "";
inUse = false;
skill = 0.0f;
}
idStr filename;
bool inUse;
float skill;
bot_characteristic_t c[MAX_CHARACTERISTICS];
};
//the bot input, will be converted to an usercmd_t
//the bot input, will be converted to an usercmd_t
struct bot_input_t
{
bot_input_t()
{
Reset();
}
void Reset()
{
thinktime = 0;
dir.Zero();
speed = 0;
viewangles.Zero();
actionflags = 0;
weapon = 0;
lastWeaponNum = 0;
respawn = false;
}
float thinktime; //time since last output (in seconds)
idVec3 dir; //movement direction
float speed; //speed in the range [0, 400]
idAngles viewangles; //the view angles
int actionflags; //one of the ACTION_? flags
int weapon; //weapon to use
int lastWeaponNum;
bool respawn;
};
#if 0
//entity state
typedef struct bot_entitystate_s
{
int type; // entity type
int flags; // entity flags
vec3_t origin; // origin of the entity
vec3_t angles; // angles of the model
vec3_t old_origin; // for lerping
vec3_t mins; // bounding box minimums
vec3_t maxs; // bounding box maximums
int groundent; // ground entity
int solid; // solid type
int modelindex; // model used
int modelindex2; // weapons, CTF flags, etc
int frame; // model frame number
int event; // impulse events -- muzzle flashes, footsteps, etc
int eventParm; // even parameter
int powerups; // bit flags
int weapon; // determines weapon and flash model, etc
int legsAnim; // mask off ANIM_TOGGLEBIT
int torsoAnim; // mask off ANIM_TOGGLEBIT
} bot_entitystate_t;
//check points
typedef struct bot_waypoint_s
{
int inuse;
char name[32];
bot_goal_t goal;
struct bot_waypoint_s* next, * prev;
} bot_waypoint_t;
//bot settings
typedef struct bot_settings_s
{
char characterfile[MAX_QPATH];
float skill;
char team[MAX_QPATH];
} bot_settings_t;
#define MAX_ACTIVATESTACK 8
#define MAX_ACTIVATEAREAS 32
typedef struct bot_activategoal_s
{
int inuse;
bot_goal_t goal; //goal to activate (buttons etc.)
float time; //time to activate something
float start_time; //time starting to activate something
float justused_time; //time the goal was used
int shoot; //true if bot has to shoot to activate
int weapon; //weapon to be used for activation
vec3_t target; //target to shoot at to activate something
vec3_t origin; //origin of the blocking entity to activate
int areas[MAX_ACTIVATEAREAS]; //routing areas disabled by blocking entity
int numareas; //number of disabled routing areas
int areasdisabled; //true if the areas are disabled for the routing
struct bot_activategoal_s* next; //next activate goal on stack
} bot_activategoal_t;
//bot state
typedef struct bot_state_s
{
int inuse; //true if this state is used by a bot client
int botthink_residual; //residual for the bot thinks
int client; //client number of the bot
int entitynum; //entity number of the bot
playerState_t cur_ps; //current player state
int last_eFlags; //last ps flags
usercmd_t lastucmd; //usercmd from last frame
int entityeventTime[1024]; //last entity event time
//
bot_settings_t settings; //several bot settings
int ( *ainode )( struct bot_state_s* bs ); //current AI node
float thinktime; //time the bot thinks this frame
vec3_t origin; //origin of the bot
vec3_t velocity; //velocity of the bot
int presencetype; //presence type of the bot
vec3_t eye; //eye coordinates of the bot
int areanum; //the number of the area the bot is in
int inventory[MAX_ITEMS]; //string with items amounts the bot has
int tfl; //the travel flags the bot uses
int flags; //several flags
int respawn_wait; //wait until respawned
int lasthealth; //health value previous frame
int lastkilledplayer; //last killed player
int lastkilledby; //player that last killed this bot
int botdeathtype; //the death type of the bot
int enemydeathtype; //the death type of the enemy
int botsuicide; //true when the bot suicides
int enemysuicide; //true when the enemy of the bot suicides
int setupcount; //true when the bot has just been setup
int map_restart; //true when the map is being restarted
int entergamechat; //true when the bot used an enter game chat
int num_deaths; //number of time this bot died
int num_kills; //number of kills of this bot
int revenge_enemy; //the revenge enemy
int revenge_kills; //number of kills the enemy made
int lastframe_health; //health value the last frame
int lasthitcount; //number of hits last frame
int chatto; //chat to all or team
float walker; //walker charactertic
float ltime; //local bot time
float entergame_time; //time the bot entered the game
float ltg_time; //long term goal time
float nbg_time; //nearby goal time
float respawn_time; //time the bot takes to respawn
float respawnchat_time; //time the bot started a chat during respawn
float chase_time; //time the bot will chase the enemy
float enemyvisible_time; //time the enemy was last visible
float check_time; //time to check for nearby items
float stand_time; //time the bot is standing still
float lastchat_time; //time the bot last selected a chat
float kamikaze_time; //time to check for kamikaze usage
float invulnerability_time; //time to check for invulnerability usage
float standfindenemy_time; //time to find enemy while standing
float attackstrafe_time; //time the bot is strafing in one dir
float attackcrouch_time; //time the bot will stop crouching
float attackchase_time; //time the bot chases during actual attack
float attackjump_time; //time the bot jumped during attack
float enemysight_time; //time before reacting to enemy
float enemydeath_time; //time the enemy died
float enemyposition_time; //time the position and velocity of the enemy were stored
float defendaway_time; //time away while defending
float defendaway_range; //max travel time away from defend area
float rushbaseaway_time; //time away from rushing to the base
float attackaway_time; //time away from attacking the enemy base
float harvestaway_time; //time away from harvesting
float ctfroam_time; //time the bot is roaming in ctf
float killedenemy_time; //time the bot killed the enemy
float arrive_time; //time arrived (at companion)
float lastair_time; //last time the bot had air
float teleport_time; //last time the bot teleported
float camp_time; //last time camped
float camp_range; //camp range
float weaponchange_time; //time the bot started changing weapons
float firethrottlewait_time; //amount of time to wait
float firethrottleshoot_time; //amount of time to shoot
float notblocked_time; //last time the bot was not blocked
float blockedbyavoidspot_time; //time blocked by an avoid spot
float predictobstacles_time; //last time the bot predicted obstacles
int predictobstacles_goalareanum; //last goal areanum the bot predicted obstacles for
vec3_t aimtarget;
vec3_t enemyvelocity; //enemy velocity 0.5 secs ago during battle
vec3_t enemyorigin; //enemy origin 0.5 secs ago during battle
//
int kamikazebody; //kamikaze body
int proxmines[MAX_PROXMINES];
int numproxmines;
//
bot_character_t* character; //the bot character
int ms; //move state of the bot
int gs; //goal state of the bot
int cs; //chat state of the bot
int ws; //weapon state of the bot
//
int enemy; //enemy entity number
int lastenemyareanum; //last reachability area the enemy was in
vec3_t lastenemyorigin; //last origin of the enemy in the reachability area
int weaponnum; //current weapon number
vec3_t viewangles; //current view angles
vec3_t ideal_viewangles; //ideal view angles
vec3_t viewanglespeed;
//
int ltgtype; //long term goal type
// team goals
int teammate; //team mate involved in this team goal
int decisionmaker; //player who decided to go for this goal
int ordered; //true if ordered to do something
float order_time; //time ordered to do something
int owndecision_time; //time the bot made it's own decision
bot_goal_t teamgoal; //the team goal
bot_goal_t altroutegoal; //alternative route goal
float reachedaltroutegoal_time; //time the bot reached the alt route goal
float teammessage_time; //time to message team mates what the bot is doing
float teamgoal_time; //time to stop helping team mate
float teammatevisible_time; //last time the team mate was NOT visible
int teamtaskpreference; //team task preference
// last ordered team goal
int lastgoal_decisionmaker;
int lastgoal_ltgtype;
int lastgoal_teammate;
bot_goal_t lastgoal_teamgoal;
// for leading team mates
int lead_teammate; //team mate the bot is leading
bot_goal_t lead_teamgoal; //team goal while leading
float lead_time; //time leading someone
float leadvisible_time; //last time the team mate was visible
float leadmessage_time; //last time a messaged was sent to the team mate
float leadbackup_time; //time backing up towards team mate
//
char teamleader[32]; //netname of the team leader
float askteamleader_time; //time asked for team leader
float becometeamleader_time; //time the bot will become the team leader
float teamgiveorders_time; //time to give team orders
float lastflagcapture_time; //last time a flag was captured
int numteammates; //number of team mates
int redflagstatus; //0 = at base, 1 = not at base
int blueflagstatus; //0 = at base, 1 = not at base
int neutralflagstatus; //0 = at base, 1 = our team has flag, 2 = enemy team has flag, 3 = enemy team dropped the flag
int flagstatuschanged; //flag status changed
int forceorders; //true if forced to give orders
int flagcarrier; //team mate carrying the enemy flag
int ctfstrategy; //ctf strategy
char subteam[32]; //sub team name
float formation_dist; //formation team mate intervening space
char formation_teammate[16]; //netname of the team mate the bot uses for relative positioning
float formation_angle; //angle relative to the formation team mate
vec3_t formation_dir; //the direction the formation is moving in
vec3_t formation_origin; //origin the bot uses for relative positioning
bot_goal_t formation_goal; //formation goal
bot_activategoal_t* activatestack; //first activate goal on the stack
bot_activategoal_t activategoalheap[MAX_ACTIVATESTACK]; //activate goal heap
bot_waypoint_t* checkpoints; //check points
bot_waypoint_t* patrolpoints; //patrol points
bot_waypoint_t* curpatrolpoint; //current patrol point the bot is going for
int patrolflags; //patrol flags
// jmarshall
bot_goal_t currentgoal;
vec3_t currentMoveGoal;
vec3_t movement_waypoints[NAV_MAX_PATHSTEPS];
int numMovementWaypoints;
int currentWaypoint;
vec3_t last_origin;
vec3_t very_short_term_origin;
int stuck_time;
vec3_t last_enemy_visible_position;
vec3_t random_move_position;
// jmarshall end
bot_input_t input;
} bot_state_t;
void BotUpdateInput( bot_state_t* bs, int time, int elapsed_time );
qboolean BotIsDead( bot_state_t* bs );
void AIEnter_Respawn( bot_state_t* bs, char* s );
extern float floattime;
#define FloatTime() floattime
float Characteristic_BFloat( bot_character_t* ch, int index, float min, float max );
void Characteristic_String( bot_character_t* ch, int index, char* buf, int size );
bot_character_t* BotLoadCharacterFromFile( char* charfile, int skill );
void BotInitLevelItems( void );
void BotChooseWeapon( bot_state_t* bs );
inline float AAS_Time()
{
return floattime;
}
unsigned short int BotTravelTime( vec3_t start, vec3_t end );
#endif
#define MAX_BOT_INVENTORY 256
typedef enum
{
NULLMOVEFLAG = -1,
MOVE_PRONE,
MOVE_CROUCH,
MOVE_WALK,
MOVE_RUN2,
MOVE_SPRINT,
MOVE_JUMP,
} botMoveFlags_t;
//
// rvmBotUtil
//
class rvmBotUtil
{
public:
static float random()
{
return ( ( rand() & 0x7fff ) / ( ( float )0x7fff ) );
}
static float crandom()
{
return ( 2.0 * ( random() - 0.5 ) );
}
};
#include "Bot_char.h"
#include "Bot_weights.h"
#include "Bot_weapons.h"
#include "Bot_goal.h"
struct bot_state_t
{
bot_state_t()
{
character = NULL;
gs = 0;
ws = 0;
Reset();
}
void Reset()
{
attackerEntity = NULL;
client = 0;
entitynum = 0;
setupcount = 0;
entergame_time = 0;
weaponnum = 0;
lasthealth = 0;
ltg_time = 0;
weaponchange_time = 0;
enemy = 0;
enemyvisible_time = 0;
enemysuicide = 0;
enemysight_time = 0;
check_time = 0;
nbg_time = 0;
enemydeath_time = 0;
teleport_time = 0;
flags = 0;
firethrottlewait_time = 0;
attackchase_time = 0;
attackcrouch_time = 0;
attackstrafe_time = 0;
attackjump_time = 0;
firethrottleshoot_time = 0;
chase_time = 0;
thinktime = 0;
useRandomPosition = false;
aimtarget.Zero();
lastenemyorigin.Zero();
origin.Zero();
enemyorigin.Zero();
random_move_position.Zero();
last_enemy_visible_position.Zero();
viewangles.Zero();
eye.Zero();
memset( &inventory[0], 0, sizeof( inventory ) );
}
bot_character_t* character;
int gs;
int ws;
int enemy;
int client;
idEntity* attackerEntity;
int lasthealth;
int entitynum;
int setupcount;
int ltg_time;
int flags;
int weaponnum;
bool useRandomPosition;
float thinktime;
float chase_time;
float attackjump_time;
float attackcrouch_time;
float attackstrafe_time;
float attackchase_time;
float firethrottlewait_time;
float firethrottleshoot_time;
float nbg_time; //nearby goal time
float entergame_time;
float weaponchange_time;
float check_time;
float teleport_time;
float enemyvisible_time; //time the enemy was last visible
int enemysuicide; //true when the enemy of the bot suicides
float enemysight_time; //time before reacting to enemy
float enemydeath_time; //time the enemy died
float aggressiveAttackTime;
idVec3 origin;
idVec3 aimtarget;
idVec3 random_move_position;
idVec3 last_enemy_visible_position;
idAngles viewangles;
idVec3 enemyorigin;
idVec3 eye;
idVec3 lastenemyorigin;
int inventory[MAX_BOT_INVENTORY];
bot_goal_t currentGoal;
bot_input_t botinput;
};
#include "Bot_chat.h"
#define Bot_Time() ((float)gameLocal.time / 1000.0f)
//
// rvmBot
//
class rvmBot : public idPlayer
{
public:
friend class rvmBotAI;
CLASS_PROTOTYPE( rvmBot );
rvmBot();
~rvmBot();
void Spawn( void );
virtual void Think( void ) override;
virtual void SpawnToPoint( const idVec3& spawn_origin, const idAngles& spawn_angles ) override;
virtual void Damage( idEntity* inflictor, idEntity* attacker, const idVec3& dir, const char* damageDefName, const float damageScale, const int location ) override;
virtual void InflictedDamageEvent(idEntity* target) override;
virtual void StateThreadChanged(void) override;
void SetEnemy( idPlayer* player, idVec3 origin );
void BotInputFrame( idUserCmdMgr& cmdMgr );
void Bot_ResetUcmd( usercmd_t& ucmd );
static void PresenceTypeBoundingBox( int presencetype, idVec3& mins, idVec3& maxs );
private:
void BotSendChatMessage(botChat_t chat, const char *targetName);
void BotInputToUserCommand( bot_input_t* bi, usercmd_t* ucmd, int time );
void BotMoveToGoalOrigin( idVec3 goalOrigin );
void ServerThink( void );
void BotUpdateInventory( void );
bool HasWeapon( int index )
{
return inventory.weapons & ( 1 << index );
}
private:
bot_state_t bs;
bool hasSpawned;
private:
int weapon_machinegun;
int weapon_shotgun;
int weapon_plasmagun;
int weapon_rocketlauncher;
protected:
bool BotIsDead(bot_state_t* bs);
bool BotReachedGoal(bot_state_t* bs, bot_goal_t* goal);
int BotGetItemLongTermGoal(bot_state_t* bs, int tfl, bot_goal_t* goal);
void BotChooseWeapon(bot_state_t* bs);
int BotFindEnemy(bot_state_t* bs, int curenemy);
bool EntityIsDead(idEntity* entity);
float BotEntityVisible(int viewer, idVec3 eye, idAngles viewangles, float fov, int ent);
float BotEntityVisibleTest(int viewer, idVec3 eye, idAngles viewangles, float fov, int ent, bool allowHeightTest);
void BotUpdateBattleInventory(bot_state_t* bs, int enemy);
float BotAggression(bot_state_t* bs);
int BotWantsToRetreat(bot_state_t* bs);
void BotBattleUseItems(bot_state_t* bs);
void BotAimAtEnemy(bot_state_t* bs);
void BotCheckAttack(bot_state_t* bs);
bool BotWantsToChase(bot_state_t* bs);
int BotNearbyGoal(bot_state_t* bs, int tfl, bot_goal_t* ltg, float range);
void BotGetRandomPointNearPosition(idVec3 point, idVec3& randomPoint, float radius);
int BotMoveInRandomDirection(bot_state_t* bs);
void BotMoveToGoal(bot_state_t* bs, bot_goal_t* goal);
void MoveToCoverPoint(void);
static int WP_MACHINEGUN;
static int WP_SHOTGUN;
static int WP_PLASMAGUN;
static int WP_ROCKET_LAUNCHER;
private:
stateResult_t state_Chase(stateParms_t* parms);
stateResult_t state_BattleFight(stateParms_t* parms);
stateResult_t state_BattleNBG(stateParms_t* parms);
stateResult_t state_Retreat(stateParms_t* parms);
stateResult_t state_Respawn(stateParms_t* parms);
stateResult_t state_SeekNBG(stateParms_t* parms);
stateResult_t state_SeekLTG(stateParms_t* parms);
stateResult_t state_Attacked(stateParms_t* parms);
private:
idAAS* aas;
};
extern idCVar bot_skill;
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,50 @@
// BotAI_Battle_Attacked.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
/*
==================
rvmBot::state_Attacked
==================
*/
stateResult_t rvmBot::state_Attacked(stateParms_t* parms) {
// respawn if dead.
if (BotIsDead(&bs))
{
stateThread.SetState("state_Respawn");
return SRESULT_DONE_FRAME;
}
if (gameLocal.SysScriptTime() > bs.aggressiveAttackTime || bs.weaponnum == 0) {
stateThread.SetState("state_Retreat");
return SRESULT_DONE;
}
// Ensure the target is a player.
idPlayer *entinfo = gameLocal.entities[bs.enemy]->Cast<idPlayer>();
if (!entinfo)
{
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
// If our enemy is dead, search for another LTG.
if (EntityIsDead(entinfo))
{
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
bs.currentGoal.origin = bs.lastenemyorigin;
//aim at the enemy
BotAimAtEnemy(&bs);
//attack the enemy if possible
BotCheckAttack(&bs);
return SRESULT_WAIT;
}
+208
View File
@@ -0,0 +1,208 @@
// BotAI_Battle_Chase.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
/*
=====================
rvmBot::state_Chase
=====================
*/
stateResult_t rvmBot::state_Chase(stateParms_t* parms)
{
bot_goal_t goal;
idVec3 target, dir;
//bot_moveresult_t moveresult;
float range;
//if (BotIsObserver(bs)) {
// AIEnter_Observer(bs, "battle chase: observer");
// return qfalse;
//}
//
////if in the intermission
//if (BotIntermission(bs)) {
// AIEnter_Intermission(bs, "battle chase: intermission");
// return qfalse;
//}
// respawn if dead.
if( BotIsDead( &bs ) )
{
stateThread.SetState("state_Respawn");
return SRESULT_DONE_FRAME;
}
//if no enemy
if( bs.enemy < 0 )
{
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
//if the enemy is visible
if( BotEntityVisibleTest( bs.entitynum, bs.eye, bs.viewangles, 360, bs.enemy, false ) )
{
//AIEnter_Battle_Fight(bs, "battle chase");
stateThread.SetState("state_BattleFight");
return SRESULT_DONE_FRAME;
}
//if there is another enemy
if( BotFindEnemy( &bs, -1 ) )
{
//AIEnter_Battle_Fight(bs, "battle chase: better enemy");
//stateThread.SetState("state_BattleFight");
stateThread.SetState("state_BattleFight");
return SRESULT_DONE_FRAME;
}
////there is no last enemy area
//if (!bs.lastenemyareanum) {
// AIEnter_Seek_LTG(bs, "battle chase: no enemy area");
// return qfalse;
//}
// jmarshall
//
//bs.tfl = TFL_DEFAULT;
//if (bot_grapple.integer) bs.tfl |= TFL_GRAPPLEHOOK;
////if in lava or slime the bot should be able to get out
//if (BotInLavaOrSlime(bs)) bs.tfl |= TFL_LAVA | TFL_SLIME;
////
//if (BotCanAndWantsToRocketJump(bs)) {
// bs.tfl |= TFL_ROCKETJUMP;
//}
//map specific code
//BotMapScripts(bs);
// jmarshall end
//create the chase goal
goal.entitynum = bs.enemy;
// goal.areanum = bs.lastenemyareanum;
VectorCopy( bs.lastenemyorigin, goal.origin );
goal.mins = idMath::CreateVector( -8, -8, -8 );
goal.maxs = idMath::CreateVector( 8, 8, 8 );
// jmarshall - goal origin is last visible position
{
// Do a trace between the last_enemy_visible_position and the goal origin,
// if for some reason we don't have line of sight to it, switch to LTG.
trace_t trace;
gameLocal.Trace( trace, bs.last_enemy_visible_position, gameLocal.entities[bs.client]->GetOrigin(), CONTENTS_SOLID, 0 );
if( trace.fraction <= 0.9f )
{
//AIEnter_Seek_LTG(bs, "can't see last enemy position");
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
}
VectorCopy( bs.last_enemy_visible_position, goal.origin );
// jmarshall end
//if the last seen enemy spot is reached the enemy could not be found
if( botGoalManager.BotTouchingGoal( bs.origin, &goal ) )
{
bs.chase_time = 0;
}
//if there's no chase time left
if( !bs.chase_time || bs.chase_time < Bot_Time() - 10 )
{
//AIEnter_Seek_LTG(bs, "battle chase: time out");
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
//check for nearby goals periodicly
if( bs.check_time < Bot_Time() )
{
bs.check_time = Bot_Time() + 1;
range = 150;
//
if( BotNearbyGoal( &bs, 0, &goal, range ) )
{
//the bot gets 5 seconds to pick up the nearby goal item
bs.nbg_time = Bot_Time() + 0.1 * range + 1;
//BotResetLastAvoidReach(bs.ms);
//AIEnter_Battle_NBG(bs, "battle chase: nbg");
stateThread.SetState("state_BattleNBG");
return SRESULT_DONE_FRAME;
}
}
BotUpdateBattleInventory( &bs, bs.enemy );
////initialize the movement state
//BotSetupForMovement(bs);
//move towards the goal
//trap_BotMoveToGoal(&moveresult, bs.ms, &goal, bs.tfl);
if( idMath::FRandRange( 0.0f, 4.0f ) <= 2.0f )
{
BotMoveToGoal( &bs, &goal );
}
else
{
BotMoveInRandomDirection( &bs );
}
//if the movement failed
//if (moveresult.failure) {
// //reset the avoid reach, otherwise bot is stuck in current area
// trap_BotResetAvoidReach(bs.ms);
// //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
// bs.ltg_time = 0;
//}
////
//BotAIBlocked(bs, &moveresult, qfalse);
//
//if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET | MOVERESULT_MOVEMENTVIEW | MOVERESULT_SWIMVIEW)) {
// VectorCopy(moveresult.ideal_viewangles, bs.ideal_viewangles);
//}
if( !( bs.flags & BFL_IDEALVIEWSET ) )
{
BotAimAtEnemy( &bs );
// jmarshall
//if (bs.chase_time > FloatTime() - 2) {
// BotAimAtEnemy(bs);
//}
//else {
// if (BotMovementViewTarget(bs.ms, &goal, bs.tfl, 300, target)) {
// VectorSubtract(target, bs.origin, dir);
// vectoangles(dir, bs.viewangles);
// }
// //else {
// // vectoangles(moveresult.movedir, bs.ideal_viewangles);
// //}
//}
// jmarshall end
// bs.ideal_viewangles[2] *= 0.5; // jmarshall <-- view angles!
}
if (BotEntityVisible(bs.entitynum, bs.eye, bs.viewangles, 360, bs.enemy))
{
//attack the enemy if possible
BotCheckAttack(&bs);
}
//if the weapon is used for the bot movement
//if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs.weaponnum = moveresult.weapon;
//if the bot is in the area the enemy was last seen in
//if (bs.areanum == bs.lastenemyareanum) bs.chase_time = 0;
//if the bot wants to retreat (the bot could have been damage during the chase)
if( BotWantsToRetreat( &bs ) )
{
//AIEnter_Battle_Retreat(bs, "battle chase: wants to retreat");
stateThread.SetState("state_Retreat");
return SRESULT_DONE_FRAME;
}
return SRESULT_WAIT;
}
+168
View File
@@ -0,0 +1,168 @@
// BotAI_Battle_Fight.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
/*
=====================
rvmBot::state_BattleFight
=====================
*/
stateResult_t rvmBot::state_BattleFight(stateParms_t* parms)
{
int areanum;
idVec3 target;
idPlayer* entinfo;
// respawn if dead.
if( BotIsDead( &bs ) )
{
stateThread.SetState("state_Respawn");
return SRESULT_DONE_FRAME;
}
//if there is another better enemy
if( BotFindEnemy( &bs, bs.enemy ) )
{
common->DPrintf( "found new better enemy\n" );
}
//if no enemy
if( bs.enemy < 0 )
{
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
//BotEntityInfo(bs.enemy, &entinfo);
entinfo = gameLocal.entities[bs.enemy]->Cast<idPlayer>();// &g_entities[bs.enemy];
//if the enemy is dead
if( bs.enemydeath_time )
{
if( bs.enemydeath_time < Bot_Time() - 1.0 )
{
bs.enemydeath_time = 0;
if( bs.enemysuicide )
{
// jmarshall - bot chat
//BotChat_EnemySuicide(bs);
// jmarshall end
}
// jmarshall - bot chat stand
// if (bs.lastkilledplayer == bs.enemy && BotChat_Kill(bs)) {
// bs.stand_time = FloatTime() + BotChatTime(bs);
// AIEnter_Stand(bs, "battle fight: enemy dead");
// }
// else {
bs.ltg_time = 0;
//AIEnter_Seek_LTG(bs, "battle fight: enemy dead");
stateThread.SetState("state_SeekLTG");
// }
// jmarshall end
return SRESULT_DONE_FRAME;
}
}
else
{
if( EntityIsDead( entinfo ) )
{
bs.enemydeath_time = Bot_Time();
}
}
// jmarshall - isinvisible
//if the enemy is invisible and not shooting the bot looses track easily
//if (entinfo->IsInvisible() && !entinfo->IsShooting()) {
// if (rvmBotUtil::random() < 0.2) {
// stateThread.SetState("state_SeekLTG");
// return;
// }
//}
//
target = entinfo->GetOrigin();
//update the reachability area and origin if possible
//areanum = BotPointAreaNum(target);
//if (areanum && trap_AAS_AreaReachability(areanum)) {
// VectorCopy(target, bs.lastenemyorigin);
// bs.lastenemyareanum = areanum;
//}
// bs.lastenemyareanum = areanum;
//update the attack inventory values
BotUpdateBattleInventory( &bs, bs.enemy );
//if the bot's health decreased
// jmarshall - bot chat
//if (bs.lastframe_health > bs.inventory[INVENTORY_HEALTH]) {
// if (BotChat_HitNoDeath(bs)) {
// bs.stand_time = FloatTime() + BotChatTime(bs);
// AIEnter_Stand(bs, "battle fight: chat health decreased");
// return qfalse;
// }
//}
//if the bot hit someone
//if (bs.cur_ps.persistant[PERS_HITS] > bs.lasthitcount) {
// if (BotChat_HitNoKill(bs)) {
// bs.stand_time = FloatTime() + BotChatTime(bs);
// AIEnter_Stand(bs, "battle fight: chat hit someone");
// return qfalse;
// }
//}
// jmarshall end
//if the enemy is not visible
if( !BotEntityVisible( bs.entitynum, bs.eye, bs.viewangles, 360, bs.enemy ) )
{
if( BotWantsToChase( &bs ) )
{
//AIEnter_Battle_Chase(bs, "battle fight: enemy out of sight");
stateThread.SetState("state_Chase");
return SRESULT_DONE_FRAME;
}
else
{
//AIEnter_Seek_LTG(bs, "battle fight: enemy out of sight");
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
}
//use holdable items
BotBattleUseItems( &bs );
//
//bs.tfl = TFL_DEFAULT;
//if (bot_grapple.integer) bs.tfl |= TFL_GRAPPLEHOOK;
////if in lava or slime the bot should be able to get out
//if (BotInLavaOrSlime(bs)) bs.tfl |= TFL_LAVA | TFL_SLIME;
////
//if (BotCanAndWantsToRocketJump(bs)) {
// bs.tfl |= TFL_ROCKETJUMP;
//}
//choose the best weapon to fight with
BotChooseWeapon( &bs );
// Move randomly around our AAS area.
BotMoveInRandomDirection(&bs);
//aim at the enemy
BotAimAtEnemy( &bs );
//attack the enemy if possible
BotCheckAttack( &bs );
//if the bot wants to retreat
if( !( bs.flags & BFL_FIGHTSUICIDAL ) )
{
if( BotWantsToRetreat( &bs ) )
{
//AIEnter_Battle_Retreat(bs, "battle fight: wants to retreat");
stateThread.SetState("state_Retreat");
return SRESULT_DONE_FRAME;
}
}
return SRESULT_WAIT;
}
+178
View File
@@ -0,0 +1,178 @@
// BotAI_Battle_NBG.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
/*
=====================
rvmBot::state_BattleNBG
=====================
*/
stateResult_t rvmBot::state_BattleNBG(stateParms_t* parms)
{
int areanum;
bot_goal_t goal;
//aas_entityinfo_t entinfo;
idEntity* entinfo;
//bot_moveresult_t moveresult;
float attack_skill;
idVec3 target, dir;
//if (BotIsObserver(bs)) {
// AIEnter_Observer(bs, "battle nbg: observer");
// return qfalse;
//}
////if in the intermission
//if (BotIntermission(bs)) {
// AIEnter_Intermission(bs, "battle nbg: intermission");
// return qfalse;
//}
// respawn if dead.
if( BotIsDead( &bs ) )
{
stateThread.SetState("state_Respawn");
return SRESULT_DONE_FRAME;
}
// if no enemy.
if( bs.enemy < 0 )
{
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
//BotEntityInfo(bs.enemy, &entinfo);
entinfo = gameLocal.entities[bs.enemy]->Cast<idPlayer>();
if( entinfo->health <= 0 )
{
//AIEnter_Seek_NBG(bs, "battle nbg: enemy dead");
stateThread.SetState("state_SeekNBG");
return SRESULT_DONE_FRAME;
}
//bs.tfl = TFL_DEFAULT;
//if (bot_grapple.integer) bs.tfl |= TFL_GRAPPLEHOOK;
////if in lava or slime the bot should be able to get out
//if (BotInLavaOrSlime(bs)) bs.tfl |= TFL_LAVA | TFL_SLIME;
////
//if (BotCanAndWantsToRocketJump(bs)) {
// bs.tfl |= TFL_ROCKETJUMP;
//}
////map specific code
//BotMapScripts(bs);
//update the last time the enemy was visible
if( BotEntityVisible( bs.entitynum, bs.eye, bs.viewangles, 360, bs.enemy ) )
{
bs.enemyvisible_time = Bot_Time();
//VectorCopy(entinfo->GetOrigin(), target);
target = entinfo->GetOrigin();
// if not a player enemy
if( bs.enemy >= MAX_CLIENTS )
{
#ifdef MISSIONPACK
// if attacking an obelisk
if( bs.enemy == redobelisk.entitynum ||
bs.enemy == blueobelisk.entitynum )
{
target[2] += 16;
}
#endif
}
//update the reachability area and origin if possible
//areanum = BotPointAreaNum(target);
//if (areanum && trap_AAS_AreaReachability(areanum)) {
VectorCopy( target, bs.lastenemyorigin );
// bs.lastenemyareanum = areanum;
//}
}
//if the bot has no goal or touches the current goal
if( !botGoalManager.BotGetTopGoal( bs.gs, &goal ) )
{
bs.nbg_time = 0;
}
else if( BotReachedGoal( &bs, &goal ) )
{
bs.nbg_time = 0;
}
//
if( bs.nbg_time < Bot_Time() )
{
//pop the current goal from the stack
botGoalManager.BotPopGoal( bs.gs );
//if the bot still has a goal
if( botGoalManager.BotGetTopGoal( bs.gs, &goal ) )
{
//AIEnter_Battle_Retreat(bs, "battle nbg: time out");
stateThread.SetState("state_Retreat");
}
else
{
//AIEnter_Battle_Fight(bs, "battle nbg: time out");
stateThread.SetState("state_BattleFight");
}
return SRESULT_DONE_FRAME;
}
//move towards the goal
BotMoveToGoal( &bs, &goal );
//initialize the movement state
//BotSetupForMovement(bs);
////move towards the goal
//trap_BotMoveToGoal(&moveresult, bs.ms, &goal, bs.tfl);
////if the movement failed
//if (moveresult.failure) {
// //reset the avoid reach, otherwise bot is stuck in current area
// trap_BotResetAvoidReach(bs.ms);
// //BotAI_Print(PRT_MESSAGE, "movement failure %d\n", moveresult.traveltype);
// bs.nbg_time = 0;
//}
////
//BotAIBlocked(bs, &moveresult, qfalse);
//update the attack inventory values
BotUpdateBattleInventory( &bs, bs.enemy );
//choose the best weapon to fight with
BotChooseWeapon( &bs );
//if the view is fixed for the movement
//if (moveresult.flags & (MOVERESULT_MOVEMENTVIEW | MOVERESULT_SWIMVIEW)) {
// VectorCopy(moveresult.ideal_viewangles, bs.ideal_viewangles);
//}
//else if (!(moveresult.flags & MOVERESULT_MOVEMENTVIEWSET)
// && !(bs.flags & BFL_IDEALVIEWSET)) {
// attack_skill = trap_Characteristic_BFloat(bs.character, CHARACTERISTIC_ATTACK_SKILL, 0, 1);
// //if the bot is skilled anough and the enemy is visible
// if (attack_skill > 0.3) {
// //&& BotEntityVisible(bs.entitynum, bs.eye, bs.viewangles, 360, bs.enemy)
// BotAimAtEnemy(bs);
// }
// else {
// if (trap_BotMovementViewTarget(bs.ms, &goal, bs.tfl, 300, target)) {
// VectorSubtract(target, bs.origin, dir);
// vectoangles(dir, bs.ideal_viewangles);
// }
// else {
// vectoangles(moveresult.movedir, bs.ideal_viewangles);
// }
// bs.ideal_viewangles[2] *= 0.5;
// }
//}
//if (attack_skill > 0.3) {
//&& BotEntityVisible(bs.entitynum, bs.eye, bs.viewangles, 360, bs.enemy)
BotAimAtEnemy( &bs );
//}
//if the weapon is used for the bot movement
//if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs.weaponnum = moveresult.weapon;
//attack the enemy if possible
BotCheckAttack( &bs );
return SRESULT_WAIT;
}
@@ -0,0 +1,144 @@
// BotAI_Battle_Retreat.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
/*
=====================
rvmBot::state_Retreat
=====================
*/
stateResult_t rvmBot::state_Retreat(stateParms_t* parms)
{
bot_goal_t goal;
idPlayer* entinfo;
rvmBot* owner;
idVec3 target, dir;
float attack_skill, range;
// respawn if dead.
if( BotIsDead( &bs ) )
{
stateThread.SetState("state_Respawn");
return SRESULT_DONE_FRAME;
}
// if no enemy.
if( bs.enemy < 0 )
{
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
// Ensure the target is a player.
entinfo = gameLocal.entities[bs.enemy]->Cast<idPlayer>();
if( !entinfo )
{
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
owner = gameLocal.entities[bs.entitynum]->Cast<rvmBot>();
// If our enemy is dead, search for another LTG.
if( EntityIsDead( entinfo ) )
{
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
//if there is another better enemy
if( BotFindEnemy( &bs, bs.enemy ) )
{
common->DPrintf( "found new better enemy\n" );
}
//update the attack inventory values
BotUpdateBattleInventory( &bs, bs.enemy );
//if the bot doesn't want to retreat anymore... probably picked up some nice items
if( BotWantsToChase( &bs ) )
{
//empty the goal stack, when chasing, only the enemy is the goal
botGoalManager.BotEmptyGoalStack( bs.gs );
//go chase the enemy
//AIEnter_Battle_Chase(bs, "battle retreat: wants to chase");
stateThread.SetState("state_Chase");
return SRESULT_DONE_FRAME;
}
//update the last time the enemy was visible
if( BotEntityVisible( bs.entitynum, bs.eye, bs.viewangles, 360, bs.enemy ) )
{
bs.enemyvisible_time = Bot_Time();
target = entinfo->GetOrigin();
bs.lastenemyorigin = target;
}
//if the enemy is NOT visible for 4 seconds
if( bs.enemyvisible_time < Bot_Time() - 4 )
{
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
//else if the enemy is NOT visible
else if( bs.enemyvisible_time < Bot_Time() )
{
//if there is another enemy
if( BotFindEnemy( &bs, -1 ) )
{
//AIEnter_Battle_Fight(bs, "battle retreat: another enemy");
stateThread.SetState("state_BattleFight");
return SRESULT_DONE_FRAME;
}
}
//use holdable items
BotBattleUseItems( &bs );
//get the current long term goal while retreating
if( !BotGetItemLongTermGoal( &bs, 0, &bs.currentGoal ) )
{
//AIEnter_Battle_SuicidalFight(bs, "battle retreat: no way out");
stateThread.SetState("state_BattleFight");
bs.flags |= BFL_FIGHTSUICIDAL;
return SRESULT_DONE_FRAME;
}
//check for nearby goals periodicly
if( bs.check_time < Bot_Time() )
{
bs.check_time = Bot_Time() + 1;
range = 150;
//
if( BotNearbyGoal( &bs, 0, &goal, range ) )
{
//trap_BotResetLastAvoidReach(bs.ms);
//time the bot gets to pick up the nearby goal item
bs.nbg_time = Bot_Time() + range / 100 + 1;
//AIEnter_Battle_NBG(bs, "battle retreat: nbg");
stateThread.SetState("state_BattleNBG");
return SRESULT_DONE_FRAME;
}
}
MoveToCoverPoint();
if (bot_skill.GetInteger() > 1)
{
bs.firethrottlewait_time = 0;
}
BotChooseWeapon( &bs );
BotAimAtEnemy( &bs );
//attack the enemy if possible
BotCheckAttack( &bs );
return SRESULT_WAIT;
}
+49
View File
@@ -0,0 +1,49 @@
// BotAI_SeekLTG.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
/*
=====================
rvmBot::state_SeekLTG
=====================
*/
stateResult_t rvmBot::state_SeekLTG(stateParms_t* parms)
{
if( BotIsDead( &bs ) )
{
stateThread.SetState("state_Respawn");
return SRESULT_DONE_FRAME;
}
BotGetItemLongTermGoal( &bs, 0, &bs.currentGoal );
// No Enemy.
bs.enemy = -1;
//if there is an enemy
if( BotFindEnemy( &bs, -1 ) )
{
if( BotWantsToRetreat( &bs ) )
{
//keep the current long term goal and retreat
//AIEnter_Battle_Retreat(bs, "seek ltg: found enemy");
stateThread.SetState("state_Retreat");
return SRESULT_DONE_FRAME;
}
else
{
//trap_BotResetLastAvoidReach(bs.ms);
//empty the goal stack
botGoalManager.BotEmptyGoalStack( bs.gs );
//go fight
stateThread.SetState("state_BattleFight");
return SRESULT_DONE_FRAME;
}
}
return SRESULT_WAIT;
}
+142
View File
@@ -0,0 +1,142 @@
// BotAI_Seek_NBG.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
/*
=====================
rvmBot::state_SeekNBG
=====================
*/
stateResult_t rvmBot::state_SeekNBG(stateParms_t* parms)
{
bot_goal_t goal;
idVec3 target, dir;
//bot_moveresult_t moveresult;
//if (BotIsObserver(bs)) {
// AIEnter_Observer(bs, "seek nbg: observer");
// return qfalse;
//}
////if in the intermission
//if (BotIntermission(bs)) {
// AIEnter_Intermission(bs, "seek nbg: intermision");
// return qfalse;
//}
// respawn if dead.
if( BotIsDead( &bs ) )
{
stateThread.SetState("state_Respawn");
return SRESULT_DONE_FRAME;
}
//bs.tfl = TFL_DEFAULT;
//if (bot_grapple.integer) bs.tfl |= TFL_GRAPPLEHOOK;
////if in lava or slime the bot should be able to get out
//if (BotInLavaOrSlime(bs)) bs.tfl |= TFL_LAVA | TFL_SLIME;
////
//if (BotCanAndWantsToRocketJump(bs)) {
// bs.tfl |= TFL_ROCKETJUMP;
//}
////map specific code
//BotMapScripts(bs);
//no enemy
bs.enemy = -1;
//if the bot has no goal
if( !botGoalManager.BotGetTopGoal( bs.gs, &goal ) )
{
bs.nbg_time = 0;
}
//if the bot touches the current goal
else if( BotReachedGoal( &bs, &goal ) )
{
BotChooseWeapon( &bs );
bs.nbg_time = 0;
}
if( bs.nbg_time < Bot_Time() )
{
//pop the current goal from the stack
botGoalManager.BotPopGoal( bs.gs );
//check for new nearby items right away
//NOTE: we canNOT reset the check_time to zero because it would create an endless loop of node switches
bs.check_time = Bot_Time() + 0.05;
//go back to seek ltg
// AIEnter_Seek_LTG(bs, "seek nbg: time out");
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
//predict obstacles
//if (BotAIPredictObstacles(bs, &goal))
// return qfalse;
////initialize the movement state
//BotSetupForMovement(bs);
////move towards the goal
//trap_BotMoveToGoal(&moveresult, bs.ms, &goal, bs.tfl);
////if the movement failed
//if (moveresult.failure) {
// //reset the avoid reach, otherwise bot is stuck in current area
// trap_BotResetAvoidReach(bs.ms);
// bs.nbg_time = 0;
//}
BotMoveToGoal( &bs, &goal );
//check if the bot is blocked
//BotAIBlocked(bs, &moveresult, qtrue);
////
//BotClearPath(bs, &moveresult);
// jmarshall - fix look at code.
//if the viewangles are used for the movement
//if (moveresult.flags & (MOVERESULT_MOVEMENTVIEWSET | MOVERESULT_MOVEMENTVIEW | MOVERESULT_SWIMVIEW)) {
// VectorCopy(moveresult.ideal_viewangles, bs.ideal_viewangles);
//}
////if waiting for something
//else if (moveresult.flags & MOVERESULT_WAITING) {
// if (random() < bs.thinktime * 0.8) {
// BotRoamGoal(bs, target);
// VectorSubtract(target, bs.origin, dir);
// vectoangles(dir, bs.ideal_viewangles);
// bs.ideal_viewangles[2] *= 0.5;
// }
//}
//else if (!(bs.flags & BFL_IDEALVIEWSET)) {
// if (!trap_BotGetSecondGoal(bs.gs, &goal)) trap_BotGetTopGoal(bs.gs, &goal);
// if (trap_BotMovementViewTarget(bs.ms, &goal, bs.tfl, 300, target)) {
// VectorSubtract(target, bs.origin, dir);
// vectoangles(dir, bs.ideal_viewangles);
// }
// //FIXME: look at cluster portals?
// else vectoangles(moveresult.movedir, bs.ideal_viewangles);
// bs.ideal_viewangles[2] *= 0.5;
//}
////if the weapon is used for the bot movement
//if (moveresult.flags & MOVERESULT_MOVEMENTWEAPON) bs.weaponnum = moveresult.weapon;
// jmarshall end
//if there is an enemy
if( BotFindEnemy( &bs, -1 ) )
{
if( BotWantsToRetreat( &bs ) )
{
//keep the current long term goal and retreat
//AIEnter_Battle_NBG(bs, "seek nbg: found enemy");
stateThread.SetState("state_BattleNBG");
return SRESULT_DONE_FRAME;
}
else
{
//trap_BotResetLastAvoidReach(bs.ms);
//empty the goal stack
botGoalManager.BotEmptyGoalStack( bs.gs );
//go fight
//AIEnter_Battle_Fight(bs, "seek nbg: found enemy");
stateThread.SetState("state_BattleFight");
return SRESULT_DONE_FRAME;
}
}
return SRESULT_WAIT;
}
+33
View File
@@ -0,0 +1,33 @@
// BotAI_respawn.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
/*
=====================
rvmBot::state_Respawn
=====================
*/
stateResult_t rvmBot::state_Respawn(stateParms_t* parms)
{
if (parms->stage == 0)
{
bs.botinput.respawn = true;
parms->stage = 1;
return SRESULT_WAIT;
}
if (parms->stage == 1)
{
if (spectating)
{
return SRESULT_WAIT; // Wait until we have moved from spectator back into the game.
}
}
bs.botinput.respawn = false;
stateThread.SetState("state_SeekLTG");
return SRESULT_DONE_FRAME;
}
+160
View File
@@ -0,0 +1,160 @@
// Bot_Input.cpp
//
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
/*
==============
rvmBot::BotInputToUserCommand
==============
*/
void rvmBot::BotInputToUserCommand(bot_input_t* bi, usercmd_t* ucmd, int time)
{
idVec3 forward, right;
short temp;
int j;
//clear the whole structure
// memset(ucmd, 0, sizeof(usercmd_t));
//
//common->Printf("dir = %f %f %f speed = %f\n", bi->dir[0], bi->dir[1], bi->dir[2], bi->speed);
//the duration for the user command in milli seconds
//
if (bi->actionflags & ACTION_DELAYEDJUMP)
{
bi->actionflags |= ACTION_JUMP;
bi->actionflags &= ~ACTION_DELAYEDJUMP;
}
//set the buttons
if (bi->actionflags & ACTION_RESPAWN)
{
ucmd->buttons = BUTTON_ATTACK;
}
if (bi->actionflags & ACTION_ATTACK)
{
ucmd->buttons |= BUTTON_ATTACK;
}
//if (bi->actionflags & ACTION_TALK) ucmd->buttons |= BUTTON_TALK;
//if (bi->actionflags & ACTION_GESTURE) ucmd->buttons |= BUTTON_GESTURE;
//if (bi->actionflags & ACTION_USE) ucmd->buttons |= BUTTON_USE_HOLDABLE;
if (bi->actionflags & ACTION_WALK)
{
ucmd->buttons |= BUTTON_RUN;
}
//if (bi->actionflags & ACTION_AFFIRMATIVE) ucmd->buttons |= BUTTON_AFFIRMATIVE;
//if (bi->actionflags & ACTION_NEGATIVE) ucmd->buttons |= BUTTON_NEGATIVE;
//if (bi->actionflags & ACTION_GETFLAG) ucmd->buttons |= BUTTON_GETFLAG;
//if (bi->actionflags & ACTION_GUARDBASE) ucmd->buttons |= BUTTON_GUARDBASE;
//if (bi->actionflags & ACTION_PATROL) ucmd->buttons |= BUTTON_PATROL;
//if (bi->actionflags & ACTION_FOLLOWME) ucmd->buttons |= BUTTON_FOLLOWME;
//
ucmd->impulse |= bi->weapon;
if (bi->lastWeaponNum != bi->weapon)
{
//ucmd->flags = UCF_IMPULSE_SEQUENCE;
bi->lastWeaponNum = bi->weapon;
}
else
{
//ucmd->flags = 0;
}
idAngles botViewAngles = viewAngles;
{
int i;
float move;
float angMod = (1.0f / 12.0f);
for (i = 0; i < 3; i++) {
move = idMath::AngleDelta(bi->viewangles[i], botViewAngles[i]);
botViewAngles[i] += (move * angMod);
}
}
//set the view angles
//NOTE: the ucmd->angles are the angles WITHOUT the delta angles
ucmd->angles[0] = ANGLE2SHORT(botViewAngles[0] - deltaViewAngles[0]);
ucmd->angles[1] = ANGLE2SHORT(botViewAngles[1] - deltaViewAngles[1]);
ucmd->angles[2] = ANGLE2SHORT(botViewAngles[2] - deltaViewAngles[2]);
bi->viewangles.ToVectors(&forward, &right, NULL);
//bot input speed is in the range [0, 400]
bi->speed = bi->speed * 127 / 400;
//set the view independent movement
ucmd->forwardmove = idMath::ClampChar(DotProduct(forward, bi->dir) * bi->speed);
ucmd->rightmove = idMath::ClampChar(DotProduct(right, bi->dir) * bi->speed);
//ucmd->upmove = abs(forward[2]) * bi->dir[2] * bi->speed;
//normal keyboard movement
if (bi->actionflags & ACTION_MOVEFORWARD)
{
ucmd->forwardmove += 127;
}
if (bi->actionflags & ACTION_MOVEBACK)
{
ucmd->forwardmove -= 127;
}
if (bi->actionflags & ACTION_MOVELEFT)
{
ucmd->rightmove -= 127;
}
if (bi->actionflags & ACTION_MOVERIGHT)
{
ucmd->rightmove += 127;
}
//jump/moveup
if (bi->actionflags & ACTION_JUMP)
ucmd->buttons |= BUTTON_JUMP;
// ucmd->upmove += 127;
//
////crouch/movedown
//if (bi->actionflags & ACTION_CROUCH)
// ucmd->upmove -= 127;
//
//Com_Printf("forward = %d right = %d up = %d\n", ucmd.forwardmove, ucmd.rightmove, ucmd.upmove);
//Com_Printf("ucmd->serverTime = %d\n", ucmd->serverTime);
if( bi->respawn )
{
ucmd->buttons |= BUTTON_ATTACK;
}
}
/*
================
rvmBot::ResetUcmd
================
*/
void rvmBot::Bot_ResetUcmd( usercmd_t& ucmd )
{
ucmd.forwardmove = 0;
ucmd.rightmove = 0;
//ucmd.upmove = 0;
ucmd.impulse = 0;
//ucmd.flags = 0;
memset( &ucmd.buttons, 0, sizeof( ucmd.buttons ) );
}
/*
========================
rvmBot::BotInputFrame
========================
*/
void rvmBot::BotInputFrame( idUserCmdMgr& cmdMgr )
{
usercmd_t botcmd = { }; //(usercmd_t&)cmdMgr.GetUserCmdForPlayer(entityNumber); // gameLocal.usercmds[entityNumber];
Bot_ResetUcmd( botcmd );
BotInputToUserCommand( &bs.botinput, &botcmd, gameLocal.time );
cmdMgr.PutUserCmdForPlayer( entityNumber, botcmd );
}
+353
View File
@@ -0,0 +1,353 @@
// Bot_char.cpp
//
#include "precompiled.h"
#include "../Game_local.h"
idBotCharacterStatsManager botCharacterStatsManager;
/*
====================
idBotCharacterStatsManager::idBotCharacterStatsManager
====================
*/
idBotCharacterStatsManager::idBotCharacterStatsManager()
{
default_char_profile = nullptr;
}
/*
====================
idBotCharacterStatsManager::Init
====================
*/
void idBotCharacterStatsManager::Init( void )
{
default_char_profile = BotLoadCharacterFromFile( "bots/default_c.c", 1 );
if( default_char_profile == NULL )
{
common->FatalError( "Failed to load default characteristic def file\n" );
}
}
/*
============================
idBotCharacterStatsManager::AllocBotCharacter
============================
*/
bot_character_t* idBotCharacterStatsManager::AllocBotCharacter( void )
{
bot_character_t* ch = NULL;
for( int i = 0; i < MAX_CHAR_STATS; i++ )
{
if( charStatsList[i].inUse == false )
{
charStatsList[i].inUse = true;
ch = &charStatsList[i];
break;
}
}
if( ch == nullptr )
{
gameLocal.Error( "idBotCharacterStatsManager::AllocBotCharacter: Too many bot characters!" );
return nullptr;
}
if( default_char_profile == NULL )
{
memset( &ch->c[0], 0, MAX_CHARACTERISTICS * sizeof( bot_characteristic_t ) );
ch->filename = "";
ch->inUse = false;
ch->skill = 0;
}
else
{
//memcpy( ch, default_char_profile, sizeof( bot_character_t ) + MAX_CHARACTERISTICS * sizeof( bot_characteristic_t ) );
*ch = *default_char_profile;
}
return ch;
}
/*
============================
idBotCharacterStatsManager::FreeCharacterFile
============================
*/
void idBotCharacterStatsManager::FreeCharacterFile( bot_character_t* ch )
{
ch->inUse = false;
}
/*
============================
idBotCharacterStatsManager::BotLoadCharacterFromFile
============================
*/
bot_character_t* idBotCharacterStatsManager::BotLoadCharacterFromFile( const char* charfile, int skill )
{
int indent, index;
bool foundcharacter;
bot_character_t* ch;
idParser parser;
idToken token;
foundcharacter = false;
// Check to see if we already loaded this bot file.
for( int i = 0; i < MAX_CHAR_STATS; i++ )
{
if(charStatsList[i].inUse && charStatsList[i].filename == charfile )
{
return &charStatsList[i];
}
}
rvmScopedLexerBaseFolder scopedBaseFolder( BOTFILESBASEFOLDER );
//a bot character is parsed in two phases
if( !parser.LoadFile( charfile ) )
{
common->Warning( "BotLoadCharacterFromFile: counldn't load %s\n", charfile );
return NULL;
}
ch = AllocBotCharacter();
ch->filename = charfile;
while( parser.ReadToken( &token ) )
{
if( token == "skill" )
{
if( !parser.ExpectTokenType( TT_NUMBER, 0, &token ) )
{
FreeCharacterFile( ch );
parser.Warning( "Expected token type number\n" );
return NULL;
}
if( !parser.ExpectTokenString( "{" ) )
{
FreeCharacterFile( ch );
parser.Warning( "Expected token {\n" );
return NULL;
}
//if it's the correct skill
if( skill < 0 || token.GetIntValue() == skill )
{
foundcharacter = true;
ch->skill = token.GetIntValue();
while( parser.ReadToken( &token ) )
{
if( token == "}" )
{
break;
}
if( token.type != TT_NUMBER || !( token.subtype & TT_INTEGER ) )
{
FreeCharacterFile( ch );
parser.Error( "expected integer index, found %s\n", token.c_str() );
return NULL;
}
index = token.GetIntValue();
if( index < 0 || index > MAX_CHARACTERISTICS )
{
FreeCharacterFile( ch );
parser.Error( "characteristic index out of range [0, %d]\n", MAX_CHARACTERISTICS );
return NULL;
}
// jmarshall - not sure what we loose by removing this check, basically duplicate definition check?
//if (ch->c[index].type)
//{
// G_Error("characteristic %d already initialized\n", index);
// trap_PC_FreeSource(source);
// BotFreeCharacterStrings(ch);
// //FreeMemory(ch);
// return NULL;
//}
// jmarshall end
if( !parser.ReadToken( &token ) )
{
FreeCharacterFile( ch );
parser.Error( "Unexpected EOF during parse characesistic" );
return NULL;
}
if( token.type == TT_NUMBER )
{
if( token.subtype & TT_FLOAT )
{
ch->c[index].value._float = token.GetFloatValue();
ch->c[index].type = CT_FLOAT;
}
else
{
ch->c[index].value.integer = token.GetIntValue();
ch->c[index].type = CT_INTEGER;
}
}
else if( token.type == TT_STRING )
{
token.StripDoubleQuotes();
ch->c[index].value.string = token;
ch->c[index].type = CT_STRING;
}
else
{
FreeCharacterFile( ch );
gameLocal.Error( "expected integer, float or string, found %s\n", token.c_str() );
return NULL;
}
}
break;
}
else
{
indent = 1;
while( indent )
{
if( !parser.ReadToken( &token ) )
{
FreeCharacterFile( ch );
return NULL;
}
if( token == "{" )
{
indent++;
}
else if( token == "}" )
{
indent--;
}
}
}
}
else
{
FreeCharacterFile( ch );
gameLocal.Error( "unknown definition %s\n", token.c_str() );
return NULL;
}
}
if( !foundcharacter )
{
FreeCharacterFile( ch );
return NULL;
}
return ch;
}
/*
============================
idBotCharacterStatsManager::CheckCharacteristicIndex
============================
*/
int idBotCharacterStatsManager::CheckCharacteristicIndex( bot_character_t* ch, int index )
{
if( index < 0 || index >= MAX_CHARACTERISTICS )
{
gameLocal.Error( "characteristic %d does not exist\n", index );
return false;
}
if( !ch->c[index].type )
{
gameLocal.Error( "characteristic %d is not initialized\n", index );
return false;
}
return true;
}
/*
============================
idBotCharacterStatsManager::Characteristic_Float
============================
*/
float idBotCharacterStatsManager::Characteristic_Float( bot_character_t* ch, int index )
{
if( !ch )
{
return 0;
}
//check if the index is in range
if( !CheckCharacteristicIndex( ch, index ) )
{
return 0;
}
if( ch->c[index].type == CT_INTEGER )
{
//an integer will be converted to a float
return ( float )ch->c[index].value.integer;
}
else if( ch->c[index].type == CT_FLOAT )
{
//floats are just returned
return ch->c[index].value._float;
}
//cannot convert a string pointer to a float
gameLocal.Error( "characteristic %d is not a float\n", index );
return 0;
}
/*
============================
Characteristic_String
============================
*/
void idBotCharacterStatsManager::Characteristic_String( bot_character_t* ch, int index, char* buf, int size )
{
//check if the index is in range
if( !CheckCharacteristicIndex( ch, index ) )
{
return;
}
//an integer will be converted to a float
if( ch->c[index].type == CT_STRING )
{
strcpy( buf, ch->c[index].value.string );
buf[size - 1] = '\0';
return;
}
gameLocal.Error( "characteristic %d is not a string\n", index );
}
/*
============================
idBotCharacterStatsManager::Characteristic_BFloat
============================
*/
float idBotCharacterStatsManager::Characteristic_BFloat( bot_character_t* ch, int index, float min, float max )
{
float value;
if( min > max )
{
gameLocal.Error( "cannot bound characteristic %d between %f and %f\n", index, min, max );
return 0;
}
value = Characteristic_Float( ch, index );
if( value < min )
{
return min;
}
if( value > max )
{
return max;
}
return value;
}
+153
View File
@@ -0,0 +1,153 @@
// Bot_char.h
//
#define MAX_CHAR_STATS 256
//========================================================
//========================================================
//name
#define CHARACTERISTIC_NAME 0 //string
//gender of the bot
#define CHARACTERISTIC_GENDER 1 //string ("male", "female", "it")
//attack skill
// > 0.0 && < 0.2 = don't move
// > 0.3 && < 1.0 = aim at enemy during retreat
// > 0.0 && < 0.4 = only move forward/backward
// >= 0.4 && < 1.0 = circle strafing
// > 0.7 && < 1.0 = random strafe direction change
#define CHARACTERISTIC_ATTACK_SKILL 2 //float [0, 1]
//weapon weight file
#define CHARACTERISTIC_WEAPONWEIGHTS 3 //string
//view angle difference to angle change factor
#define CHARACTERISTIC_VIEW_FACTOR 4 //float <0, 1]
//maximum view angle change
#define CHARACTERISTIC_VIEW_MAXCHANGE 5 //float [1, 360]
//reaction time in seconds
#define CHARACTERISTIC_REACTIONTIME 6 //float [0, 5]
//accuracy when aiming
#define CHARACTERISTIC_AIM_ACCURACY 7 //float [0, 1]
//weapon specific aim accuracy
#define CHARACTERISTIC_AIM_ACCURACY_MACHINEGUN 8 //float [0, 1]
#define CHARACTERISTIC_AIM_ACCURACY_SHOTGUN 9 //float [0, 1]
#define CHARACTERISTIC_AIM_ACCURACY_ROCKETLAUNCHER 10 //float [0, 1]
#define CHARACTERISTIC_AIM_ACCURACY_GRENADELAUNCHER 11 //float [0, 1]
#define CHARACTERISTIC_AIM_ACCURACY_LIGHTNING 12
#define CHARACTERISTIC_AIM_ACCURACY_PLASMAGUN 13 //float [0, 1]
#define CHARACTERISTIC_AIM_ACCURACY_RAILGUN 14
#define CHARACTERISTIC_AIM_ACCURACY_BFG10K 15 //float [0, 1]
//skill when aiming
// > 0.0 && < 0.9 = aim is affected by enemy movement
// > 0.4 && <= 0.8 = enemy linear leading
// > 0.8 && <= 1.0 = enemy exact movement leading
// > 0.5 && <= 1.0 = prediction shots when enemy is not visible
// > 0.6 && <= 1.0 = splash damage by shooting nearby geometry
#define CHARACTERISTIC_AIM_SKILL 16 //float [0, 1]
//weapon specific aim skill
#define CHARACTERISTIC_AIM_SKILL_ROCKETLAUNCHER 17 //float [0, 1]
#define CHARACTERISTIC_AIM_SKILL_GRENADELAUNCHER 18 //float [0, 1]
#define CHARACTERISTIC_AIM_SKILL_PLASMAGUN 19 //float [0, 1]
#define CHARACTERISTIC_AIM_SKILL_BFG10K 20 //float [0, 1]
//========================================================
//chat
//========================================================
//file with chats
#define CHARACTERISTIC_CHAT_FILE 21 //string
//name of the chat character
#define CHARACTERISTIC_CHAT_NAME 22 //string
//characters per minute type speed
#define CHARACTERISTIC_CHAT_CPM 23 //integer [1, 4000]
//tendency to insult/praise
#define CHARACTERISTIC_CHAT_INSULT 24 //float [0, 1]
//tendency to chat misc
#define CHARACTERISTIC_CHAT_MISC 25 //float [0, 1]
//tendency to chat at start or end of level
#define CHARACTERISTIC_CHAT_STARTENDLEVEL 26 //float [0, 1]
//tendency to chat entering or exiting the game
#define CHARACTERISTIC_CHAT_ENTEREXITGAME 27 //float [0, 1]
//tendency to chat when killed someone
#define CHARACTERISTIC_CHAT_KILL 28 //float [0, 1]
//tendency to chat when died
#define CHARACTERISTIC_CHAT_DEATH 29 //float [0, 1]
//tendency to chat when enemy suicides
#define CHARACTERISTIC_CHAT_ENEMYSUICIDE 30 //float [0, 1]
//tendency to chat when hit while talking
#define CHARACTERISTIC_CHAT_HITTALKING 31 //float [0, 1]
//tendency to chat when bot was hit but didn't dye
#define CHARACTERISTIC_CHAT_HITNODEATH 32 //float [0, 1]
//tendency to chat when bot hit the enemy but enemy didn't dye
#define CHARACTERISTIC_CHAT_HITNOKILL 33 //float [0, 1]
//tendency to randomly chat
#define CHARACTERISTIC_CHAT_RANDOM 34 //float [0, 1]
//tendency to reply
#define CHARACTERISTIC_CHAT_REPLY 35 //float [0, 1]
//========================================================
//movement
//========================================================
//tendency to crouch
#define CHARACTERISTIC_CROUCHER 36 //float [0, 1]
//tendency to jump
#define CHARACTERISTIC_JUMPER 37 //float [0, 1]
//tendency to walk
#define CHARACTERISTIC_WALKER 48 //float [0, 1]
//tendency to jump using a weapon
#define CHARACTERISTIC_WEAPONJUMPING 38 //float [0, 1]
//tendency to use the grapple hook when available
#define CHARACTERISTIC_GRAPPLE_USER 39 //float [0, 1] //use this!!
//========================================================
//goal
//========================================================
//item weight file
#define CHARACTERISTIC_ITEMWEIGHTS 40 //string
//the aggression of the bot
#define CHARACTERISTIC_AGGRESSION 41 //float [0, 1]
//the self preservation of the bot (rockets near walls etc.)
#define CHARACTERISTIC_SELFPRESERVATION 42 //float [0, 1]
//how likely the bot is to take revenge
#define CHARACTERISTIC_VENGEFULNESS 43 //float [0, 1] //use this!!
//tendency to camp
#define CHARACTERISTIC_CAMPER 44 //float [0, 1]
//========================================================
//========================================================
//tendency to get easy frags
#define CHARACTERISTIC_EASY_FRAGGER 45 //float [0, 1]
//how alert the bot is (view distance)
#define CHARACTERISTIC_ALERTNESS 46 //float [0, 1]
//how much the bot fires it's weapon
#define CHARACTERISTIC_FIRETHROTTLE 47 //float [0, 1]
//
// idBotCharacterStatsManager
//
class idBotCharacterStatsManager
{
public:
idBotCharacterStatsManager();
// Inits the stats manager.
void Init( void );
// Loads a character file.
bot_character_t* BotLoadCharacterFromFile( const char* charfile, int skill );
// Free character file.
void FreeCharacterFile( bot_character_t* ch );
// Returns the default character stats profile.
bot_character_t* GetDefaultCharProfile( void )
{
return default_char_profile;
}
int CheckCharacteristicIndex( bot_character_t* ch, int index );
float Characteristic_Float( bot_character_t* ch, int index );
void Characteristic_String( bot_character_t* ch, int index, char* buf, int size );
float Characteristic_BFloat( bot_character_t* ch, int index, float min, float max );
private:
bot_character_t* AllocBotCharacter( void );
bot_character_t* default_char_profile;
bot_character_t charStatsList[MAX_CHAR_STATS];
};
extern idBotCharacterStatsManager botCharacterStatsManager;
+54
View File
@@ -0,0 +1,54 @@
// Bot_Chat.cpp
//
#include "precompiled.h"
#include "../Game_local.h"
const char *bot_kill_insult[] = {
"%s: Try aiming next time %s",
"%s: Trust me when I say this %s, you suck.",
"%s: Maybe you should go back to go cart racing %s?",
"%s: Your technique reminds me of a story %s, a very dull one."
};
const char* bot_death_insult[] = {
"%s: Mmmmmmm. Was it good for you too %s?",
"%s: Well I guess %s won the lottery.",
"%s: My mother fragged me once %s. Once.",
"%s: I'm gonna pull out your bowels %s",
"%s: Beginners luck %s... Again",
"%s: So %s... you're up to what ... 3 frags an hour?"
};
const char* bot_death_praise[] = {
"%s: %s not bad for an amateur.",
"%s: %s alright that was pretty good. Your still a dousche.",
"%s: That was definitely ... um ... pretty good %s",
"%s: I've seen better %s, but not many.",
"%s: Take a moment to reflect on your accomplishment %s",
"%s: Your pretty good for a dousche %s"
};
/*
====================
rvmBot::BotSendChatMessage
====================
*/
void rvmBot::BotSendChatMessage(botChat_t chat, const char* targetName) {
switch (chat)
{
case KILL:
gameLocal.mpGame.AddChatLine(bot_kill_insult[rvRandom::irand(0, 3)], netname.c_str(), targetName);
break;
case DEATH:
if (rvRandom::irand(0, 10) < 5)
{
gameLocal.mpGame.AddChatLine(bot_death_insult[rvRandom::irand(0, 5)], netname.c_str(), targetName);
}
else
{
gameLocal.mpGame.AddChatLine(bot_death_praise[rvRandom::irand(0, 5)], netname.c_str(), targetName);
}
break;
}
}
+9
View File
@@ -0,0 +1,9 @@
// Bot_chat.h
//
#pragma once
enum botChat_t {
KILL = 0,
DEATH,
};
File diff suppressed because it is too large Load Diff
+342
View File
@@ -0,0 +1,342 @@
// Bot_goal.h
//
#define MAX_BOT_ITEM_INFOS 2
#define MAX_BOT_ITEM_INFO 256
#define MAX_BOT_LEVEL_ITEMS 256
//#define DEBUG_AI_GOAL
#ifdef RANDOMIZE
#define UNDECIDEDFUZZY
#endif //RANDOMIZE
#define DROPPEDWEIGHT
//minimum avoid goal time
#define AVOID_MINIMUM_TIME 10
//default avoid goal time
#define AVOID_DEFAULT_TIME 30
//avoid dropped goal time
#define AVOID_DROPPED_TIME 10
//
#define TRAVELTIME_SCALE 0.01
//item flags
#define IFL_NOTFREE 1 //not in free for all
#define IFL_NOTTEAM 2 //not in team play
#define IFL_NOTSINGLE 4 //not in single player
#define IFL_NOTBOT 8 //bot should never go for this
#define IFL_ROAM 16 //bot roam goal
//a bot goal
struct bot_goal_t
{
bot_goal_t()
{
Reset();
}
void Reset()
{
origin.Zero();
areanum = 0;
mins.Zero();
maxs.Zero();
entitynum = 0;
number = 0;
flags = 0;
iteminfo = 0;
framenum = -1;
}
int framenum;
idVec3 origin; //origin of the goal
int areanum; //area number of the goal
idVec3 mins, maxs; //mins and maxs of the goal
int entitynum; //number of the goal entity
int number; //goal number
int flags; //goal flags
int iteminfo; //item information
};
//location in the map "target_location"
struct maplocation_t
{
maplocation_t()
{
Reset();
}
void Reset()
{
origin.Zero();
areanum = 0;
name = "";
next = nullptr;
}
idVec3 origin;
int areanum;
idStr name;
maplocation_t* next;
};
//camp spots "info_camp"
struct campspot_t
{
campspot_t()
{
Reset();
}
void Reset()
{
origin.Zero();
areanum = 0;
name = "";
range = 0;
weight = 0;
random = 0;
}
idVec3 origin;
int areanum;
idStr name;
float range;
float weight;
float wait;
float random;
};
struct levelitem_t
{
levelitem_t()
{
Reset();
}
void Reset()
{
number = 0;
iteminfo = 0;
flags = 0;
weight = 0;
origin.Zero();
goalorigin.Zero();
item = nullptr;
timeout = 0;
prev = nullptr;
next = nullptr;
}
idStr name;
int number; //number of the level item
int iteminfo; //index into the item info
int flags; //item flags
float weight; //fixed roam weight
idVec3 origin; //origin of the item
idVec3 goalorigin; //goal origin within the area
//int entitynum; //entity number
idItem* item;
float timeout; //item is removed after this time
levelitem_t* prev, * next;
};
struct iteminfo_t
{
iteminfo_t()
{
Reset();
}
void Reset()
{
classname = "";
name = "";
model = "";
modelindex = 0;
type = 0;
index = 0;
respawntime = 0;
mins.Zero();
maxs.Zero();
number = 0;
}
idStr classname; //classname of the item
idStr name; //name of the item
idStr model; //model of the item
int modelindex; //model index
int type; //item type
int index; //index in the inventory
float respawntime; //respawn time
idVec3 mins; //mins of the item
idVec3 maxs; //maxs of the item
int number; //number of the item info
};
//
// itemconfig_t
//
struct itemconfig_t
{
itemconfig_t()
{
Reset();
}
void Reset( void )
{
numiteminfo = 0;
for( int i = 0; i < MAX_BOT_ITEM_INFO; i++ )
{
iteminfo[i].Reset();
}
}
int numiteminfo;
iteminfo_t iteminfo[MAX_BOT_ITEM_INFO];
};
//goal state
struct bot_goalstate_t
{
bot_goalstate_t()
{
itemweightindex = NULL;
Reset();
}
void Reset()
{
itemweightconfig = NULL;
if( itemweightindex != NULL )
{
delete itemweightindex;
}
itemweightindex = NULL;
client = -1;
lastreachabilityarea = 0;
goalstacktop = 0;
for( int i = 0; i < MAX_AVOIDGOALS; i++ )
{
avoidgoals[i] = 0;
avoidgoaltimes[i] = 0;
}
}
~bot_goalstate_t()
{
if( itemweightindex != NULL )
{
delete itemweightindex;
}
itemweightindex = NULL;
}
bool InUse()
{
return client != -1;
}
weightconfig_t* itemweightconfig; //weight config
int* itemweightindex; //index from item to weight
int client; //client using this goal state
int lastreachabilityarea; //last area with reachabilities the bot was in
bot_goal_t goalstack[MAX_GOALSTACK]; //goal stack
int goalstacktop; //the top of the goal stack
int avoidgoals[MAX_AVOIDGOALS]; //goals to avoid
float avoidgoaltimes[MAX_AVOIDGOALS]; //times to avoid the goals
};
class idBotGoalManager
{
public:
idBotGoalManager();
int BotSetupGoalAI( void );
void InitLevelItems( void );
void UpdateEntityItems( void );
void BotPushGoal( int goalstate, bot_goal_t* goal );
void BotPopGoal( int goalstate );
void BotEmptyGoalStack( int goalstate );
int BotLoadItemWeights( int goalstate, char* filename );
void BotResetGoalState( int goalstate );
int BotItemGoalInVisButNotVisible( int viewer, idVec3 eye, idAngles viewangles, bot_goal_t* goal );
int BotChooseLTGItem( int goalstate, idVec3 origin, int* inventory, int travelflags );
int BotChooseNBGItem( int goalstate, idVec3 origin, int* inventory, int travelflags, bot_goal_t* ltg, float maxtime );
int BotTouchingGoal( idVec3 origin, bot_goal_t* goal );
int BotAllocGoalState( int client );
void BotGoalName( int number, char* name, int size );
void BotFreeGoalState( int handle );
void BotShutdownGoalAI( void );
void BotFreeItemWeights( int goalstate );
public:
bool BotNearGoal( idVec3 p1, idVec3 p2 );
int BotGetTopGoal( int goalstate, bot_goal_t* goal );
int BotGetSecondGoal( int goalstate, bot_goal_t* goal );
public:
void BotDumpGoalStack( int goalstate );
public:
int BotGetLevelItemGoal( int index, char* name, bot_goal_t* goal );
void BotSetAvoidGoalTime( int goalstate, int number, float avoidtime );
float BotAvoidGoalTime( int goalstate, int number );
void BotResetAvoidGoals( int goalstate );
void BotDumpAvoidGoals( int goalstate );
void BotAddToAvoidGoals( bot_goalstate_t* gs, int number, float avoidtime );
void BotRemoveFromAvoidGoals( int goalstate, int number );
int BotGetMapLocationGoal( char* name, bot_goal_t* goal );
int BotGetNextCampSpotGoal( int num, bot_goal_t* goal );
void BotFindEntityForLevelItem( levelitem_t* li );
private:
levelitem_t* AllocLevelItem( void );
void FreeLevelItem( levelitem_t* li );
void AddLevelItemToList( levelitem_t* li );
void RemoveLevelItemFromList( levelitem_t* li );
void BotFreeInfoEntities( void );
void BotInitInfoEntities( void );
void InitLevelItemHeap( void );
int* ItemWeightIndex( weightconfig_t* iwc, itemconfig_t* ic );
itemconfig_t* LoadItemConfig( char* filename );
void BotSaveGoalFuzzyLogic( int goalstate, char* filename );
void BotMutateGoalFuzzyLogic( int goalstate, float range );
bot_goalstate_t* BotGoalStateFromHandle( int handle );
void BotInterbreedGoalFuzzyLogic( int parent1, int parent2, int child );
private:
void ParseItemInfo( idParser& parser, iteminfo_t* itemInfo );
private:
bot_goalstate_t botgoalstates[MAX_CLIENTS + 1];
//item configuration
itemconfig_t itemconfiglocal;
itemconfig_t* itemconfig;
//level items
levelitem_t levelitemheap[MAX_BOT_LEVEL_ITEMS];
levelitem_t* freelevelitems;
levelitem_t* levelitems;
int numlevelitems;
//map locations
idList<maplocation_t> maplocations;
idList<campspot_t> campspots;
};
extern idBotGoalManager botGoalManager;
+492
View File
@@ -0,0 +1,492 @@
// Bot_weapons.cpp
//
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
idCVar bot_weaponsfile( "bot_weaponsfile", "weapons.c", CVAR_GAME | CVAR_CHEAT, "which file to load the weapons weights from" );
idBotWeaponInfoManager botWeaponInfoManager;
/*
=========================
idBotWeaponInfoManager::BotValidWeaponNumber
=========================
*/
int idBotWeaponInfoManager::BotValidWeaponNumber( int weaponnum )
{
if( weaponnum <= 0 || weaponnum > BOT_MAX_WEAPONS )
{
gameLocal.Error( "weapon number out of range\n" );
return false;
}
return true;
}
/*
=========================
idBotWeaponInfoManager::BotWeaponStateFromHandle
=========================
*/
bot_weaponstate_t* idBotWeaponInfoManager::BotWeaponStateFromHandle( int handle )
{
if( handle <= 0 || handle > MAX_CLIENTS )
{
gameLocal.Error( "move state handle %d out of range\n", handle );
}
return &botweaponstates[handle];
}
/*
========================
idBotWeaponInfoManager::ParseProjectileInfo
========================
*/
void idBotWeaponInfoManager::ParseProjectileInfo( idParser& parser, projectileinfo_t& newProjectileInfo )
{
idToken token;
idToken valueToken;
parser.ExpectTokenString( "{" );
while( true )
{
if( !parser.ReadToken( &token ) )
{
parser.Error( "Unexpected end of file found while parsing weaponinfo!" );
}
if( token == "}" )
{
break;
}
if( !parser.ReadToken( &valueToken ) )
{
parser.Error( "Failed to read value token, encountered EOF parsing weapon info!" );
}
if( token == "name" )
{
newProjectileInfo.name = valueToken; // name of the projectile
}
else if( token == "model" )
{
newProjectileInfo.model = valueToken; // model of the projectile
}
else if( token == "flags" )
{
newProjectileInfo.flags = valueToken.GetIntValue(); // special flags
}
else if( token == "gravity" )
{
newProjectileInfo.gravity = valueToken.GetFloatValue(); // amount of gravity applied to the projectile [0,1]
}
else if( token == "damage" )
{
newProjectileInfo.damage = valueToken.GetIntValue(); // damage of the projectile
}
else if( token == "radius" )
{
newProjectileInfo.radius = valueToken.GetFloatValue(); // radius of damage
}
else if( token == "visdamage" )
{
newProjectileInfo.visdamage = valueToken.GetIntValue(); // damage of the projectile to visible entities
}
else if( token == "damagetype" )
{
newProjectileInfo.damagetype = valueToken.GetIntValue(); // type of damage (combination of the DAMAGETYPE_? flags)
}
else if( token == "healthinc" )
{
newProjectileInfo.healthinc = valueToken.GetIntValue(); // health increase the owner gets
}
else if( token == "push" )
{
newProjectileInfo.push = valueToken.GetFloatValue(); // amount a player is pushed away from the projectile impact
}
else if( token == "detonation" )
{
newProjectileInfo.detonation = valueToken.GetFloatValue(); // time before projectile explodes after fire pressed
}
else if( token == "bounce" )
{
newProjectileInfo.bounce = valueToken.GetFloatValue(); // amount the projectile bounces
}
else if( token == "bouncefric" )
{
newProjectileInfo.bouncefric = valueToken.GetFloatValue(); // amount the bounce decreases per bounce
}
else if( token == "bouncestop" )
{
newProjectileInfo.bouncestop = valueToken.GetFloatValue(); // minimum bounce value before bouncing stops
}
else
{
parser.Error( "ParseProjectileInfo: Unexpected token %s\n", token.c_str() );
}
}
}
/*
========================
idBotWeaponInfoManager::ParseWeaponInfo
========================
*/
void idBotWeaponInfoManager::ParseWeaponInfo( idParser& parser, weaponinfo_t& newWeaponInfo )
{
idToken token;
idToken valueToken;
parser.ExpectTokenString( "{" );
while( true )
{
if( !parser.ReadToken( &token ) )
{
parser.Error( "Unexpected end of file found while parsing weaponinfo!" );
}
if( token == "}" )
{
break;
}
if( !parser.ReadToken( &valueToken ) )
{
parser.Error( "Failed to read value token, encountered EOF parsing weapon info!" );
}
if( token == "number" )
{
newWeaponInfo.number = valueToken.GetIntValue(); //weapon number
}
else if( token == "name" )
{
newWeaponInfo.name = valueToken; //name of the weapon
}
else if( token == "level" )
{
newWeaponInfo.level = valueToken.GetIntValue();
}
else if( token == "model" )
{
newWeaponInfo.model = valueToken; //model of the weapon
}
else if( token == "weaponindex" )
{
newWeaponInfo.weaponindex = valueToken.GetIntValue(); //index of weapon in inventory
}
else if( token == "flags" )
{
newWeaponInfo.flags = valueToken.GetIntValue(); //special flags
}
else if( token == "projectile" )
{
newWeaponInfo.projectile = valueToken; //projectile used by the weapon
}
else if( token == "numprojectiles" )
{
newWeaponInfo.numprojectiles = valueToken.GetIntValue(); //number of projectiles
}
else if( token == "hspread" )
{
newWeaponInfo.hspread = valueToken.GetFloatValue(); //horizontal spread of projectiles (degrees from middle)
}
else if( token == "vspread" )
{
newWeaponInfo.vspread = valueToken.GetFloatValue(); //vertical spread of projectiles (degrees from middle)
}
else if( token == "speed" )
{
newWeaponInfo.speed = valueToken.GetFloatValue(); //speed of the projectile (0 = instant hit)
}
else
{
parser.Error( "ParseWeaponInfo: Unexpected token %s\n", token.c_str() );
}
}
}
/*
========================
idBotWeaponInfoManager::LoadWeaponConfig
========================
*/
void idBotWeaponInfoManager::LoadWeaponConfig( char* filename )
{
idParser parser;
idToken token;
int j;
if( !parser.LoadFile( filename ) )
{
gameLocal.Error( "Failed to load bot weapon config %s\n", filename );
}
while( parser.ReadToken( &token ) )
{
if( token == "weaponinfo" )
{
weaponinfo_t newWeaponInfo;
ParseWeaponInfo( parser, newWeaponInfo );
if( newWeaponInfo.number < 0 || newWeaponInfo.number >= BOT_MAX_WEAPONS )
{
parser.Error( "weapon info number %d out of range\n", newWeaponInfo.number );
return;
}
weaponinfo[newWeaponInfo.number] = newWeaponInfo;
weaponinfo[newWeaponInfo.number].valid = true;
}
else if( token == "projectileinfo" )
{
projectileinfo_t newProjectileInfo;
ParseProjectileInfo( parser, newProjectileInfo );
projectileinfo.Append( newProjectileInfo );
}
else
{
parser.Error( "LoadWeaponConfig: Unknown definintion %s", token.c_str() );
}
}
// fix up weapons.
for( int i = 0; i < BOT_MAX_WEAPONS; i++ )
{
if( !weaponinfo[i].valid )
{
continue;
}
if( weaponinfo[i].name.Length() <= 0 )
{
parser.Error( "weapon %d has no name\n", i );
return;
}
if( weaponinfo[i].projectile.Length() <= 0 )
{
parser.Error( "weapon %s has no projectile\n", weaponinfo[i].name );
return;
}
//find the projectile info and copy it to the weapon info
for( j = 0; j < projectileinfo.Num(); j++ )
{
if( projectileinfo[j].name == weaponinfo[i].projectile )
{
memcpy( &weaponinfo[i].proj, &projectileinfo[j], sizeof( projectileinfo_t ) );
break;
}
}
if( j == projectileinfo.Num() )
{
parser.Error( "weapon %s uses undefined projectile\n", weaponinfo[i].name.c_str() );
return;
}
}
}
/*
========================
idBotWeaponInfoManager::Init
========================
*/
void idBotWeaponInfoManager::Init( void )
{
rvmScopedLexerBaseFolder scopedBaseFolder( BOTFILESBASEFOLDER );
LoadWeaponConfig( ( char* )bot_weaponsfile.GetString() );
}
/*
=====================
WeaponWeightIndex
=====================
*/
void idBotWeaponInfoManager::WeaponWeightIndex( weightconfig_t* wwc, bot_weaponstate_t* weaponState )
{
for( int i = 0; i < BOT_MAX_WEAPONS; i++ )
{
weaponState->weaponweightindex[i] = botFuzzyWeightManager.FindFuzzyWeight( wwc, ( char* )weaponinfo[i].name.c_str() );
}
}
/*
=====================
idBotWeaponInfoManager::WeaponWeightIndex
=====================
*/
void idBotWeaponInfoManager::BotFreeWeaponWeights( int weaponstate )
{
bot_weaponstate_t* ws;
ws = BotWeaponStateFromHandle( weaponstate );
if( !ws )
{
return;
}
// if (ws->weaponweightconfig)
// FreeWeightConfig(ws->weaponweightconfig);
// if (ws->weaponweightindex) FreeMemory(ws->weaponweightindex);
}
/*
=====================
BotLoadWeaponWeights
=====================
*/
int idBotWeaponInfoManager::BotLoadWeaponWeights( int weaponstate, char* filename )
{
bot_weaponstate_t* ws;
ws = BotWeaponStateFromHandle( weaponstate );
if( !ws )
{
return BLERR_CANNOTLOADWEAPONWEIGHTS;
}
BotFreeWeaponWeights( weaponstate );
ws->weaponweightconfig = botFuzzyWeightManager.ReadWeightConfig( filename );
if( !ws->weaponweightconfig )
{
gameLocal.Error( "couldn't load weapon config %s\n", filename );
return BLERR_CANNOTLOADWEAPONWEIGHTS;
}
WeaponWeightIndex( ws->weaponweightconfig, ws );
return BLERR_NOERROR;
}
/*
=====================
idBotWeaponInfoManager::BotGetWeaponInfo
=====================
*/
void idBotWeaponInfoManager::BotGetWeaponInfo( int weaponstate, int weapon, weaponinfo_t* weaponinfo )
{
bot_weaponstate_t* ws;
if( !BotValidWeaponNumber( weapon ) )
{
return;
}
ws = BotWeaponStateFromHandle( weaponstate );
if( !ws )
{
return;
}
*weaponinfo = this->weaponinfo[weapon];
}
/*
=====================
idBotWeaponInfoManager::BotChooseBestFightWeapon
=====================
*/
int idBotWeaponInfoManager::BotChooseBestFightWeapon( int weaponstate, int* inventory )
{
int i, index, bestweapon;
float weight, bestweight;
bot_weaponstate_t* ws;
ws = BotWeaponStateFromHandle( weaponstate );
if( !ws )
{
return 0;
}
//if the bot has no weapon weight configuration
if( !ws->weaponweightconfig )
{
return 0;
}
bestweight = 0;
bestweapon = 0;
for( i = 0; i < BOT_MAX_WEAPONS; i++ )
{
if( !weaponinfo[i].valid )
{
continue;
}
index = ws->weaponweightindex[i];
if( index < 0 )
{
continue;
}
weight = botFuzzyWeightManager.FuzzyWeight( inventory, ws->weaponweightconfig, index );
if( weight > bestweight )
{
bestweight = weight;
bestweapon = i;
}
}
return bestweapon;
}
/*
=====================
idBotWeaponInfoManager::BotResetWeaponState
=====================
*/
void idBotWeaponInfoManager::BotResetWeaponState( int weaponstate )
{
weightconfig_t* weaponweightconfig;
int* weaponweightindex;
bot_weaponstate_t* ws;
ws = BotWeaponStateFromHandle( weaponstate );
if( !ws )
{
return;
}
weaponweightconfig = ws->weaponweightconfig;
weaponweightindex = ws->weaponweightindex;
//Com_Memset(ws, 0, sizeof(bot_weaponstate_t));
ws->weaponweightconfig = weaponweightconfig;
memcpy( ws->weaponweightindex, weaponweightindex, sizeof( int ) * BOT_MAX_WEAPONS );
}
/*
=====================
idBotWeaponInfoManager::BotAllocWeaponState
=====================
*/
int idBotWeaponInfoManager::BotAllocWeaponState( void )
{
int i;
for( i = 1; i <= MAX_CLIENTS; i++ )
{
if( !botweaponstates[i].inUse )
{
botweaponstates[i].Reset();
botweaponstates[i].inUse = true;
return i;
}
}
return 0;
}
/*
=====================
idBotWeaponInfoManager::BotAllocWeaponState
=====================
*/
void idBotWeaponInfoManager::BotFreeWeaponState( int ws )
{
botweaponstates[ws].inUse = false;
botweaponstates[ws].Reset();
}
+161
View File
@@ -0,0 +1,161 @@
// Bot_weapons.h
//
#pragma once
#define BOT_MAX_WEAPONS 32
//projectile flags
#define PFL_WINDOWDAMAGE 1 //projectile damages through window
#define PFL_RETURN 2 //set when projectile returns to owner
//weapon flags
#define WFL_FIRERELEASED 1 //set when projectile is fired with key-up event
//damage types
#define DAMAGETYPE_IMPACT 1 //damage on impact
#define DAMAGETYPE_RADIAL 2 //radial damage
#define DAMAGETYPE_VISIBLE 4 //damage to all entities visible to the projectile
struct projectileinfo_t
{
projectileinfo_t()
{
name = "";
model = "";
flags = 0;
gravity = 0;
damage = 0;
radius = 0;
visdamage = 0;
damagetype = 0;
healthinc = 0;
push = 0;
detonation = 0;
bounce = 0;
bouncefric = 0;
bouncestop = 0;
}
idStr name;
idStr model;
int flags;
float gravity;
int damage;
float radius;
int visdamage;
int damagetype;
int healthinc;
float push;
float detonation;
float bounce;
float bouncefric;
float bouncestop;
};
struct weaponinfo_t
{
weaponinfo_t()
{
valid = 0;
number = 0;
name = "";
model = "";
level = 0;
weaponindex = 0;
flags = 0;
projectile = "";
numprojectiles = 0;
hspread = 0;
vspread = 0;
speed = 0;
acceleration = 0;
recoil.Zero();
offset.Zero();
angleoffset.Zero();
extrazvelocity = 0;
ammoamount = 0;
ammoindex = 0;
activate = 0;
reload = 0;
spinup = 0;
spindown = 0;
}
int valid; //true if the weapon info is valid
int number; //number of the weapon
idStr name;
idStr model;
int level;
int weaponindex;
int flags;
idStr projectile;
int numprojectiles;
float hspread;
float vspread;
float speed;
float acceleration;
idVec3 recoil;
idVec3 offset;
idVec3 angleoffset;
float extrazvelocity;
int ammoamount;
int ammoindex;
float activate;
float reload;
float spinup;
float spindown;
projectileinfo_t proj; //pointer to the used projectile
};
struct bot_weaponstate_t
{
bot_weaponstate_t()
{
Reset();
}
void Reset()
{
inUse = false;
weaponweightconfig = NULL;
for( int i = 0; i < BOT_MAX_WEAPONS; i++ )
{
weaponweightindex[i] = 0;
}
}
bool inUse;
weightconfig_t* weaponweightconfig;
int weaponweightindex[BOT_MAX_WEAPONS]; //weapon weight index
};
//
// idBotWeaponInfoManager
//
class idBotWeaponInfoManager
{
public:
void Init( void );
int BotLoadWeaponWeights( int weaponstate, char* filename );
void BotGetWeaponInfo( int weaponstate, int weapon, weaponinfo_t* weaponinfo );
int BotChooseBestFightWeapon( int weaponstate, int* inventory );
void BotResetWeaponState( int weaponstate );
int BotAllocWeaponState( void );
void BotFreeWeaponState( int ws );
private:
int BotValidWeaponNumber( int weaponnum );
bot_weaponstate_t* BotWeaponStateFromHandle( int handle );
void WeaponWeightIndex( weightconfig_t* wwc, bot_weaponstate_t* weaponState );
void BotFreeWeaponWeights( int weaponstate );
private:
void LoadWeaponConfig( char* filename );
void ParseWeaponInfo( idParser& parser, weaponinfo_t& newWeaponInfo );
void ParseProjectileInfo( idParser& parser, projectileinfo_t& newProjectileInfo );
private:
idList<projectileinfo_t> projectileinfo;
bot_weaponstate_t botweaponstates[MAX_CLIENTS + 1];
weaponinfo_t weaponinfo[BOT_MAX_WEAPONS];
};
extern idBotWeaponInfoManager botWeaponInfoManager;
+915
View File
@@ -0,0 +1,915 @@
// Bot_wieghts.cpp
//
#include "precompiled.h"
#pragma hdrstop
#include "../Game_local.h"
idBotFuzzyWeightManager botFuzzyWeightManager;
/*
========================
idBotFuzzyWeightManager::Init
========================
*/
void idBotFuzzyWeightManager::Init( void )
{
memset( &fuzzyseperators[0], 0, sizeof( fuzzyseperators ) );
}
/*
========================
idBotFuzzyWeightManager::AllocFuzzyWeight
========================
*/
fuzzyseperator_t* idBotFuzzyWeightManager::AllocFuzzyWeight( void )
{
for( int i = 0; i < MAX_FUZZY_OPERATORS; i++ )
{
if( fuzzyseperators[i].inUse == false )
{
memset( &fuzzyseperators[i], 0, sizeof( fuzzyseperator_t ) );
fuzzyseperators[i].inUse = true;
return &fuzzyseperators[i];
}
}
gameLocal.Error( "AllocFuzzyWeight: Not enough fuzzy weights\n" );
return NULL;
}
/*
========================
idBotFuzzyWeightManager::ReadValue
========================
*/
bool idBotFuzzyWeightManager::ReadValue( idParser& source, float* value )
{
idToken token;
if( !source.ReadToken( &token ) )
{
return false;
}
if( token == "-" )
{
source.Warning( "negative value set to zero\n" );
if( !source.ExpectTokenType( TT_NUMBER, 0, &token ) )
{
return false;
}
}
if( token.type != TT_NUMBER )
{
source.Error( "invalid return value %s\n", token.c_str() );
return false;
}
*value = token.GetFloatValue();
return true;
}
/*
===================
idBotFuzzyWeightManager::ReadFuzzyWeight
===================
*/
int idBotFuzzyWeightManager::ReadFuzzyWeight( idParser& source, fuzzyseperator_t* fs )
{
if( source.CheckTokenString( "balance" ) )
{
fs->type = WT_BALANCE;
if( !source.ExpectTokenString( "(" ) )
{
return false;
}
if( !ReadValue( source, &fs->weight ) )
{
return false;
}
if( !source.ExpectTokenString( "," ) )
{
return false;
}
if( !ReadValue( source, &fs->minweight ) )
{
return false;
}
if( !source.ExpectTokenString( "," ) )
{
return false;
}
if( !ReadValue( source, &fs->maxweight ) )
{
return false;
}
if( !source.ExpectTokenString( ")" ) )
{
return false;
}
}
else
{
fs->type = 0;
if( !ReadValue( source, &fs->weight ) )
{
return false;
}
fs->minweight = fs->weight;
fs->maxweight = fs->weight;
}
if( !source.ExpectTokenString( ";" ) )
{
return false;
}
return true;
}
/*
===================
idBotFuzzyWeightManager::FreeFuzzySeperators_r
===================
*/
void idBotFuzzyWeightManager::FreeFuzzySeperators_r( fuzzyseperator_t* fs )
{
if( !fs )
{
return;
}
if( fs->child )
{
FreeFuzzySeperators_r( fs->child );
}
if( fs->next )
{
FreeFuzzySeperators_r( fs->next );
}
fs->inUse = false;
}
/*
===================
FreeWeightConfig2
===================
*/
void idBotFuzzyWeightManager::FreeWeightConfig2( weightconfig_t* config )
{
int i;
for( i = 0; i < config->numweights; i++ )
{
FreeFuzzySeperators_r( config->weights[i].firstseperator );
// jmarshall - todo
//if (config->weights[i].name)
// FreeMemory(config->weights[i].name);
// jmarshall end
}
}
/*
===================
idBotFuzzyWeightManager::FreeWeightConfig
===================
*/
void idBotFuzzyWeightManager::FreeWeightConfig( weightconfig_t* config )
{
//if (!LibVarGetValue("bot_reloadcharacters"))
// return;
FreeWeightConfig2( config );
}
/*
===================
idBotFuzzyWeightManager::ReadFuzzySeperators_r
===================
*/
fuzzyseperator_t* idBotFuzzyWeightManager::ReadFuzzySeperators_r( idParser& source )
{
int newindent, index, founddefault;
bool def;
idToken token;
fuzzyseperator_t* fs, * lastfs, * firstfs;
founddefault = false;
firstfs = NULL;
lastfs = NULL;
if( !source.ExpectTokenString( "(" ) )
{
return NULL;
}
if( !source.ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) )
{
return NULL;
}
index = token.GetIntValue();
if( !source.ExpectTokenString( ")" ) )
{
return NULL;
}
if( !source.ExpectTokenString( "{" ) )
{
return NULL;
}
if( !source.ExpectAnyToken( &token ) )
{
return NULL;
}
do
{
def = ( token == "default" ); //!strcmp(token.string, "default");
if( def || ( token == "case" ) )
{
fs = AllocFuzzyWeight();
fs->index = index;
if( lastfs )
{
lastfs->next = fs;
}
else
{
firstfs = fs;
}
lastfs = fs;
if( def )
{
if( founddefault )
{
FreeFuzzySeperators_r( firstfs );
gameLocal.Error( "switch already has a default\n" );
return NULL;
}
fs->value = MAX_INVENTORYVALUE;
founddefault = true;
}
else
{
if( !source.ExpectTokenType( TT_NUMBER, TT_INTEGER, &token ) )
{
FreeFuzzySeperators_r( firstfs );
return NULL;
}
fs->value = token.GetIntValue();
}
if( !source.ExpectTokenString( ":" ) || !source.ExpectAnyToken( &token ) )
{
FreeFuzzySeperators_r( firstfs );
return NULL;
}
newindent = false;
if( token == "{" )
{
newindent = true;
if( !source.ExpectAnyToken( &token ) )
{
FreeFuzzySeperators_r( firstfs );
return NULL;
}
}
if( token == "return" )
{
if( !ReadFuzzyWeight( source, fs ) )
{
FreeFuzzySeperators_r( firstfs );
return NULL;
}
}
else if( token == "switch" )
{
fs->child = ReadFuzzySeperators_r( source );
if( !fs->child )
{
FreeFuzzySeperators_r( firstfs );
return NULL;
}
}
else
{
gameLocal.Error( "invalid name %s\n", token.c_str() );
return NULL;
}
if( newindent )
{
if( !source.ExpectTokenString( "}" ) )
{
FreeFuzzySeperators_r( firstfs );
return NULL;
}
}
}
else
{
gameLocal.Error( "invalid name %s\n", token.c_str() );
FreeFuzzySeperators_r( firstfs );
return NULL;
}
if( !source.ExpectAnyToken( &token ) )
{
FreeFuzzySeperators_r( firstfs );
return NULL;
}
}
while( token != "}" );
if( !founddefault )
{
source.Warning( "switch without default\n" );
fs = AllocFuzzyWeight();
fs->index = index;
fs->value = MAX_INVENTORYVALUE;
fs->weight = 0;
fs->next = NULL;
fs->child = NULL;
if( lastfs )
{
lastfs->next = fs;
}
else
{
firstfs = fs;
}
lastfs = fs;
}
return firstfs;
}
/*
=====================
idBotFuzzyWeightManager::ReadWeightConfig
=====================
*/
weightconfig_t* idBotFuzzyWeightManager::ReadWeightConfig( char* filename )
{
int newindent, avail = 0, n;
idToken token;
idParser source;
fuzzyseperator_t* fs;
weightconfig_t* config = NULL;
avail = -1;
for( n = 0; n < MAX_WEIGHT_FILES; n++ )
{
config = &weightFileList[n];
if( config->inUse )
{
continue;
}
if( config->filename == filename )
{
return config;
}
avail = n;
break;
}
if( avail == -1 )
{
gameLocal.Error( "weightFileList was full trying to load %s\n", filename );
return NULL;
}
rvmScopedLexerBaseFolder scopedBaseFolder( BOTFILESBASEFOLDER );
if( !source.LoadFile( filename ) )
{
gameLocal.Error( "couldn't load %s\n", filename );
return NULL;
}
config = &weightFileList[avail];
config->Reset();
config->filename = filename;
//parse the item config file
while( source.ReadToken( &token ) )
{
if( token == "weight" )
{
if( config->numweights >= MAX_WEIGHTS )
{
gameLocal.Error( "too many fuzzy weights\n" );
break;
}
if( !source.ExpectTokenType( TT_STRING, 0, &token ) )
{
FreeWeightConfig( config );
return NULL;
}
token.StripDoubleQuotes();
config->weights[config->numweights].name = token.c_str();
if( !source.ExpectAnyToken( &token ) )
{
FreeWeightConfig( config );
return NULL;
}
newindent = false;
if( token == "{" )
{
newindent = true;
if( !source.ExpectAnyToken( &token ) )
{
FreeWeightConfig( config );
return NULL;
}
}
if( token == "switch" )
{
fs = ReadFuzzySeperators_r( source );
if( !fs )
{
FreeWeightConfig( config );
return NULL;
}
config->weights[config->numweights].firstseperator = fs;
}
else if( token == "return" )
{
fs = ( fuzzyseperator_t* )AllocFuzzyWeight();
fs->index = 0;
fs->value = MAX_INVENTORYVALUE;
fs->next = NULL;
fs->child = NULL;
if( !ReadFuzzyWeight( source, fs ) )
{
FreeWeightConfig( config );
return NULL;
}
config->weights[config->numweights].firstseperator = fs;
}
else
{
gameLocal.Error( "invalid name %s\n", token.c_str() );
FreeWeightConfig( config );
return NULL;
}
if( newindent )
{
if( !source.ExpectTokenString( "}" ) )
{
FreeWeightConfig( config );
return NULL;
}
}
config->numweights++;
}
else
{
gameLocal.Error( "invalid name %s\n", token.c_str() );
FreeWeightConfig( config );
return NULL;
}
}
//if the file was located in a pak file
common->Printf( "idBotFuzzyWeightManager::ReadWeightConfig: loaded %s\n", filename );
config->inUse = true;
return config;
}
/*
==================
idBotFuzzyWeightManager::FindFuzzyWeight
==================
*/
int idBotFuzzyWeightManager::FindFuzzyWeight( weightconfig_t* wc, char* name )
{
int i;
for( i = 0; i < wc->numweights; i++ )
{
if( wc->weights[i].name == name )
{
return i;
}
}
return -1;
}
/*
==================
idBotFuzzyWeightManager::FuzzyWeight_r
==================
*/
float idBotFuzzyWeightManager::FuzzyWeight_r( int* inventory, fuzzyseperator_t* fs )
{
float scale, w1, w2;
if( inventory[fs->index] < fs->value )
{
if( fs->child )
{
return FuzzyWeight_r( inventory, fs->child );
}
else
{
return fs->weight;
}
}
else if( fs->next )
{
if( inventory[fs->index] < fs->next->value )
{
//first weight
if( fs->child )
{
w1 = FuzzyWeight_r( inventory, fs->child );
}
else
{
w1 = fs->weight;
}
//second weight
if( fs->next->child )
{
w2 = FuzzyWeight_r( inventory, fs->next->child );
}
else
{
w2 = fs->next->weight;
}
//the scale factor
scale = ( inventory[fs->index] - fs->value ) / ( fs->next->value - fs->value );
//scale between the two weights
return scale * w1 + ( 1 - scale ) * w2;
}
return FuzzyWeight_r( inventory, fs->next );
}
return fs->weight;
}
/*
============================
idBotFuzzyWeightManager::FuzzyWeightUndecided_r
============================
*/
float idBotFuzzyWeightManager::FuzzyWeightUndecided_r( int* inventory, fuzzyseperator_t* fs )
{
float scale, w1, w2;
if( inventory[fs->index] < fs->value )
{
if( fs->child )
{
return FuzzyWeightUndecided_r( inventory, fs->child );
}
else
{
return fs->minweight + rvmBotUtil::random() * ( fs->maxweight - fs->minweight );
}
}
else if( fs->next )
{
if( inventory[fs->index] < fs->next->value )
{
//first weight
if( fs->child )
{
w1 = FuzzyWeightUndecided_r( inventory, fs->child );
}
else
{
w1 = fs->minweight + rvmBotUtil::random() * ( fs->maxweight - fs->minweight );
}
//second weight
if( fs->next->child )
{
w2 = FuzzyWeight_r( inventory, fs->next->child );
}
else
{
w2 = fs->next->minweight + rvmBotUtil::random() * ( fs->next->maxweight - fs->next->minweight );
}
//the scale factor
scale = ( inventory[fs->index] - fs->value ) / ( fs->next->value - fs->value );
//scale between the two weights
return scale * w1 + ( 1 - scale ) * w2;
}
return FuzzyWeightUndecided_r( inventory, fs->next );
}
return fs->weight;
}
/*
=================
idBotFuzzyWeightManager::FuzzyWeight
=================
*/
float idBotFuzzyWeightManager::FuzzyWeight( int* inventory, weightconfig_t* wc, int weightnum )
{
return FuzzyWeight_r( inventory, wc->weights[weightnum].firstseperator );
}
/*
=================
idBotFuzzyWeightManager::FuzzyWeightUndecided
=================
*/
float idBotFuzzyWeightManager::FuzzyWeightUndecided( int* inventory, weightconfig_t* wc, int weightnum )
{
return FuzzyWeightUndecided_r( inventory, wc->weights[weightnum].firstseperator );
}
/*
====================
idBotFuzzyWeightManager::EvolveFuzzySeperator_r
====================
*/
void idBotFuzzyWeightManager::EvolveFuzzySeperator_r( fuzzyseperator_t* fs )
{
if( fs->child )
{
EvolveFuzzySeperator_r( fs->child );
}
else if( fs->type == WT_BALANCE )
{
//every once in a while an evolution leap occurs, mutation
if( rvmBotUtil::random() < 0.01 )
{
fs->weight += rvmBotUtil::crandom() * ( fs->maxweight - fs->minweight );
}
else
{
fs->weight += rvmBotUtil::crandom() * ( fs->maxweight - fs->minweight ) * 0.5;
}
//modify bounds if necesary because of mutation
if( fs->weight < fs->minweight )
{
fs->minweight = fs->weight;
}
else if( fs->weight > fs->maxweight )
{
fs->maxweight = fs->weight;
}
}
if( fs->next )
{
EvolveFuzzySeperator_r( fs->next );
}
}
/*
====================
idBotFuzzyWeightManager::EvolveWeightConfig
====================
*/
void idBotFuzzyWeightManager::EvolveWeightConfig( weightconfig_t* config )
{
int i;
for( i = 0; i < config->numweights; i++ )
{
EvolveFuzzySeperator_r( config->weights[i].firstseperator );
}
}
/*
====================
idBotFuzzyWeightManager::ScaleWeight
====================
*/
void idBotFuzzyWeightManager::ScaleFuzzySeperator_r( fuzzyseperator_t* fs, float scale )
{
if( fs->child )
{
ScaleFuzzySeperator_r( fs->child, scale );
}
else if( fs->type == WT_BALANCE )
{
fs->weight = ( fs->maxweight + fs->minweight ) * scale;
//get the weight between bounds
if( fs->weight < fs->minweight )
{
fs->weight = fs->minweight;
}
else if( fs->weight > fs->maxweight )
{
fs->weight = fs->maxweight;
}
}
if( fs->next )
{
ScaleFuzzySeperator_r( fs->next, scale );
}
}
/*
====================
idBotFuzzyWeightManager::ScaleWeight
====================
*/
void idBotFuzzyWeightManager::ScaleWeight( weightconfig_t* config, char* name, float scale )
{
int i;
if( scale < 0 )
{
scale = 0;
}
else if( scale > 1 )
{
scale = 1;
}
for( i = 0; i < config->numweights; i++ )
{
if( config->weights[i].name == name )
{
ScaleFuzzySeperator_r( config->weights[i].firstseperator, scale );
break;
}
}
}
/*
====================
idBotFuzzyWeightManager::ScaleFuzzySeperatorBalanceRange_r
====================
*/
void idBotFuzzyWeightManager::ScaleFuzzySeperatorBalanceRange_r( fuzzyseperator_t* fs, float scale )
{
if( fs->child )
{
ScaleFuzzySeperatorBalanceRange_r( fs->child, scale );
}
else if( fs->type == WT_BALANCE )
{
float mid = ( fs->minweight + fs->maxweight ) * 0.5;
//get the weight between bounds
fs->maxweight = mid + ( fs->maxweight - mid ) * scale;
fs->minweight = mid + ( fs->minweight - mid ) * scale;
if( fs->maxweight < fs->minweight )
{
fs->maxweight = fs->minweight;
}
}
if( fs->next )
{
ScaleFuzzySeperatorBalanceRange_r( fs->next, scale );
}
}
/*
====================
idBotFuzzyWeightManager::ScaleFuzzyBalanceRange
====================
*/
void idBotFuzzyWeightManager::ScaleFuzzyBalanceRange( weightconfig_t* config, float scale )
{
int i;
if( scale < 0 )
{
scale = 0;
}
else if( scale > 100 )
{
scale = 100;
}
for( i = 0; i < config->numweights; i++ )
{
ScaleFuzzySeperatorBalanceRange_r( config->weights[i].firstseperator, scale );
}
}
/*
====================
idBotFuzzyWeightManager::InterbreedFuzzySeperator_r
====================
*/
int idBotFuzzyWeightManager::InterbreedFuzzySeperator_r( fuzzyseperator_t* fs1, fuzzyseperator_t* fs2, fuzzyseperator_t* fsout )
{
if( fs1->child )
{
if( !fs2->child || !fsout->child )
{
gameLocal.Error( "cannot interbreed weight configs, unequal child\n" );
return false;
}
if( !InterbreedFuzzySeperator_r( fs2->child, fs2->child, fsout->child ) )
{
return false;
}
}
else if( fs1->type == WT_BALANCE )
{
if( fs2->type != WT_BALANCE || fsout->type != WT_BALANCE )
{
gameLocal.Error( "cannot interbreed weight configs, unequal balance\n" );
return false;
}
fsout->weight = ( fs1->weight + fs2->weight ) / 2;
if( fsout->weight > fsout->maxweight )
{
fsout->maxweight = fsout->weight;
}
if( fsout->weight > fsout->minweight )
{
fsout->minweight = fsout->weight;
}
}
if( fs1->next )
{
if( !fs2->next || !fsout->next )
{
gameLocal.Error( "cannot interbreed weight configs, unequal next\n" );
return false;
}
if( !InterbreedFuzzySeperator_r( fs1->next, fs2->next, fsout->next ) )
{
return false;
}
}
return true;
}
/*
====================
idBotFuzzyWeightManager::InterbreedWeightConfigs
====================
*/
void idBotFuzzyWeightManager::InterbreedWeightConfigs( weightconfig_t* config1, weightconfig_t* config2, weightconfig_t* configout )
{
int i;
if( config1->numweights != config2->numweights ||
config1->numweights != configout->numweights )
{
gameLocal.Error( "cannot interbreed weight configs, unequal numweights\n" );
return;
}
for( i = 0; i < config1->numweights; i++ )
{
InterbreedFuzzySeperator_r( config1->weights[i].firstseperator,
config2->weights[i].firstseperator,
configout->weights[i].firstseperator );
}
}
/*
=======================
idBotFuzzyWeightManager::BotShutdownWeights
=======================
*/
void idBotFuzzyWeightManager::BotShutdownWeights( void )
{
int i;
for( i = 0; i < MAX_WEIGHT_FILES; i++ )
{
weightFileList[i].inUse = false;
//if (weightFileList[i])
//{
// FreeWeightConfig2(weightFileList[i]);
// weightFileList[i] = NULL;
//}
}
}
+53
View File
@@ -0,0 +1,53 @@
// Bot_weights.h
//
#define MAX_INVENTORYVALUE 999999
#define EVALUATERECURSIVELY
#define MAX_WEIGHT_FILES 128
#define MAX_FUZZY_OPERATORS 8192
class idBotFuzzyWeightManager
{
public:
// Init the fuzzy weight manager.
void Init( void );
// Parses a weight config file.
weightconfig_t* ReadWeightConfig( char* filename );
void BotShutdownWeights( void );
// Fuzzy Weight simulation functions.
int FindFuzzyWeight( weightconfig_t* wc, char* name );
float FuzzyWeight( int* inventory, weightconfig_t* wc, int weightnum );
float FuzzyWeightUndecided( int* inventory, weightconfig_t* wc, int weightnum );
void EvolveFuzzySeperator_r( fuzzyseperator_t* fs );
void EvolveWeightConfig( weightconfig_t* config );
void ScaleWeight( weightconfig_t* config, char* name, float scale );
void ScaleFuzzyBalanceRange( weightconfig_t* config, float scale );
void InterbreedWeightConfigs( weightconfig_t* config1, weightconfig_t* config2, weightconfig_t* configout );
void FreeWeightConfig( weightconfig_t* config );
private:
fuzzyseperator_t* AllocFuzzyWeight( void );
bool ReadValue( idParser& source, float* value );
int ReadFuzzyWeight( idParser& source, fuzzyseperator_t* fs );
int InterbreedFuzzySeperator_r( fuzzyseperator_t* fs1, fuzzyseperator_t* fs2, fuzzyseperator_t* fsout );
fuzzyseperator_t* ReadFuzzySeperators_r( idParser& source );
void FreeWeightConfig2( weightconfig_t* config );
void FreeFuzzySeperators_r( fuzzyseperator_t* fs );
void ScaleFuzzySeperatorBalanceRange_r( fuzzyseperator_t* fs, float scale );
void ScaleFuzzySeperator_r( fuzzyseperator_t* fs, float scale );
float FuzzyWeight_r( int* inventory, fuzzyseperator_t* fs );
float FuzzyWeightUndecided_r( int* inventory, fuzzyseperator_t* fs );
weightconfig_t weightFileList[MAX_WEIGHT_FILES];
fuzzyseperator_t fuzzyseperators[MAX_FUZZY_OPERATORS];
};
extern idBotFuzzyWeightManager botFuzzyWeightManager;
File diff suppressed because it is too large Load Diff
+228 -64
View File
@@ -7,10 +7,10 @@
This file has been generated with the Type Info Generator v1.1 (c) 2004 id Software
1178 constants
131 enums
536 classes/structs/unions
37 templates
1172 constants
130 enums
556 classes/structs/unions
38 templates
7 max inheritance level for 'idAI_Vagary'
===================================================================================
@@ -952,12 +952,6 @@ static constantInfo_t constantInfo[] = {
{ "int", "idProjectile::LAUNCHED", "2" },
{ "int", "idProjectile::FIZZLED", "3" },
{ "int", "idProjectile::EXPLODED", "4" },
{ "int", "WP_READY", "0" },
{ "int", "WP_OUTOFAMMO", "1" },
{ "int", "WP_RELOAD", "2" },
{ "int", "WP_HOLSTERED", "3" },
{ "int", "WP_RISING", "4" },
{ "int", "WP_LOWERING", "5" },
{ "static const int", "AMMO_NUMTYPES", "16" },
{ "static const int", "LIGHTID_WORLD_MUZZLE_FLASH", "1" },
{ "static const int", "LIGHTID_VIEW_MUZZLE_FLASH", "100" },
@@ -2381,17 +2375,7 @@ static enumValueInfo_t idProjectile_projectileState_t_typeInfo[] = {
{ NULL, 0 }
};
static enumValueInfo_t weaponStatus_t_typeInfo[] = {
{ "WP_READY", 0 },
{ "WP_OUTOFAMMO", 1 },
{ "WP_RELOAD", 2 },
{ "WP_HOLSTERED", 3 },
{ "WP_RISING", 4 },
{ "WP_LOWERING", 5 },
{ NULL, 0 }
};
static enumValueInfo_t idWeapon_enum_108_typeInfo[] = {
static enumValueInfo_t idWeapon_enum_107_typeInfo[] = {
{ "EVENT_RELOAD", 2 },
{ "EVENT_ENDRELOAD", 3 },
{ "EVENT_CHANGESKIN", 4 },
@@ -2399,13 +2383,13 @@ static enumValueInfo_t idWeapon_enum_108_typeInfo[] = {
{ NULL, 0 }
};
static enumValueInfo_t idLight_enum_109_typeInfo[] = {
static enumValueInfo_t idLight_enum_108_typeInfo[] = {
{ "EVENT_BECOMEBROKEN", 2 },
{ "EVENT_MAXEVENTS", 3 },
{ NULL, 0 }
};
static enumValueInfo_t idItem_enum_110_typeInfo[] = {
static enumValueInfo_t idItem_enum_109_typeInfo[] = {
{ "EVENT_PICKUP", 2 },
{ "EVENT_RESPAWN", 3 },
{ "EVENT_RESPAWNFX", 4 },
@@ -2420,7 +2404,7 @@ static enumValueInfo_t playerIconType_t_typeInfo[] = {
{ NULL, 0 }
};
static enumValueInfo_t enum_112_typeInfo[] = {
static enumValueInfo_t enum_111_typeInfo[] = {
{ "BERSERK", 0 },
{ "INVISIBILITY", 1 },
{ "MEGAHEALTH", 2 },
@@ -2429,7 +2413,7 @@ static enumValueInfo_t enum_112_typeInfo[] = {
{ NULL, 0 }
};
static enumValueInfo_t enum_113_typeInfo[] = {
static enumValueInfo_t enum_112_typeInfo[] = {
{ "SPEED", 0 },
{ "PROJECTILE_DAMAGE", 1 },
{ "MELEE_DAMAGE", 2 },
@@ -2437,7 +2421,7 @@ static enumValueInfo_t enum_113_typeInfo[] = {
{ NULL, 0 }
};
static enumValueInfo_t enum_114_typeInfo[] = {
static enumValueInfo_t enum_113_typeInfo[] = {
{ "INFLUENCE_NONE", 0 },
{ "INFLUENCE_LEVEL1", 1 },
{ "INFLUENCE_LEVEL2", 2 },
@@ -2445,7 +2429,7 @@ static enumValueInfo_t enum_114_typeInfo[] = {
{ NULL, 0 }
};
static enumValueInfo_t idPlayer_enum_115_typeInfo[] = {
static enumValueInfo_t idPlayer_enum_114_typeInfo[] = {
{ "EVENT_IMPULSE", 2 },
{ "EVENT_EXIT_TELEPORTER", 3 },
{ "EVENT_ABORT_TELEPORTER", 4 },
@@ -2502,7 +2486,7 @@ static enumValueInfo_t moverState_t_typeInfo[] = {
{ NULL, 0 }
};
static enumValueInfo_t idExplodingBarrel_enum_121_typeInfo[] = {
static enumValueInfo_t idExplodingBarrel_enum_120_typeInfo[] = {
{ "EVENT_EXPLODE", 2 },
{ "EVENT_MAXEVENTS", 3 },
{ NULL, 0 }
@@ -2516,7 +2500,7 @@ static enumValueInfo_t idExplodingBarrel_explode_state_t_typeInfo[] = {
{ NULL, 0 }
};
static enumValueInfo_t idSecurityCamera_enum_123_typeInfo[] = {
static enumValueInfo_t idSecurityCamera_enum_122_typeInfo[] = {
{ "SCANNING", 0 },
{ "LOSINGINTEREST", 1 },
{ "ALERT", 2 },
@@ -2524,7 +2508,7 @@ static enumValueInfo_t idSecurityCamera_enum_123_typeInfo[] = {
{ NULL, 0 }
};
static enumValueInfo_t idBrittleFracture_enum_124_typeInfo[] = {
static enumValueInfo_t idBrittleFracture_enum_123_typeInfo[] = {
{ "EVENT_PROJECT_DECAL", 2 },
{ "EVENT_SHATTER", 3 },
{ "EVENT_MAXEVENTS", 4 },
@@ -2591,7 +2575,7 @@ static enumValueInfo_t stopEvent_t_typeInfo[] = {
{ NULL, 0 }
};
static enumValueInfo_t enum_130_typeInfo[] = {
static enumValueInfo_t enum_129_typeInfo[] = {
{ "OP_RETURN", 0 },
{ "OP_UINC_F", 1 },
{ "OP_UINCP_F", 2 },
@@ -2827,30 +2811,29 @@ static enumTypeInfo_t enumTypeInfo[] = {
{ "idPlayerStart::enum_104", idPlayerStart_enum_104_typeInfo },
{ "idProjectile::enum_105", idProjectile_enum_105_typeInfo },
{ "idProjectile::projectileState_t", idProjectile_projectileState_t_typeInfo },
{ "weaponStatus_t", weaponStatus_t_typeInfo },
{ "idWeapon::enum_108", idWeapon_enum_108_typeInfo },
{ "idLight::enum_109", idLight_enum_109_typeInfo },
{ "idItem::enum_110", idItem_enum_110_typeInfo },
{ "idWeapon::enum_107", idWeapon_enum_107_typeInfo },
{ "idLight::enum_108", idLight_enum_108_typeInfo },
{ "idItem::enum_109", idItem_enum_109_typeInfo },
{ "playerIconType_t", playerIconType_t_typeInfo },
{ "enum_111", enum_111_typeInfo },
{ "enum_112", enum_112_typeInfo },
{ "enum_113", enum_113_typeInfo },
{ "enum_114", enum_114_typeInfo },
{ "idPlayer::enum_115", idPlayer_enum_115_typeInfo },
{ "idPlayer::enum_114", idPlayer_enum_114_typeInfo },
{ "idMover::moveStage_t", idMover_moveStage_t_typeInfo },
{ "idMover::moverCommand_t", idMover_moverCommand_t_typeInfo },
{ "idMover::moverDir_t", idMover_moverDir_t_typeInfo },
{ "idElevator::elevatorState_t", idElevator_elevatorState_t_typeInfo },
{ "moverState_t", moverState_t_typeInfo },
{ "idExplodingBarrel::enum_121", idExplodingBarrel_enum_121_typeInfo },
{ "idExplodingBarrel::enum_120", idExplodingBarrel_enum_120_typeInfo },
{ "idExplodingBarrel::explode_state_t", idExplodingBarrel_explode_state_t_typeInfo },
{ "idSecurityCamera::enum_123", idSecurityCamera_enum_123_typeInfo },
{ "idBrittleFracture::enum_124", idBrittleFracture_enum_124_typeInfo },
{ "idSecurityCamera::enum_122", idSecurityCamera_enum_122_typeInfo },
{ "idBrittleFracture::enum_123", idBrittleFracture_enum_123_typeInfo },
{ "moveType_t", moveType_t_typeInfo },
{ "moveCommand_t", moveCommand_t_typeInfo },
{ "talkState_t", talkState_t_typeInfo },
{ "moveStatus_t", moveStatus_t_typeInfo },
{ "stopEvent_t", stopEvent_t_typeInfo },
{ "enum_130", enum_130_typeInfo },
{ "enum_129", enum_129_typeInfo },
{ NULL, NULL }
};
@@ -2945,6 +2928,10 @@ static classVariableInfo_t idMath_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t rvRandom_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t idRandom_typeInfo[] = {
{ ": int", "seed", (intptr_t)(&((idRandom *)0)->seed), sizeof( ((idRandom *)0)->seed ) },
{ NULL, 0 }
@@ -4001,9 +3988,9 @@ static classVariableInfo_t glRaytracingVec3_t_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t glRaytracingLight_s_class_171_typeInfo[] = {
// { "float", "pad1", (intptr_t)(&((glRaytracingLight_s::class_171 *)0)->pad1), sizeof( ((glRaytracingLight_s::class_171 *)0)->pad1 ) },
// { "float", "volumetricScattering", (intptr_t)(&((glRaytracingLight_s::class_171 *)0)->volumetricScattering), sizeof( ((glRaytracingLight_s::class_171 *)0)->volumetricScattering ) },
static classVariableInfo_t glRaytracingLight_s_class_172_typeInfo[] = {
// { "float", "pad1", (intptr_t)(&((glRaytracingLight_s::class_172 *)0)->pad1), sizeof( ((glRaytracingLight_s::class_172 *)0)->pad1 ) },
// { "float", "volumetricScattering", (intptr_t)(&((glRaytracingLight_s::class_172 *)0)->volumetricScattering), sizeof( ((glRaytracingLight_s::class_172 *)0)->volumetricScattering ) },
{ NULL, 0 }
};
@@ -5120,11 +5107,11 @@ static classVariableInfo_t frameLookup_t_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t class_280_class_280_typeInfo[] = {
// { "const idSoundShader *", "soundShader", (intptr_t)(&((class_280::class_280 *)0)->soundShader), sizeof( ((class_280::class_280 *)0)->soundShader ) },
// { "const function_t *", "function", (intptr_t)(&((class_280::class_280 *)0)->function), sizeof( ((class_280::class_280 *)0)->function ) },
// { "const idDeclSkin *", "skin", (intptr_t)(&((class_280::class_280 *)0)->skin), sizeof( ((class_280::class_280 *)0)->skin ) },
// { "int", "index", (intptr_t)(&((class_280::class_280 *)0)->index), sizeof( ((class_280::class_280 *)0)->index ) },
static classVariableInfo_t class_281_class_281_typeInfo[] = {
// { "const idSoundShader *", "soundShader", (intptr_t)(&((class_281::class_281 *)0)->soundShader), sizeof( ((class_281::class_281 *)0)->soundShader ) },
// { "const function_t *", "function", (intptr_t)(&((class_281::class_281 *)0)->function), sizeof( ((class_281::class_281 *)0)->function ) },
// { "const idDeclSkin *", "skin", (intptr_t)(&((class_281::class_281 *)0)->skin), sizeof( ((class_281::class_281 *)0)->skin ) },
// { "int", "index", (intptr_t)(&((class_281::class_281 *)0)->index), sizeof( ((class_281::class_281 *)0)->index ) },
{ NULL, 0 }
};
@@ -5462,6 +5449,12 @@ static classVariableInfo_t idEventQueue_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t rvmGameDelayRemoveEntry_t_typeInfo[] = {
{ "int32_t", "removeTime", (intptr_t)(&((rvmGameDelayRemoveEntry_t *)0)->removeTime), sizeof( ((rvmGameDelayRemoveEntry_t *)0)->removeTime ) },
{ "idEntity *", "entity", (intptr_t)(&((rvmGameDelayRemoveEntry_t *)0)->entity), sizeof( ((rvmGameDelayRemoveEntry_t *)0)->entity ) },
{ NULL, 0 }
};
static classVariableInfo_t idGameLocal_typeInfo[] = {
{ ": idDict", "serverInfo", (intptr_t)(&((idGameLocal *)0)->serverInfo), sizeof( ((idGameLocal *)0)->serverInfo ) },
{ "int", "numClients", (intptr_t)(&((idGameLocal *)0)->numClients), sizeof( ((idGameLocal *)0)->numClients ) },
@@ -5547,6 +5540,7 @@ static classVariableInfo_t idGameLocal_typeInfo[] = {
{ "idDict", "newInfo", (intptr_t)(&((idGameLocal *)0)->newInfo), sizeof( ((idGameLocal *)0)->newInfo ) },
{ "idStrList", "shakeSounds", (intptr_t)(&((idGameLocal *)0)->shakeSounds), sizeof( ((idGameLocal *)0)->shakeSounds ) },
{ "byte[16384]", "lagometer", (intptr_t)(&((idGameLocal *)0)->lagometer), sizeof( ((idGameLocal *)0)->lagometer ) },
{ "idList < rvmGameDelayRemoveEntry_t >", "delayRemoveEntities", (intptr_t)(&((idGameLocal *)0)->delayRemoveEntities), sizeof( ((idGameLocal *)0)->delayRemoveEntities ) },
{ NULL, 0 }
};
@@ -6772,20 +6766,39 @@ static classVariableInfo_t idDebris_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t WeaponParticle_t_typeInfo[] = {
{ "char[64]", "name", (intptr_t)(&((WeaponParticle_t *)0)->name), sizeof( ((WeaponParticle_t *)0)->name ) },
{ "char[128]", "particlename", (intptr_t)(&((WeaponParticle_t *)0)->particlename), sizeof( ((WeaponParticle_t *)0)->particlename ) },
{ "bool", "active", (intptr_t)(&((WeaponParticle_t *)0)->active), sizeof( ((WeaponParticle_t *)0)->active ) },
{ "int", "startTime", (intptr_t)(&((WeaponParticle_t *)0)->startTime), sizeof( ((WeaponParticle_t *)0)->startTime ) },
{ "jointHandle_t", "joint", (intptr_t)(&((WeaponParticle_t *)0)->joint), sizeof( ((WeaponParticle_t *)0)->joint ) },
{ "bool", "smoke", (intptr_t)(&((WeaponParticle_t *)0)->smoke), sizeof( ((WeaponParticle_t *)0)->smoke ) },
{ "const idDeclParticle *", "particle", (intptr_t)(&((WeaponParticle_t *)0)->particle), sizeof( ((WeaponParticle_t *)0)->particle ) },
{ "idFuncEmitter *", "emitter", (intptr_t)(&((WeaponParticle_t *)0)->emitter), sizeof( ((WeaponParticle_t *)0)->emitter ) },
{ NULL, 0 }
};
static classVariableInfo_t WeaponLight_t_typeInfo[] = {
{ "char[64]", "name", (intptr_t)(&((WeaponLight_t *)0)->name), sizeof( ((WeaponLight_t *)0)->name ) },
{ "bool", "active", (intptr_t)(&((WeaponLight_t *)0)->active), sizeof( ((WeaponLight_t *)0)->active ) },
{ "int", "startTime", (intptr_t)(&((WeaponLight_t *)0)->startTime), sizeof( ((WeaponLight_t *)0)->startTime ) },
{ "jointHandle_t", "joint", (intptr_t)(&((WeaponLight_t *)0)->joint), sizeof( ((WeaponLight_t *)0)->joint ) },
{ "int", "lightHandle", (intptr_t)(&((WeaponLight_t *)0)->lightHandle), sizeof( ((WeaponLight_t *)0)->lightHandle ) },
{ "renderLight_t", "light", (intptr_t)(&((WeaponLight_t *)0)->light), sizeof( ((WeaponLight_t *)0)->light ) },
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponObject_typeInfo[] = {
{ ": idWeapon *", "owner", (intptr_t)(&((rvmWeaponObject *)0)->owner), sizeof( ((rvmWeaponObject *)0)->owner ) },
{ ": rvStateThread", "stateThread", (intptr_t)(&((rvmWeaponObject *)0)->stateThread), sizeof( ((rvmWeaponObject *)0)->stateThread ) },
{ "float", "next_attack", (intptr_t)(&((rvmWeaponObject *)0)->next_attack), sizeof( ((rvmWeaponObject *)0)->next_attack ) },
{ NULL, 0 }
};
static classVariableInfo_t idWeapon_typeInfo[] = {
{ ": idScriptBool", "WEAPON_ATTACK", (intptr_t)(&((idWeapon *)0)->WEAPON_ATTACK), sizeof( ((idWeapon *)0)->WEAPON_ATTACK ) },
{ "idScriptBool", "WEAPON_RELOAD", (intptr_t)(&((idWeapon *)0)->WEAPON_RELOAD), sizeof( ((idWeapon *)0)->WEAPON_RELOAD ) },
{ "idScriptBool", "WEAPON_NETRELOAD", (intptr_t)(&((idWeapon *)0)->WEAPON_NETRELOAD), sizeof( ((idWeapon *)0)->WEAPON_NETRELOAD ) },
{ "idScriptBool", "WEAPON_NETENDRELOAD", (intptr_t)(&((idWeapon *)0)->WEAPON_NETENDRELOAD), sizeof( ((idWeapon *)0)->WEAPON_NETENDRELOAD ) },
{ "idScriptBool", "WEAPON_NETFIRING", (intptr_t)(&((idWeapon *)0)->WEAPON_NETFIRING), sizeof( ((idWeapon *)0)->WEAPON_NETFIRING ) },
{ "idScriptBool", "WEAPON_RAISEWEAPON", (intptr_t)(&((idWeapon *)0)->WEAPON_RAISEWEAPON), sizeof( ((idWeapon *)0)->WEAPON_RAISEWEAPON ) },
{ "idScriptBool", "WEAPON_LOWERWEAPON", (intptr_t)(&((idWeapon *)0)->WEAPON_LOWERWEAPON), sizeof( ((idWeapon *)0)->WEAPON_LOWERWEAPON ) },
{ "weaponStatus_t", "status", (intptr_t)(&((idWeapon *)0)->status), sizeof( ((idWeapon *)0)->status ) },
{ "idThread *", "thread", (intptr_t)(&((idWeapon *)0)->thread), sizeof( ((idWeapon *)0)->thread ) },
{ "idStr", "state", (intptr_t)(&((idWeapon *)0)->state), sizeof( ((idWeapon *)0)->state ) },
{ "idStr", "idealState", (intptr_t)(&((idWeapon *)0)->idealState), sizeof( ((idWeapon *)0)->idealState ) },
{ "int", "animBlendFrames", (intptr_t)(&((idWeapon *)0)->animBlendFrames), sizeof( ((idWeapon *)0)->animBlendFrames ) },
{ ": int", "animBlendFrames", (intptr_t)(&((idWeapon *)0)->animBlendFrames), sizeof( ((idWeapon *)0)->animBlendFrames ) },
{ "int", "animDoneTime", (intptr_t)(&((idWeapon *)0)->animDoneTime), sizeof( ((idWeapon *)0)->animDoneTime ) },
{ "bool", "isPlayerFlashlight", (intptr_t)(&((idWeapon *)0)->isPlayerFlashlight), sizeof( ((idWeapon *)0)->isPlayerFlashlight ) },
{ "bool", "isLinked", (intptr_t)(&((idWeapon *)0)->isLinked), sizeof( ((idWeapon *)0)->isLinked ) },
{ "idEntity *", "projectileEnt", (intptr_t)(&((idWeapon *)0)->projectileEnt), sizeof( ((idWeapon *)0)->projectileEnt ) },
{ "idPlayer *", "owner", (intptr_t)(&((idWeapon *)0)->owner), sizeof( ((idWeapon *)0)->owner ) },
@@ -6798,6 +6811,7 @@ static classVariableInfo_t idWeapon_typeInfo[] = {
{ "float", "hideOffset", (intptr_t)(&((idWeapon *)0)->hideOffset), sizeof( ((idWeapon *)0)->hideOffset ) },
{ "bool", "hide", (intptr_t)(&((idWeapon *)0)->hide), sizeof( ((idWeapon *)0)->hide ) },
{ "bool", "disabled", (intptr_t)(&((idWeapon *)0)->disabled), sizeof( ((idWeapon *)0)->disabled ) },
{ "bool", "isFlashLight", (intptr_t)(&((idWeapon *)0)->isFlashLight), sizeof( ((idWeapon *)0)->isFlashLight ) },
{ "int", "berserk", (intptr_t)(&((idWeapon *)0)->berserk), sizeof( ((idWeapon *)0)->berserk ) },
{ "idVec3", "playerViewOrigin", (intptr_t)(&((idWeapon *)0)->playerViewOrigin), sizeof( ((idWeapon *)0)->playerViewOrigin ) },
{ "idMat3", "playerViewAxis", (intptr_t)(&((idWeapon *)0)->playerViewAxis), sizeof( ((idWeapon *)0)->playerViewAxis ) },
@@ -6814,12 +6828,17 @@ static classVariableInfo_t idWeapon_typeInfo[] = {
{ "idDict", "brassDict", (intptr_t)(&((idWeapon *)0)->brassDict), sizeof( ((idWeapon *)0)->brassDict ) },
{ "int", "brassDelay", (intptr_t)(&((idWeapon *)0)->brassDelay), sizeof( ((idWeapon *)0)->brassDelay ) },
{ "idStr", "icon", (intptr_t)(&((idWeapon *)0)->icon), sizeof( ((idWeapon *)0)->icon ) },
{ "idStr", "pdaIcon", (intptr_t)(&((idWeapon *)0)->pdaIcon), sizeof( ((idWeapon *)0)->pdaIcon ) },
{ "idStr", "displayName", (intptr_t)(&((idWeapon *)0)->displayName), sizeof( ((idWeapon *)0)->displayName ) },
{ "idStr", "itemDesc", (intptr_t)(&((idWeapon *)0)->itemDesc), sizeof( ((idWeapon *)0)->itemDesc ) },
{ "renderLight_t", "guiLight", (intptr_t)(&((idWeapon *)0)->guiLight), sizeof( ((idWeapon *)0)->guiLight ) },
{ "int", "guiLightHandle", (intptr_t)(&((idWeapon *)0)->guiLightHandle), sizeof( ((idWeapon *)0)->guiLightHandle ) },
{ "renderLight_t", "muzzleFlash", (intptr_t)(&((idWeapon *)0)->muzzleFlash), sizeof( ((idWeapon *)0)->muzzleFlash ) },
{ "int", "muzzleFlashHandle", (intptr_t)(&((idWeapon *)0)->muzzleFlashHandle), sizeof( ((idWeapon *)0)->muzzleFlashHandle ) },
{ "renderLight_t", "worldMuzzleFlash", (intptr_t)(&((idWeapon *)0)->worldMuzzleFlash), sizeof( ((idWeapon *)0)->worldMuzzleFlash ) },
{ "int", "worldMuzzleFlashHandle", (intptr_t)(&((idWeapon *)0)->worldMuzzleFlashHandle), sizeof( ((idWeapon *)0)->worldMuzzleFlashHandle ) },
{ "float", "fraccos", (intptr_t)(&((idWeapon *)0)->fraccos), sizeof( ((idWeapon *)0)->fraccos ) },
{ "float", "fraccos2", (intptr_t)(&((idWeapon *)0)->fraccos2), sizeof( ((idWeapon *)0)->fraccos2 ) },
{ "idVec3", "flashColor", (intptr_t)(&((idWeapon *)0)->flashColor), sizeof( ((idWeapon *)0)->flashColor ) },
{ "int", "muzzleFlashEnd", (intptr_t)(&((idWeapon *)0)->muzzleFlashEnd), sizeof( ((idWeapon *)0)->muzzleFlashEnd ) },
{ "int", "flashTime", (intptr_t)(&((idWeapon *)0)->flashTime), sizeof( ((idWeapon *)0)->flashTime ) },
@@ -6835,7 +6854,7 @@ static classVariableInfo_t idWeapon_typeInfo[] = {
{ "ammo_t", "ammoType", (intptr_t)(&((idWeapon *)0)->ammoType), sizeof( ((idWeapon *)0)->ammoType ) },
{ "int", "ammoRequired", (intptr_t)(&((idWeapon *)0)->ammoRequired), sizeof( ((idWeapon *)0)->ammoRequired ) },
{ "int", "clipSize", (intptr_t)(&((idWeapon *)0)->clipSize), sizeof( ((idWeapon *)0)->clipSize ) },
{ "int", "ammoClip", (intptr_t)(&((idWeapon *)0)->ammoClip), sizeof( ((idWeapon *)0)->ammoClip ) },
{ "idPredictedValue < int >", "ammoClip", (intptr_t)(&((idWeapon *)0)->ammoClip), sizeof( ((idWeapon *)0)->ammoClip ) },
{ "int", "lowAmmo", (intptr_t)(&((idWeapon *)0)->lowAmmo), sizeof( ((idWeapon *)0)->lowAmmo ) },
{ "bool", "powerAmmo", (intptr_t)(&((idWeapon *)0)->powerAmmo), sizeof( ((idWeapon *)0)->powerAmmo ) },
{ "bool", "isFiring", (intptr_t)(&((idWeapon *)0)->isFiring), sizeof( ((idWeapon *)0)->isFiring ) },
@@ -6848,6 +6867,9 @@ static classVariableInfo_t idWeapon_typeInfo[] = {
{ "jointHandle_t", "flashJointWorld", (intptr_t)(&((idWeapon *)0)->flashJointWorld), sizeof( ((idWeapon *)0)->flashJointWorld ) },
{ "jointHandle_t", "barrelJointWorld", (intptr_t)(&((idWeapon *)0)->barrelJointWorld), sizeof( ((idWeapon *)0)->barrelJointWorld ) },
{ "jointHandle_t", "ejectJointWorld", (intptr_t)(&((idWeapon *)0)->ejectJointWorld), sizeof( ((idWeapon *)0)->ejectJointWorld ) },
{ "jointHandle_t", "smokeJointView", (intptr_t)(&((idWeapon *)0)->smokeJointView), sizeof( ((idWeapon *)0)->smokeJointView ) },
{ "idHashTable < WeaponParticle_t >", "weaponParticles", (intptr_t)(&((idWeapon *)0)->weaponParticles), sizeof( ((idWeapon *)0)->weaponParticles ) },
{ "idHashTable < WeaponLight_t >", "weaponLights", (intptr_t)(&((idWeapon *)0)->weaponLights), sizeof( ((idWeapon *)0)->weaponLights ) },
{ "const idSoundShader *", "sndHum", (intptr_t)(&((idWeapon *)0)->sndHum), sizeof( ((idWeapon *)0)->sndHum ) },
{ "const idDeclParticle *", "weaponSmoke", (intptr_t)(&((idWeapon *)0)->weaponSmoke), sizeof( ((idWeapon *)0)->weaponSmoke ) },
{ "int", "weaponSmokeStartTime", (intptr_t)(&((idWeapon *)0)->weaponSmokeStartTime), sizeof( ((idWeapon *)0)->weaponSmokeStartTime ) },
@@ -6870,6 +6892,9 @@ static classVariableInfo_t idWeapon_typeInfo[] = {
{ "float", "weaponAngleOffsetMax", (intptr_t)(&((idWeapon *)0)->weaponAngleOffsetMax), sizeof( ((idWeapon *)0)->weaponAngleOffsetMax ) },
{ "float", "weaponOffsetTime", (intptr_t)(&((idWeapon *)0)->weaponOffsetTime), sizeof( ((idWeapon *)0)->weaponOffsetTime ) },
{ "float", "weaponOffsetScale", (intptr_t)(&((idWeapon *)0)->weaponOffsetScale), sizeof( ((idWeapon *)0)->weaponOffsetScale ) },
{ "int", "grabberState", (intptr_t)(&((idWeapon *)0)->grabberState), sizeof( ((idWeapon *)0)->grabberState ) },
{ ": rvmWeaponObject *", "currentWeaponObject", (intptr_t)(&((idWeapon *)0)->currentWeaponObject), sizeof( ((idWeapon *)0)->currentWeaponObject ) },
{ "bool", "OutOfAmmo", (intptr_t)(&((idWeapon *)0)->OutOfAmmo), sizeof( ((idWeapon *)0)->OutOfAmmo ) },
{ NULL, 0 }
};
@@ -8056,6 +8081,125 @@ static classVariableInfo_t idThread_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponFist_typeInfo[] = {
{ "bool", "side", (intptr_t)(&((rvmWeaponFist *)0)->side), sizeof( ((rvmWeaponFist *)0)->side ) },
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponPistol_typeInfo[] = {
{ ": float", "spread", (intptr_t)(&((rvmWeaponPistol *)0)->spread), sizeof( ((rvmWeaponPistol *)0)->spread ) },
{ "const idSoundShader *", "snd_lowammo", (intptr_t)(&((rvmWeaponPistol *)0)->snd_lowammo), sizeof( ((rvmWeaponPistol *)0)->snd_lowammo ) },
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponFlashlight_typeInfo[] = {
{ "bool", "on", (intptr_t)(&((rvmWeaponFlashlight *)0)->on), sizeof( ((rvmWeaponFlashlight *)0)->on ) },
{ "float", "intensity", (intptr_t)(&((rvmWeaponFlashlight *)0)->intensity), sizeof( ((rvmWeaponFlashlight *)0)->intensity ) },
{ "idStr", "skin_on", (intptr_t)(&((rvmWeaponFlashlight *)0)->skin_on), sizeof( ((rvmWeaponFlashlight *)0)->skin_on ) },
{ "idStr", "skin_on_invis", (intptr_t)(&((rvmWeaponFlashlight *)0)->skin_on_invis), sizeof( ((rvmWeaponFlashlight *)0)->skin_on_invis ) },
{ "idStr", "skin_off", (intptr_t)(&((rvmWeaponFlashlight *)0)->skin_off), sizeof( ((rvmWeaponFlashlight *)0)->skin_off ) },
{ "idStr", "skin_off_invis", (intptr_t)(&((rvmWeaponFlashlight *)0)->skin_off_invis), sizeof( ((rvmWeaponFlashlight *)0)->skin_off_invis ) },
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponPDA_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponShotgun_typeInfo[] = {
{ ": float", "spread", (intptr_t)(&((rvmWeaponShotgun *)0)->spread), sizeof( ((rvmWeaponShotgun *)0)->spread ) },
{ "const idSoundShader *", "snd_lowammo", (intptr_t)(&((rvmWeaponShotgun *)0)->snd_lowammo), sizeof( ((rvmWeaponShotgun *)0)->snd_lowammo ) },
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponDoubleShotgun_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponMachineGun_typeInfo[] = {
{ ": float", "spread", (intptr_t)(&((rvmWeaponMachineGun *)0)->spread), sizeof( ((rvmWeaponMachineGun *)0)->spread ) },
{ "const idSoundShader *", "snd_lowammo", (intptr_t)(&((rvmWeaponMachineGun *)0)->snd_lowammo), sizeof( ((rvmWeaponMachineGun *)0)->snd_lowammo ) },
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponPlasmaGun_typeInfo[] = {
{ ": float", "spread", (intptr_t)(&((rvmWeaponPlasmaGun *)0)->spread), sizeof( ((rvmWeaponPlasmaGun *)0)->spread ) },
{ "const idSoundShader *", "snd_lowammo", (intptr_t)(&((rvmWeaponPlasmaGun *)0)->snd_lowammo), sizeof( ((rvmWeaponPlasmaGun *)0)->snd_lowammo ) },
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponChainGun_typeInfo[] = {
{ ": idAnimatedEntity *", "world_model", (intptr_t)(&((rvmWeaponChainGun *)0)->world_model), sizeof( ((rvmWeaponChainGun *)0)->world_model ) },
{ "jointHandle_t", "world_barrel_joint", (intptr_t)(&((rvmWeaponChainGun *)0)->world_barrel_joint), sizeof( ((rvmWeaponChainGun *)0)->world_barrel_joint ) },
{ "jointHandle_t", "barrel_joint", (intptr_t)(&((rvmWeaponChainGun *)0)->barrel_joint), sizeof( ((rvmWeaponChainGun *)0)->barrel_joint ) },
{ "float", "barrel_angle", (intptr_t)(&((rvmWeaponChainGun *)0)->barrel_angle), sizeof( ((rvmWeaponChainGun *)0)->barrel_angle ) },
{ "float", "current_rate", (intptr_t)(&((rvmWeaponChainGun *)0)->current_rate), sizeof( ((rvmWeaponChainGun *)0)->current_rate ) },
{ "float", "start_rate", (intptr_t)(&((rvmWeaponChainGun *)0)->start_rate), sizeof( ((rvmWeaponChainGun *)0)->start_rate ) },
{ "float", "end_rate", (intptr_t)(&((rvmWeaponChainGun *)0)->end_rate), sizeof( ((rvmWeaponChainGun *)0)->end_rate ) },
{ "float", "spin_start", (intptr_t)(&((rvmWeaponChainGun *)0)->spin_start), sizeof( ((rvmWeaponChainGun *)0)->spin_start ) },
{ "float", "spin_end", (intptr_t)(&((rvmWeaponChainGun *)0)->spin_end), sizeof( ((rvmWeaponChainGun *)0)->spin_end ) },
{ "float", "spread", (intptr_t)(&((rvmWeaponChainGun *)0)->spread), sizeof( ((rvmWeaponChainGun *)0)->spread ) },
{ "int", "numSkipFrames", (intptr_t)(&((rvmWeaponChainGun *)0)->numSkipFrames), sizeof( ((rvmWeaponChainGun *)0)->numSkipFrames ) },
{ "const idSoundShader *", "snd_windup", (intptr_t)(&((rvmWeaponChainGun *)0)->snd_windup), sizeof( ((rvmWeaponChainGun *)0)->snd_windup ) },
{ "const idSoundShader *", "snd_winddown", (intptr_t)(&((rvmWeaponChainGun *)0)->snd_winddown), sizeof( ((rvmWeaponChainGun *)0)->snd_winddown ) },
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponRocketLauncher_typeInfo[] = {
{ "float", "spread", (intptr_t)(&((rvmWeaponRocketLauncher *)0)->spread), sizeof( ((rvmWeaponRocketLauncher *)0)->spread ) },
{ "idStr", "skin_invisible", (intptr_t)(&((rvmWeaponRocketLauncher *)0)->skin_invisible), sizeof( ((rvmWeaponRocketLauncher *)0)->skin_invisible ) },
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponBFG_typeInfo[] = {
{ "float", "spread", (intptr_t)(&((rvmWeaponBFG *)0)->spread), sizeof( ((rvmWeaponBFG *)0)->spread ) },
{ "float", "fuse_start", (intptr_t)(&((rvmWeaponBFG *)0)->fuse_start), sizeof( ((rvmWeaponBFG *)0)->fuse_start ) },
{ "float", "fuse_end", (intptr_t)(&((rvmWeaponBFG *)0)->fuse_end), sizeof( ((rvmWeaponBFG *)0)->fuse_end ) },
{ "float", "powerLevel", (intptr_t)(&((rvmWeaponBFG *)0)->powerLevel), sizeof( ((rvmWeaponBFG *)0)->powerLevel ) },
{ "float", "fire_time", (intptr_t)(&((rvmWeaponBFG *)0)->fire_time), sizeof( ((rvmWeaponBFG *)0)->fire_time ) },
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponHandgrenade_typeInfo[] = {
{ ": float", "spread", (intptr_t)(&((rvmWeaponHandgrenade *)0)->spread), sizeof( ((rvmWeaponHandgrenade *)0)->spread ) },
{ "float", "fuse_start", (intptr_t)(&((rvmWeaponHandgrenade *)0)->fuse_start), sizeof( ((rvmWeaponHandgrenade *)0)->fuse_start ) },
{ "idStr", "skin_nade", (intptr_t)(&((rvmWeaponHandgrenade *)0)->skin_nade), sizeof( ((rvmWeaponHandgrenade *)0)->skin_nade ) },
{ "idStr", "skin_nade_invis", (intptr_t)(&((rvmWeaponHandgrenade *)0)->skin_nade_invis), sizeof( ((rvmWeaponHandgrenade *)0)->skin_nade_invis ) },
{ "idStr", "skin_nonade", (intptr_t)(&((rvmWeaponHandgrenade *)0)->skin_nonade), sizeof( ((rvmWeaponHandgrenade *)0)->skin_nonade ) },
{ "idStr", "skin_nonade_invis", (intptr_t)(&((rvmWeaponHandgrenade *)0)->skin_nonade_invis), sizeof( ((rvmWeaponHandgrenade *)0)->skin_nonade_invis ) },
{ "idProjectile *", "projectile", (intptr_t)(&((rvmWeaponHandgrenade *)0)->projectile), sizeof( ((rvmWeaponHandgrenade *)0)->projectile ) },
{ "boolean", "show_grenade", (intptr_t)(&((rvmWeaponHandgrenade *)0)->show_grenade), sizeof( ((rvmWeaponHandgrenade *)0)->show_grenade ) },
{ ": float", "fuse_end", (intptr_t)(&((rvmWeaponHandgrenade *)0)->fuse_end), sizeof( ((rvmWeaponHandgrenade *)0)->fuse_end ) },
{ "float", "current_time", (intptr_t)(&((rvmWeaponHandgrenade *)0)->current_time), sizeof( ((rvmWeaponHandgrenade *)0)->current_time ) },
{ "float", "time_held", (intptr_t)(&((rvmWeaponHandgrenade *)0)->time_held), sizeof( ((rvmWeaponHandgrenade *)0)->time_held ) },
{ "float", "power", (intptr_t)(&((rvmWeaponHandgrenade *)0)->power), sizeof( ((rvmWeaponHandgrenade *)0)->power ) },
{ "boolean", "exploded", (intptr_t)(&((rvmWeaponHandgrenade *)0)->exploded), sizeof( ((rvmWeaponHandgrenade *)0)->exploded ) },
{ "const idSoundShader *", "snd_lowammo", (intptr_t)(&((rvmWeaponHandgrenade *)0)->snd_lowammo), sizeof( ((rvmWeaponHandgrenade *)0)->snd_lowammo ) },
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponChainsaw_typeInfo[] = {
{ ": bool", "side", (intptr_t)(&((rvmWeaponChainsaw *)0)->side), sizeof( ((rvmWeaponChainsaw *)0)->side ) },
{ NULL, 0 }
};
static classVariableInfo_t rvmWeaponGrabber_typeInfo[] = {
{ "const idSoundShader *", "snd_fireloop", (intptr_t)(&((rvmWeaponGrabber *)0)->snd_fireloop), sizeof( ((rvmWeaponGrabber *)0)->snd_fireloop ) },
{ "const idSoundShader *", "snd_electroloop", (intptr_t)(&((rvmWeaponGrabber *)0)->snd_electroloop), sizeof( ((rvmWeaponGrabber *)0)->snd_electroloop ) },
{ "const idSoundShader *", "snd_mainfire", (intptr_t)(&((rvmWeaponGrabber *)0)->snd_mainfire), sizeof( ((rvmWeaponGrabber *)0)->snd_mainfire ) },
{ "const idSoundShader *", "snd_cangrab", (intptr_t)(&((rvmWeaponGrabber *)0)->snd_cangrab), sizeof( ((rvmWeaponGrabber *)0)->snd_cangrab ) },
{ "const idSoundShader *", "snd_warning", (intptr_t)(&((rvmWeaponGrabber *)0)->snd_warning), sizeof( ((rvmWeaponGrabber *)0)->snd_warning ) },
{ "const idSoundShader *", "snd_stopfire", (intptr_t)(&((rvmWeaponGrabber *)0)->snd_stopfire), sizeof( ((rvmWeaponGrabber *)0)->snd_stopfire ) },
{ ": float", "next_attack", (intptr_t)(&((rvmWeaponGrabber *)0)->next_attack), sizeof( ((rvmWeaponGrabber *)0)->next_attack ) },
{ "float", "fireStartTime", (intptr_t)(&((rvmWeaponGrabber *)0)->fireStartTime), sizeof( ((rvmWeaponGrabber *)0)->fireStartTime ) },
{ "bool", "warningBeep1", (intptr_t)(&((rvmWeaponGrabber *)0)->warningBeep1), sizeof( ((rvmWeaponGrabber *)0)->warningBeep1 ) },
{ "bool", "warningBeep2", (intptr_t)(&((rvmWeaponGrabber *)0)->warningBeep2), sizeof( ((rvmWeaponGrabber *)0)->warningBeep2 ) },
{ "bool", "warningBeep3", (intptr_t)(&((rvmWeaponGrabber *)0)->warningBeep3), sizeof( ((rvmWeaponGrabber *)0)->warningBeep3 ) },
{ "bool", "warningBeep4", (intptr_t)(&((rvmWeaponGrabber *)0)->warningBeep4), sizeof( ((rvmWeaponGrabber *)0)->warningBeep4 ) },
{ "float", "grabberState", (intptr_t)(&((rvmWeaponGrabber *)0)->grabberState), sizeof( ((rvmWeaponGrabber *)0)->grabberState ) },
{ NULL, 0 }
};
static classTypeInfo_t classTypeInfo[] = {
// { "BITT< unsigned int B >", "", sizeof(BITT< unsigned int B >), BITT_unsigned_int_B__typeInfo },
{ "sysEvent_t", "", sizeof(sysEvent_t), sysEvent_t_typeInfo },
@@ -8081,6 +8225,7 @@ static classTypeInfo_t classTypeInfo[] = {
{ "idSIMDProcessor", "", sizeof(idSIMDProcessor), idSIMDProcessor_typeInfo },
{ "idMath::_flint", "", sizeof(idMath::_flint), idMath__flint_typeInfo },
{ "idMath", "", sizeof(idMath), idMath_typeInfo },
{ "rvRandom", "", sizeof(rvRandom), rvRandom_typeInfo },
{ "idRandom", "", sizeof(idRandom), idRandom_typeInfo },
{ "idRandom2", "", sizeof(idRandom2), idRandom2_typeInfo },
{ "idComplex", "", sizeof(idComplex), idComplex_typeInfo },
@@ -8228,7 +8373,7 @@ static classTypeInfo_t classTypeInfo[] = {
{ "glRaytracingMeshDesc_t", "", sizeof(glRaytracingMeshDesc_t), glRaytracingMeshDesc_t_typeInfo },
{ "glRaytracingInstanceDesc_t", "", sizeof(glRaytracingInstanceDesc_t), glRaytracingInstanceDesc_t_typeInfo },
{ "glRaytracingVec3_t", "", sizeof(glRaytracingVec3_t), glRaytracingVec3_t_typeInfo },
// { "glRaytracingLight_s::class_171", "", sizeof(glRaytracingLight_s::class_171), glRaytracingLight_s_class_171_typeInfo },
// { "glRaytracingLight_s::class_172", "", sizeof(glRaytracingLight_s::class_172), glRaytracingLight_s_class_172_typeInfo },
{ "glRaytracingLight_t", "", sizeof(glRaytracingLight_t), glRaytracingLight_t_typeInfo },
{ "glRaytracingLightingPassDesc_t", "", sizeof(glRaytracingLightingPassDesc_t), glRaytracingLightingPassDesc_t_typeInfo },
{ "QD3D12NeuralPOMImageRGBA8", "", sizeof(QD3D12NeuralPOMImageRGBA8), QD3D12NeuralPOMImageRGBA8_typeInfo },
@@ -8337,7 +8482,7 @@ static classTypeInfo_t classTypeInfo[] = {
{ "jointAnimInfo_t", "", sizeof(jointAnimInfo_t), jointAnimInfo_t_typeInfo },
{ "jointMod_t", "", sizeof(jointMod_t), jointMod_t_typeInfo },
{ "frameLookup_t", "", sizeof(frameLookup_t), frameLookup_t_typeInfo },
// { "class_280::class_280", "", sizeof(class_280::class_280), class_280_class_280_typeInfo },
// { "class_281::class_281", "", sizeof(class_281::class_281), class_281_class_281_typeInfo },
{ "frameCommand_t", "", sizeof(frameCommand_t), frameCommand_t_typeInfo },
{ "animFlags_t", "", sizeof(animFlags_t), animFlags_t_typeInfo },
{ "idModelExport", "", sizeof(idModelExport), idModelExport_typeInfo },
@@ -8370,6 +8515,7 @@ static classTypeInfo_t classTypeInfo[] = {
{ "spawnSpot_t", "", sizeof(spawnSpot_t), spawnSpot_t_typeInfo },
{ "idEventQueue", "", sizeof(idEventQueue), idEventQueue_typeInfo },
// { "idEntityPtr< class type >", "", sizeof(idEntityPtr< class type >), idEntityPtr_class_type__typeInfo },
{ "rvmGameDelayRemoveEntry_t", "", sizeof(rvmGameDelayRemoveEntry_t), rvmGameDelayRemoveEntry_t_typeInfo },
{ "idGameLocal", "idGame", sizeof(idGameLocal), idGameLocal_typeInfo },
{ "idGameError", "idException", sizeof(idGameError), idGameError_typeInfo },
{ "idForce", "idClass", sizeof(idForce), idForce_typeInfo },
@@ -8490,6 +8636,10 @@ static classTypeInfo_t classTypeInfo[] = {
{ "beamTarget_t", "", sizeof(beamTarget_t), beamTarget_t_typeInfo },
{ "idBFGProjectile", "idProjectile", sizeof(idBFGProjectile), idBFGProjectile_typeInfo },
{ "idDebris", "idEntity", sizeof(idDebris), idDebris_typeInfo },
// { "idPredictedValue< class type_ >", "", sizeof(idPredictedValue< class type_ >), idPredictedValue_class_type___typeInfo },
{ "WeaponParticle_t", "", sizeof(WeaponParticle_t), WeaponParticle_t_typeInfo },
{ "WeaponLight_t", "", sizeof(WeaponLight_t), WeaponLight_t_typeInfo },
{ "rvmWeaponObject", "idClass", sizeof(rvmWeaponObject), rvmWeaponObject_typeInfo },
{ "idWeapon", "idAnimatedEntity", sizeof(idWeapon), idWeapon_typeInfo },
{ "idLight", "idEntity", sizeof(idLight), idLight_typeInfo },
{ "idWorldspawn", "idEntity", sizeof(idWorldspawn), idWorldspawn_typeInfo },
@@ -8593,6 +8743,20 @@ static classTypeInfo_t classTypeInfo[] = {
{ "prstack_t", "", sizeof(prstack_t), prstack_t_typeInfo },
{ "idInterpreter", "", sizeof(idInterpreter), idInterpreter_typeInfo },
{ "idThread", "idClass", sizeof(idThread), idThread_typeInfo },
{ "rvmWeaponFist", "rvmWeaponObject", sizeof(rvmWeaponFist), rvmWeaponFist_typeInfo },
{ "rvmWeaponPistol", "rvmWeaponObject", sizeof(rvmWeaponPistol), rvmWeaponPistol_typeInfo },
{ "rvmWeaponFlashlight", "rvmWeaponObject", sizeof(rvmWeaponFlashlight), rvmWeaponFlashlight_typeInfo },
{ "rvmWeaponPDA", "rvmWeaponObject", sizeof(rvmWeaponPDA), rvmWeaponPDA_typeInfo },
{ "rvmWeaponShotgun", "rvmWeaponObject", sizeof(rvmWeaponShotgun), rvmWeaponShotgun_typeInfo },
{ "rvmWeaponDoubleShotgun", "rvmWeaponObject", sizeof(rvmWeaponDoubleShotgun), rvmWeaponDoubleShotgun_typeInfo },
{ "rvmWeaponMachineGun", "rvmWeaponObject", sizeof(rvmWeaponMachineGun), rvmWeaponMachineGun_typeInfo },
{ "rvmWeaponPlasmaGun", "rvmWeaponObject", sizeof(rvmWeaponPlasmaGun), rvmWeaponPlasmaGun_typeInfo },
{ "rvmWeaponChainGun", "rvmWeaponObject", sizeof(rvmWeaponChainGun), rvmWeaponChainGun_typeInfo },
{ "rvmWeaponRocketLauncher", "rvmWeaponObject", sizeof(rvmWeaponRocketLauncher), rvmWeaponRocketLauncher_typeInfo },
{ "rvmWeaponBFG", "rvmWeaponObject", sizeof(rvmWeaponBFG), rvmWeaponBFG_typeInfo },
{ "rvmWeaponHandgrenade", "rvmWeaponObject", sizeof(rvmWeaponHandgrenade), rvmWeaponHandgrenade_typeInfo },
{ "rvmWeaponChainsaw", "rvmWeaponObject", sizeof(rvmWeaponChainsaw), rvmWeaponChainsaw_typeInfo },
{ "rvmWeaponGrabber", "rvmWeaponObject", sizeof(rvmWeaponGrabber), rvmWeaponGrabber_typeInfo },
{ NULL, NULL, 0, NULL }
};
+11 -11
View File
@@ -312,17 +312,17 @@ stateResult_t rvStateThread::Execute( void )
stateName = call->state;
stateStage = call->parms.stage;
if( g_debugState.GetBool() )
{
if( call->parms.stage )
{
gameLocal.Printf( "%s: %s (%d)\n", ((idEntity *)owner)->GetClassname(), call->state.c_str(), call->parms.stage );
}
else
{
gameLocal.Printf( "%s: %s\n", ((idEntity*)owner)->GetClassname(), call->state.c_str() );
}
}
//if( g_debugState.GetBool() )
//{
// if( call->parms.stage )
// {
// gameLocal.Printf( "%s: %s (%d)\n", ((idEntity *)owner)->GetClassname(), call->state.c_str(), call->parms.stage );
// }
// else
// {
// gameLocal.Printf( "%s: %s\n", ((idEntity*)owner)->GetClassname(), call->state.c_str() );
// }
//}
// Actually call the state function
lastResult = ( stateResult_t )owner->Invoke( call->state, &call->parms );
+355
View File
@@ -0,0 +1,355 @@
// Weapon_BFG.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponBFG )
END_CLASS
#define BFG_MINRELEASETIME 0.05
#define BFG_FUSE 2.0
#define BFG_SHORTFUSE 0.5
#define BFG_MAXPOWER 4.0
#define BFG_FIRERATE 4
#define BFG_FIREDELAY 4
#define BFG_NUMPROJECTILES 1
// blend times
#define BFG_IDLE_TO_LOWER 4
#define BFG_IDLE_TO_FIRE 4
#define BFG_IDLE_TO_RELOAD 4
#define BFG_RAISE_TO_IDLE 4
#define BFG_FIRE_TO_IDLE 4
#define BFG_RELOAD_TO_IDLE 4
/*
===============
rvmWeaponBFG::Init
===============
*/
void rvmWeaponBFG::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
next_attack = 0;
fuse_start = 0;
fuse_end = 0;
powerLevel = 0;
fire_time = 0;
spread = weapon->GetFloat( "spread" );
owner->Event_SetGuiFloat( "powerlevel", 0 );
owner->Event_SetGuiFloat( "overcharge", 0 );
}
/*
===============
rvmWeaponBFG::Raise
===============
*/
stateResult_t rvmWeaponBFG::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, BFG_RAISE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponBFG::Lower
===============
*/
stateResult_t rvmWeaponBFG::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponBFG::Idle
===============
*/
stateResult_t rvmWeaponBFG::Idle( stateParms_t* parms )
{
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT
};
switch( parms->stage )
{
case IDLE_NOTSET:
if( !owner->AmmoInClip() )
{
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle_empty" );
owner->Event_WeaponOutOfAmmo();
}
else
{
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle" );
owner->Event_WeaponReady();
}
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
// Do nothing.
return SRESULT_DONE;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponBFG::Fire
===============
*/
stateResult_t rvmWeaponBFG::Fire( stateParms_t* parms )
{
float time_held;
float power = 0.0f;
float intensity;
int ammoClip = owner->AmmoInClip();
enum FIRE_State
{
FIRE_NOTSET = 0,
FIRE_FUSING,
FIRE_SHORTFUSE,
FIRE_SHORTFUSEWAIT,
FIRE_FIRE,
FIRE_FIRE_ANIMWAIT,
FIRE_FIRE_COOLDOWN,
FIRE_DONE
};
if( ammoClip == 0 && owner->AmmoAvailable() && parms->stage == 0 )
{
//owner->WeaponState( WP_RELOAD, PISTOL_IDLE_TO_RELOAD );
owner->Reload();
return SRESULT_DONE;
}
switch( parms->stage )
{
case FIRE_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "fire_begin", false );
fuse_start = gameLocal.time;
fuse_end = gameLocal.time + SEC2MS( BFG_FUSE );
parms->stage = FIRE_FUSING;
return SRESULT_WAIT;
case FIRE_FUSING:
if( !owner->IsFiring() )
{
parms->stage = FIRE_FIRE;
}
else if( gameLocal.time > gameLocal.time + SEC2MS( BFG_MINRELEASETIME ) && !owner->IsFiring() )
{
parms->stage = FIRE_SHORTFUSE;
}
else if( gameLocal.time >= fuse_end )
{
parms->stage = FIRE_SHORTFUSE;
}
else
{
powerLevel = ( gameLocal.time - fuse_start ) / BFG_FUSE;
owner->Event_SetColor( powerLevel, powerLevel, powerLevel );
owner->Event_SetGuiFloat( "powerlevel", powerLevel );
}
return SRESULT_WAIT;
case FIRE_SHORTFUSE:
if( owner->IsFiring() )
{
fuse_end = gameLocal.time + SEC2MS( BFG_SHORTFUSE );
parms->stage = FIRE_SHORTFUSEWAIT;
}
else
{
parms->stage = FIRE_FIRE;
}
return SRESULT_WAIT;
case FIRE_SHORTFUSEWAIT:
if( !owner->IsFiring() || gameLocal.time >= fuse_end )
{
powerLevel = ( gameLocal.time - fuse_start ) / BFG_FUSE;
owner->Event_SetGuiFloat( "powerlevel", powerLevel );
parms->stage = FIRE_FIRE;
}
return SRESULT_WAIT;
case FIRE_FIRE:
if( gameLocal.time >= fuse_end )
{
OverCharge();
parms->stage = FIRE_DONE;
}
else
{
time_held = gameLocal.time - fuse_start;
if( power > BFG_MAXPOWER )
{
power = BFG_MAXPOWER;
}
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "fire", false );
fire_time = gameLocal.time;
owner->Event_LaunchProjectiles( BFG_NUMPROJECTILES, spread, 0, 1, 1 );
parms->stage = FIRE_FIRE_ANIMWAIT;
}
return SRESULT_WAIT;
case FIRE_FIRE_ANIMWAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, BFG_FIRE_TO_IDLE ) )
{
parms->stage = FIRE_FIRE_COOLDOWN;
}
else
{
intensity = 1 - ( ( gameLocal.time - fire_time ) / 0.5 );
if( intensity < 0 )
{
intensity = 0;
}
owner->Event_SetColor( intensity, intensity, intensity );
}
return SRESULT_WAIT;
case FIRE_FIRE_COOLDOWN:
if( powerLevel <= 0 )
{
parms->stage = FIRE_DONE;
}
else
{
powerLevel -= SEC2MS( 0.05 ); // TODO: DELTA TIME THIS!!
owner->Event_SetGuiFloat( "powerlevel", powerLevel );
}
return SRESULT_WAIT;
case FIRE_DONE:
owner->Event_SetGuiFloat( "powerlevel", 0 );
return SRESULT_DONE;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponBFG::OverCharge
===============
*/
void rvmWeaponBFG::OverCharge()
{
idStr entname;
idEntity* explosion;
idVec3 forward;
idAngles angles;
idPlayer* player;
player = owner->GetOwner();
owner->Event_AllowDrop( false );
owner->Event_UseAmmo( owner->ClipSize() );
angles = player->viewAngles;
forward = angles.ToForward();
entname = owner->GetKey( "def_overcharge" );
//explosion = sys.spawn(entname);
{
idDict spawnArgs;
spawnArgs.Set( "classname", entname );
gameLocal.SpawnEntityDef( spawnArgs, &explosion );
}
explosion->Event_SetOrigin( owner->GetOrigin() + forward * 16 );
explosion->Event_SetShaderParm( /*SHADERPARM_TIMEOFFSET*/4, -gameLocal.time );
gameLocal.DelayRemoveEntity( explosion, 2 );
owner->Event_StartSound( "snd_explode", SND_CHANNEL_ANY, false );
gameLocal.RadiusDamage( owner->GetOrigin(), owner, owner->GetOwner(), nullptr, nullptr, "damage_bfg_overcharge", 1.0 );
}
/*
===============
rvmWeaponBFG::Reload
===============
*/
stateResult_t rvmWeaponBFG::Reload( stateParms_t* parms )
{
enum RELOAD_State
{
RELOAD_NOTSET = 0,
RELOAD_WAIT
};
switch( parms->stage )
{
case RELOAD_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "reload", false );
parms->stage = RELOAD_WAIT;
return SRESULT_WAIT;
case RELOAD_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
owner->Event_AddToClip( owner->ClipSize() );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
+27
View File
@@ -0,0 +1,27 @@
// Weapon_bfg.h
//
#pragma once
class rvmWeaponBFG : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponBFG );
virtual void Init( idWeapon* weapon );
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
private:
void OverCharge();
float spread;
float fuse_start;
float fuse_end;
float powerLevel;
float fire_time;
};
+324
View File
@@ -0,0 +1,324 @@
// Weapon_chaingun.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponChainGun )
END_CLASS
#define CHAINGUN_FIRE_SKIPFRAMES 7 // 6 shots per second
#define CHAINGUN_LOWAMMO 10
#define CHAINGUN_NUMPROJECTILES 1
#define CHAINGUN_BARREL_SPEED ( 60 * ( USERCMD_HZ / CHAINGUN_FIRE_SKIPFRAMES ) )
#define CHAINGUN_BARREL_ACCEL_TIME 0.4
#define CHAINGUN_BARREL_DECCEL_TIME 1.0
#define CHAINGUN_BARREL_ACCEL ( CHAINGUN_BARREL_SPEED / CHAINGUN_BARREL_ACCEL_TIME )
#define CHAINGUN_BARREL_DECCEL ( CHAINGUN_BARREL_SPEED / CHAINGUN_BARREL_DECCEL_TIME )
// blend times
#define CHAINGUN_IDLE_TO_LOWER 4
#define CHAINGUN_IDLE_TO_FIRE 0
#define CHAINGUN_IDLE_TO_RELOAD 4
#define CHAINGUN_RAISE_TO_IDLE 0
#define CHAINGUN_WINDDOWN_TO_IDLE 0
#define CHAINGUN_RELOAD_TO_IDLE 0
/*
===============
rvmWeaponChainGun::Init
===============
*/
void rvmWeaponChainGun::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
world_model = ( idAnimatedEntity* )owner->GetWorldModel();
world_barrel_joint = owner->GetAnimator()->GetJointHandle( "toob" );
barrel_joint = owner->GetAnimator()->GetJointHandle( "spinner" );
barrel_angle = 0;
current_rate = 0;
start_rate = 0;
end_rate = 0;
spin_start = 0;
numSkipFrames = 0;
spin_end = 0;
spread = weapon->GetFloat( "spread" ); // weapon->GetFloat("spread")
snd_windup = FindSound( "snd_windup" );
snd_winddown = FindSound( "snd_winddown" );
}
/*
===============
rvmWeaponChainGun::UpdateBarrel
===============
*/
void rvmWeaponChainGun::UpdateBarrel()
{
float currentTime;
//float t;
idAngles ang;
currentTime = gameLocal.time;
//if (currentTime < spin_end) {
// t = (currentTime - spin_start) / (spin_end - spin_start);
// current_rate = start_rate + t * (end_rate - start_rate);
//}
//else {
current_rate = end_rate;
//}
if( current_rate )
{
barrel_angle = barrel_angle + current_rate * GAME_FRAMETIME;
ang.pitch = 0;
ang.yaw = 0;
ang.roll = barrel_angle;
owner->Event_SetJointAngle( barrel_joint, JOINTMOD_LOCAL, ang );
ang.yaw = barrel_angle;
ang.roll = 0;
world_model->Event_SetJointAngle( world_barrel_joint, JOINTMOD_LOCAL, ang );
}
}
/*
===============
rvmWeaponChainGun::SpinUp
===============
*/
void rvmWeaponChainGun::SpinUp()
{
start_rate = current_rate;
end_rate = CHAINGUN_BARREL_SPEED;
spin_start = gameLocal.time;
spin_end = spin_start + ( end_rate - current_rate ) / CHAINGUN_BARREL_ACCEL;
owner->Event_StartSound( "snd_windup", SND_CHANNEL_BODY3, false );
}
/*
===============
rvmWeaponChainGun::SpinDown
===============
*/
void rvmWeaponChainGun::SpinDown()
{
start_rate = current_rate;
end_rate = 0;
spin_start = gameLocal.time;
spin_end = spin_start + ( current_rate - end_rate ) / CHAINGUN_BARREL_DECCEL;
owner->Event_StartSound( "snd_winddown", SND_CHANNEL_BODY3, false );
}
/*
===============
rvmWeaponChainGun::Raise
===============
*/
stateResult_t rvmWeaponChainGun::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, CHAINGUN_RAISE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponChainGun::Lower
===============
*/
stateResult_t rvmWeaponChainGun::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponChainGun::Idle
===============
*/
stateResult_t rvmWeaponChainGun::Idle( stateParms_t* parms )
{
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT
};
switch( parms->stage )
{
case IDLE_NOTSET:
if( !owner->AmmoInClip() )
{
owner->Event_WeaponOutOfAmmo();
}
else
{
owner->Event_WeaponReady();
}
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle" );
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
// Do nothing.
return SRESULT_DONE;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponChainGun::Fire
===============
*/
stateResult_t rvmWeaponChainGun::Fire( stateParms_t* parms )
{
float ammoClip;
// float currentTime;
// float skip;
ammoClip = owner->AmmoInClip();
enum FireState
{
FIRE_NOTSET = 0,
FIRE_SPIN1,
FIRE_FIRE,
FIRE_SKIPFRAMES
};
switch( parms->stage )
{
case FIRE_NOTSET:
SpinUp();
UpdateBarrel();
if( current_rate >= end_rate )
{
if( ammoClip > 0 )
{
parms->stage = FIRE_SPIN1;
}
else
{
parms->stage = 0;
return SRESULT_DONE;
}
}
return SRESULT_WAIT;
case FIRE_SPIN1:
owner->Event_StartSound( "snd_spin", SND_CHANNEL_BODY3, false );
parms->stage = FIRE_FIRE;
return SRESULT_WAIT;
case FIRE_FIRE:
owner->Event_LaunchProjectiles( CHAINGUN_NUMPROJECTILES, spread, 0, 1, 1 );
owner->Event_StartSound( "snd_fire", SND_CHANNEL_BODY3, false );
if( ammoClip == CHAINGUN_LOWAMMO )
{
owner->Event_StartSound( "snd_lowammo", SND_CHANNEL_ITEM, false );
}
numSkipFrames = 0;
parms->stage = FIRE_SKIPFRAMES;
return SRESULT_WAIT;
case FIRE_SKIPFRAMES:
UpdateBarrel();
numSkipFrames++;
if( numSkipFrames >= CHAINGUN_FIRE_SKIPFRAMES )
{
if( owner->IsFiring() )
{
parms->stage = FIRE_FIRE;
numSkipFrames = 0;
}
else
{
SpinDown();
return SRESULT_DONE;
}
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponChainGun::Reload
===============
*/
stateResult_t rvmWeaponChainGun::Reload( stateParms_t* parms )
{
enum RELOAD_State
{
RELOAD_NOTSET = 0,
RELOAD_WAIT
};
switch( parms->stage )
{
case RELOAD_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "reload", false );
parms->stage = RELOAD_WAIT;
return SRESULT_WAIT;
case RELOAD_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
owner->Event_AddToClip( owner->ClipSize() );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
+37
View File
@@ -0,0 +1,37 @@
// Weapon_chaingun.h
//
#pragma once
class rvmWeaponChainGun : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponChainGun );
virtual void Init( idWeapon* weapon );
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
private:
void UpdateBarrel();
void SpinUp();
void SpinDown();
private:
idAnimatedEntity* world_model;
jointHandle_t world_barrel_joint;
jointHandle_t barrel_joint;
float barrel_angle;
float current_rate;
float start_rate;
float end_rate;
float spin_start;
float spin_end;
float spread;
int numSkipFrames;
const idSoundShader* snd_windup;
const idSoundShader* snd_winddown;
};
+225
View File
@@ -0,0 +1,225 @@
// Weapon_chainsaw.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponChainsaw )
END_CLASS
#define CHAINSAW_FIRERATE 0.1
// blend times
#define CHAINSAW_IDLE_TO_LOWER 4
#define CHAINSAW_IDLE_TO_FIRE 4
#define CHAINSAW_RAISE_TO_IDLE 4
#define CHAINSAW_FIRE_TO_IDLE 4
/*
===============
rvmWeaponChainsaw::Init
===============
*/
void rvmWeaponChainsaw::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
next_attack = 0;
}
/*
===============
rvmWeaponChainsaw::Raise
===============
*/
stateResult_t rvmWeaponChainsaw::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, CHAINSAW_RAISE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponChainsaw::Lower
===============
*/
stateResult_t rvmWeaponChainsaw::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponChainsaw::Idle
===============
*/
stateResult_t rvmWeaponChainsaw::Idle( stateParms_t* parms )
{
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT
};
switch( parms->stage )
{
case IDLE_NOTSET:
owner->Event_WeaponReady();
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle" );
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
// Do nothing.
return SRESULT_DONE;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponChainsaw::Reload
===============
*/
stateResult_t rvmWeaponChainsaw::Reload( stateParms_t* parms )
{
return SRESULT_DONE;
}
/*
===============
rvmWeaponChainsaw::Fire
===============
*/
stateResult_t rvmWeaponChainsaw::Fire( stateParms_t* parms )
{
float currentTime;
if( parms->stage == 0 )
{
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "melee_start", false );
owner->Event_Melee();
owner->Event_StartSound( "snd_startattack", SND_CHANNEL_WEAPON, false );
parms->stage = 1;
return SRESULT_WAIT;
}
if( parms->stage == 1 )
{
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 3 ) )
{
parms->stage = 2;
return SRESULT_WAIT;
}
return SRESULT_WAIT;
}
if( parms->stage == 2 )
{
owner->Event_StartSound( "snd_attack", SND_CHANNEL_WEAPON, false );
parms->stage = 3;
return SRESULT_WAIT;
}
if( parms->stage == 3 )
{
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
parms->stage = 4;
return SRESULT_WAIT;
}
return SRESULT_WAIT;
}
if( parms->stage == 4 )
{
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "melee_loop" );
next_attack = gameLocal.SysScriptTime();
parms->stage = 5;
return SRESULT_WAIT;
}
if( parms->stage == 5 )
{
if( owner->IsFiring() )
{
currentTime = gameLocal.SysScriptTime();
if( currentTime >= next_attack )
{
owner->Event_Melee();
next_attack = currentTime + CHAINSAW_FIRERATE;
}
return SRESULT_WAIT;
}
else
{
parms->stage = 6;
return SRESULT_WAIT;
}
}
if( parms->stage == 6 )
{
owner->Event_StartSound( "snd_stopattack", SND_CHANNEL_WEAPON, false );
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "melee_end", false );
parms->stage = 7;
return SRESULT_WAIT;
}
if( !owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
return SRESULT_WAIT;
}
return SRESULT_DONE;
}
+20
View File
@@ -0,0 +1,20 @@
// Weapon_chainsaw.h
//
#pragma once
class rvmWeaponChainsaw : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponChainsaw );
virtual void Init( idWeapon* weapon );
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
private:
bool side;
};
@@ -0,0 +1,252 @@
// Weapon_double_shotgun.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponDoubleShotgun )
END_CLASS
//#define SHOTGUN_DOUBLE_FIRERATE 1.333
#define SHOTGUN_DOUBLE_FIRERATE 2.2
#define SHOTGUN_DOUBLE_REQUIRED 2
// blend times
#define SHOTGUN_DOUBLE_IDLE_TO_IDLE 0
#define SHOTGUN_DOUBLE_IDLE_TO_LOWER 4
#define SHOTGUN_DOUBLE_IDLE_TO_FIRE 0
#define SHOTGUN_DOUBLE_IDLE_TO_RELOAD 4
#define SHOTGUN_DOUBLE_IDLE_TO_NOAMMO 4
#define SHOTGUN_DOUBLE_NOAMMO_TO_RELOAD 4
#define SHOTGUN_DOUBLE_NOAMMO_TO_IDLE 4
#define SHOTGUN_DOUBLE_RAISE_TO_IDLE 4
#define SHOTGUN_DOUBLE_FIRE_TO_IDLE 4
#define SHOTGUN_DOUBLE_RELOAD_TO_IDLE 4
#define SHOTGUN_DOUBLE_RELOAD_TO_FIRE 4
//Shotgun Projectile Information
#define SHOTGUN_CENTER_PROJECTILES 8
//#define SHOTGUN_CENTER_PROJECTILES 7
#define SHOTGUN_BIG_PROJECTILES 12
//#define SHOTGUN_BIG_PROJECTILES 13
#define SHOTGUN_CENTER_WIDTH 5
#define SHOTGUN_CENTER_HEIGHT 10
//#define SHOTGUN_CENTER_HEIGHT 12
#define SHOTGUN_BIG_WIDTH 22
//#define SHOTGUN_BIG_WIDTH 25
#define SHOTGUN_BIG_HEIGHT 15
/*
===============
rvmWeaponDoubleShotgun::Init
===============
*/
void rvmWeaponDoubleShotgun::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
next_attack = 0;
}
/*
===============
rvmWeaponDoubleShotgun::Raise
===============
*/
stateResult_t rvmWeaponDoubleShotgun::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, SHOTGUN_DOUBLE_RAISE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponDoubleShotgun::Lower
===============
*/
stateResult_t rvmWeaponDoubleShotgun::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponDoubleShotgun::Idle
===============
*/
stateResult_t rvmWeaponDoubleShotgun::Idle( stateParms_t* parms )
{
//float currentTime = 0;
float clip_size;
clip_size = owner->ClipSize();
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT
};
switch( parms->stage )
{
case IDLE_NOTSET:
owner->Event_WeaponReady();
if( !owner->AmmoInClip() )
{
owner->Event_WeaponOutOfAmmo();
}
else
{
owner->Event_WeaponReady();
}
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle" );
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
// Do nothing.
return SRESULT_DONE;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponDoubleShotgun::Fire
===============
*/
stateResult_t rvmWeaponDoubleShotgun::Fire( stateParms_t* parms )
{
int ammoClip = owner->AmmoInClip();
enum FIRE_State
{
FIRE_NOTSET = 0,
FIRE_WAIT
};
if( ammoClip == 0 && owner->AmmoAvailable() && parms->stage == 0 )
{
//owner->WeaponState( WP_RELOAD, PISTOL_IDLE_TO_RELOAD );
owner->Reload();
return SRESULT_DONE;
}
switch( parms->stage )
{
case FIRE_NOTSET:
//if (ammoClip == SHOTGUN_LOWAMMO) {
// int length;
// owner->StartSoundShader(snd_lowammo, SND_CHANNEL_ITEM, 0, false, &length);
//}
//owner->Event_LaunchProjectiles(SHOTGUN_NUMPROJECTILES, spread, 0, 1, 1);
owner->Event_LaunchProjectilesEllipse( SHOTGUN_CENTER_PROJECTILES, SHOTGUN_CENTER_WIDTH, SHOTGUN_CENTER_HEIGHT, 0, 1.0 );
owner->Event_LaunchProjectilesEllipse( SHOTGUN_BIG_PROJECTILES, SHOTGUN_BIG_WIDTH, SHOTGUN_BIG_HEIGHT, 0, 1.0 );
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "fire", false );
parms->stage = FIRE_WAIT;
return SRESULT_WAIT;
case FIRE_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, SHOTGUN_DOUBLE_FIRE_TO_IDLE ) )
{
owner->Event_WeaponReloading();
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponDoubleShotgun::Reload
===============
*/
stateResult_t rvmWeaponDoubleShotgun::Reload( stateParms_t* parms )
{
enum RELOAD_State
{
RELOAD_NOTSET = 0,
RELOAD_WAIT
};
switch( parms->stage )
{
case RELOAD_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "reload_start", false );
parms->stage = RELOAD_WAIT;
return SRESULT_WAIT;
case RELOAD_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
owner->Event_AddToClip( owner->ClipSize() );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponDoubleShotgun::EjectBrass
===============
*/
void rvmWeaponDoubleShotgun::EjectBrass( void )
{
}
@@ -0,0 +1,22 @@
// Weapon_double_shotgun.h
//
#pragma once
class rvmWeaponDoubleShotgun : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponDoubleShotgun );
virtual void Init( idWeapon* weapon );
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
void EjectBrass( void );
private:
};
+185
View File
@@ -0,0 +1,185 @@
// weapon_fist.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponFist )
END_CLASS
#define RIFLE_NUMPROJECTILES 1
// blend times
#define FISTS_IDLE_TO_LOWER 4
#define FISTS_IDLE_TO_PUNCH 0
#define FISTS_RAISE_TO_IDLE 4
#define FISTS_PUNCH_TO_IDLE 1
/*
================
rvmWeaponFist::Init
================
*/
void rvmWeaponFist::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
}
/*
================
rvmWeaponFist::Raise
================
*/
stateResult_t rvmWeaponFist::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, FISTS_RAISE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvmWeaponFist::Lower
================
*/
stateResult_t rvmWeaponFist::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvmWeaponFist::Idle
================
*/
stateResult_t rvmWeaponFist::Idle( stateParms_t* parms )
{
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT
};
switch( parms->stage )
{
case IDLE_NOTSET:
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle" );
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
// Do nothing.
return SRESULT_DONE;
}
return SRESULT_ERROR;
}
/*
================
rvmWeaponFist::Fire
================
*/
stateResult_t rvmWeaponFist::Fire( stateParms_t* parms )
{
enum FIRE_State
{
FIRE_NOTSET = 0,
FIRE_MELEE,
FIRE_WAIT
};
switch( parms->stage )
{
case FIRE_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, GetFireAnim(), false );
parms->stage = FIRE_MELEE;
parms->Wait( 0.1f );
return SRESULT_WAIT;
case FIRE_MELEE:
owner->Event_Melee();
parms->stage = FIRE_WAIT;
return SRESULT_WAIT;
case FIRE_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
side = !side;
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvmWeaponFist::Reload
================
*/
stateResult_t rvmWeaponFist::Reload( stateParms_t* parms )
{
return SRESULT_DONE;
}
/*
================
rvmWeaponFist::GetFireAnim
================
*/
const char* rvmWeaponFist::GetFireAnim()
{
if( side )
{
return "punch_left";
}
else
{
return "punch_right";
}
}
+21
View File
@@ -0,0 +1,21 @@
// Weapon_fist.h
//
#pragma once
class rvmWeaponFist : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponFist );
virtual void Init( idWeapon* weapon );
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
private:
const char* GetFireAnim();
bool side;
};
@@ -0,0 +1,254 @@
// Weapon_flashlight.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponFlashlight )
END_CLASS
// blend times
#define FLASHLIGHT_IDLE_TO_LOWER 4
#define FLASHLIGHT_IDLE_TO_FIRE 2
#define FLASHLIGHT_IDLE_TO_RELOAD 4
#define FLASHLIGHT_RAISE_TO_IDLE 4
#define FLASHLIGHT_FIRE_TO_IDLE 4
#define FLASHLIGHT_RELOAD_TO_IDLE 4
#define FLASHLIGHT_MIN_SKIN_INTENSITY 0.2
/*
================
rvmWeaponFlashlight::Init
================
*/
void rvmWeaponFlashlight::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
skin_on = owner->GetKey( "skin_on" );
skin_on_invis = owner->GetKey( "skin_on_invis" );
skin_off = owner->GetKey( "skin_off" );
skin_off_invis = owner->GetKey( "skin_off_invis" );
intensity = 1.0;
owner->Event_SetLightParm( 3, 1.0 );
owner->Event_SetShaderParm( 3, 1.0 );
on = true;
UpdateSkin();
}
/*
================
rvmWeaponFlashlight::UpdateLightIntensity
================
*/
void rvmWeaponFlashlight::UpdateLightIntensity( void )
{
// TODO this has to interact with scripts somehow
}
/*
================
rvmWeaponFlashlight::UpdateSkin
================
*/
void rvmWeaponFlashlight::UpdateSkin( void )
{
if( on && ( intensity > FLASHLIGHT_MIN_SKIN_INTENSITY ) )
{
if( !owner->Event_IsInvisible() )
{
owner->Event_SetSkin( skin_on );
}
else
{
owner->Event_SetSkin( skin_on_invis );
}
}
else
{
if( !owner->Event_IsInvisible() )
{
owner->Event_SetSkin( skin_off );
}
else
{
owner->Event_SetSkin( skin_off_invis );
}
}
}
/*
================
rvmWeaponFlashlight::Raise
================
*/
stateResult_t rvmWeaponFlashlight::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, FLASHLIGHT_RAISE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvmWeaponFlashlight::Lower
================
*/
stateResult_t rvmWeaponFlashlight::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvmWeaponFlashlight::Idle
================
*/
stateResult_t rvmWeaponFlashlight::Idle( stateParms_t* parms )
{
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT
};
switch( parms->stage )
{
case IDLE_NOTSET:
owner->Event_WeaponReady();
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle" );
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
// Do nothing.
return SRESULT_DONE;
}
return SRESULT_ERROR;
}
/*
================
rvmWeaponFlashlight::Fire
================
*/
stateResult_t rvmWeaponFlashlight::Fire( stateParms_t* parms )
{
enum FIRE_State
{
FIRE_NOTSET = 0,
FIRE_MELEE,
FIRE_WAIT
};
switch( parms->stage )
{
case FIRE_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "fire", false );
parms->stage = FIRE_MELEE;
parms->Wait( 0.1f );
return SRESULT_WAIT;
case FIRE_MELEE:
owner->Event_Melee();
parms->stage = FIRE_WAIT;
return SRESULT_WAIT;
case FIRE_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, FLASHLIGHT_FIRE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_DONE;
}
/*
================
rvmWeaponFlashlight::Reload
================
*/
stateResult_t rvmWeaponFlashlight::Reload( stateParms_t* parms )
{
enum RELOAD_State
{
RELOAD_NOTSET = 0,
RELOAD_TOGGLEFLASHLIGHT,
RELOAD_WAIT
};
switch( parms->stage )
{
case RELOAD_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "reload", false );
parms->stage = RELOAD_TOGGLEFLASHLIGHT;
parms->Wait( 0.2f );
return SRESULT_WAIT;
case RELOAD_TOGGLEFLASHLIGHT:
on = !on;
UpdateSkin();
owner->Event_Flashlight( on );
parms->stage = RELOAD_WAIT;
return SRESULT_WAIT;
case RELOAD_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, FLASHLIGHT_RELOAD_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
@@ -0,0 +1,28 @@
// Weapon_flashlight.h
//
#pragma once
class rvmWeaponFlashlight : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponFlashlight );
virtual void Init( idWeapon* weapon );
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
private:
void UpdateSkin( void );
void UpdateLightIntensity( void );
bool on;
float intensity;
idStr skin_on;
idStr skin_on_invis;
idStr skin_off;
idStr skin_off_invis;
};
+400
View File
@@ -0,0 +1,400 @@
// Weapon_grabber.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponGrabber )
END_CLASS
// blend times
#define GRABBER_IDLE_TO_LOWER 4
#define GRABBER_IDLE_TO_OPEN 4
#define GRABBER_IDLE_TO_OPENFIRE 4
#define GRABBER_OPEN_TO_CLOSE 4
#define GRABBER_OPEN_TO_FIRE 4
#define GRABBER_CLOSE_TO_OPEN 4
#define GRABBER_CLOSE_TO_IDLE 4
#define GRABBER_OPENFIRE_TO_FIRE 2
#define GRABBER_FIRE_TO_CLOSE 4
#define GRABBER_RAISE_TO_IDLE 4
#define WARNING_BEEP_1 1.5
#define WARNING_BEEP_2 2.25
#define WARNING_BEEP_3 2.50
#define WARNING_BEEP_4 2.75
/*
===============
rvmWeaponGrabber::Init
===============
*/
void rvmWeaponGrabber::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
next_attack = 0;
snd_fireloop = FindSound( "snd_fireloop" );
snd_electroloop = FindSound( "snd_electroloop" );
snd_mainfire = FindSound( "snd_mainfire" );
snd_cangrab = FindSound( "snd_cangrab" );
snd_warning = FindSound( "snd_warning" );
snd_stopfire = FindSound( "snd_stopfire" );
owner->Event_Grabber( true );
grabberState = -1;
}
/*
===============
rvmWeaponGrabber::Raise
===============
*/
stateResult_t rvmWeaponGrabber::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, GRABBER_RAISE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponGrabber::Lower
===============
*/
stateResult_t rvmWeaponGrabber::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponGrabber::CanFire
Original grabber logic had this, so we prevent the fire action from going unless grabState is 1 or 2.
grabState = grabberHasTarget();
if ( grabState == 1 || grabState == 2 ) {
if(WEAPON_ATTACK) {
weaponState( "GrabberOpenFire", GRABBER_IDLE_TO_OPENFIRE );
}
}
===============
*/
//bool rvmWeaponGrabber::CanFire()
//{
// int grabState = owner->Event_GrabberHasTarget();
// return grabState == 1 || grabState == 2;
//}
/*
===============
rvmWeaponGrabber::Idle
===============
*/
stateResult_t rvmWeaponGrabber::Idle( stateParms_t* parms )
{
int grabState = 0;
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT,
IDLE_GRABBER_OPEN,
IDLE_GRABBER_OPEN_WAIT,
};
UpdateGuiLight();
grabState = owner->Event_GrabberHasTarget();
if( grabState == 1 || grabState == 2 )
{
parms->stage = IDLE_GRABBER_OPEN;
}
switch( parms->stage )
{
case IDLE_NOTSET:
owner->Event_WeaponReady();
if( !owner->AmmoInClip() )
{
owner->Event_WeaponOutOfAmmo();
}
else
{
owner->Event_WeaponReady();
}
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle" );
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
// Do nothing.
return SRESULT_WAIT;
case IDLE_GRABBER_OPEN:
owner->StartSoundShader( snd_fireloop, SND_CHANNEL_BODY3, 0, false, NULL );
owner->StartSoundShader( snd_electroloop, SND_CHANNEL_BODY2, 0, false, NULL );
owner->StartSoundShader( snd_mainfire, SND_CHANNEL_BODY, 0, false, NULL );
StartWarningSound();
StartActive();
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "open", false );
parms->stage = IDLE_GRABBER_OPEN_WAIT;
return SRESULT_WAIT;
case IDLE_GRABBER_OPEN_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
//owner->WeaponState( WP_FIRE, GRABBER_OPEN_TO_CLOSE );
owner->BeginAttack();
return SRESULT_DONE;
}
else
{
grabState = owner->Event_GrabberHasTarget();
if( grabState == 3 )
{
//owner->WeaponState( WP_FIRE, GRABBER_OPEN_TO_CLOSE );
owner->BeginAttack();
return SRESULT_DONE;
}
}
UpdateGuiLight();
UpdateWarningSound();
return SRESULT_WAIT;;
}
return SRESULT_DONE;
}
/*
=====================
rvmWeaponGrabber::StartWarningSound
=====================
*/
void rvmWeaponGrabber::StartWarningSound()
{
fireStartTime = gameLocal.realClientTime;
warningBeep1 = false;
warningBeep2 = false;
warningBeep3 = false;
warningBeep4 = false;
}
/*
=====================
rvmWeaponGrabber::StartActive
=====================
*/
void rvmWeaponGrabber::StartActive()
{
owner->Event_StartWeaponParticle( "barrel_upper" );
owner->Event_StartWeaponLight( "light_barrel_upper" );
owner->Event_StartWeaponLight( "light_barrel_lower" );
owner->Event_StartWeaponLight( "light_side" );
}
/*
=====================
rvmWeaponGrabber::StopActive
=====================
*/
void rvmWeaponGrabber::StopActive()
{
owner->Event_StopWeaponParticle( "barrel_upper" );
owner->Event_StopWeaponLight( "light_barrel_upper" );
owner->Event_StopWeaponLight( "light_barrel_lower" );
owner->Event_StopWeaponLight( "light_side" );
}
/*
==================== =
rvmWeaponGrabber::UpdateGuiLight
==================== =
*/
void rvmWeaponGrabber::UpdateGuiLight()
{
float newState = owner->Event_GrabberHasTarget();
if( newState != grabberState )
{
grabberState = newState;
if( grabberState == 0 )
{
owner->Event_StartWeaponLight( "gLightBlue" );
owner->Event_StopWeaponLight( "gLightYellow" );
owner->Event_StopWeaponLight( "gLightRed" );
}
else if( grabberState == 1 )
{
//startSound("snd_cangrab", SND_CHANNEL_ITEM, false);
owner->StartSoundShader( snd_cangrab, SND_CHANNEL_ITEM, 0, false, NULL );
owner->Event_StartWeaponLight( "gLightYellow" );
owner->Event_StopWeaponLight( "gLightBlue" );
owner->Event_StopWeaponLight( "gLightRed" );
}
else if( grabberState == 2 )
{
owner->Event_StartWeaponLight( "gLightRed" );
owner->Event_StopWeaponLight( "gLightBlue" );
owner->Event_StopWeaponLight( "gLightYellow" );
}
}
}
/*
=====================
rvmWeaponGrabber::UpdateWarningSound
=====================
*/
void rvmWeaponGrabber::UpdateWarningSound()
{
float currentTime;
float elapsed;
currentTime = gameLocal.realClientTime;
elapsed = currentTime - fireStartTime;
if( elapsed > WARNING_BEEP_1 && !warningBeep1 )
{
owner->StartSoundShader( snd_warning, SND_CHANNEL_ITEM, 0, false, NULL );
warningBeep1 = true;
}
if( elapsed > WARNING_BEEP_2 && !warningBeep2 )
{
owner->StartSoundShader( snd_warning, SND_CHANNEL_ITEM, 0, false, NULL );
warningBeep2 = true;
}
if( elapsed > WARNING_BEEP_3 && !warningBeep3 )
{
owner->StartSoundShader( snd_warning, SND_CHANNEL_ITEM, 0, false, NULL );
warningBeep3 = true;
}
if( elapsed > WARNING_BEEP_4 && !warningBeep4 )
{
owner->StartSoundShader( snd_warning, SND_CHANNEL_ITEM, 0, false, NULL );
warningBeep4 = true;
}
}
/*
===============
rvmWeaponGrabber::Fire
===============
*/
stateResult_t rvmWeaponGrabber::Fire( stateParms_t* parms )
{
//int grabState;
//
//grabState = owner->Event_GrabberHasTarget();
//
//enum FIRE_State
//{
// FIRE_NOTSET = 0,
// FIRE_WAIT_GRABSTATE,
// FIRE_ACTUALLY_FIRE,
// FIRE_WAIT
//};
//
//switch( parms->stage )
//{
// case FIRE_NOTSET:
// next_attack = MS2SEC( gameLocal.realClientTime );
// owner->Event_PlayAnim( ANIMCHANNEL_ALL, "idleopen", true );
// parms->stage = FIRE_WAIT_GRABSTATE;
// return SRESULT_WAIT;
//
// case FIRE_WAIT_GRABSTATE:
// if( grabState == 3 || grabState == 0 )
// {
// parms->stage = FIRE_ACTUALLY_FIRE;
// }
// return SRESULT_WAIT;
//
// case FIRE_ACTUALLY_FIRE:
// StopActive();
//
// // Stops fire loop sound
// owner->StartSoundShader( snd_stopfire, SND_CHANNEL_BODY3, 0, false, NULL );
// owner->StopSound( SND_CHANNEL_BODY2, false );
//
// owner->Event_StartWeaponSmoke();
// owner->Event_PlayAnim( ANIMCHANNEL_ALL, "fire", true );
// break;
//
// case FIRE_WAIT:
// if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
// {
// owner->WeaponState( WP_IDLE, GRABBER_CLOSE_TO_IDLE );
// firingState = 0;
// }
// else
// {
// UpdateGuiLight();
// }
// break;
//}
return SRESULT_DONE;
}
/*
===============
rvmWeaponGrabber::Reload
===============
*/
stateResult_t rvmWeaponGrabber::Reload( stateParms_t* parms )
{
return SRESULT_DONE;
}
+43
View File
@@ -0,0 +1,43 @@
// Weapon_grabber.h
//
#pragma once
class rvmWeaponGrabber : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponGrabber );
virtual void Init( idWeapon* weapon );
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
private:
void StartActive();
void StopActive();
void StartWarningSound();
void UpdateWarningSound();
void UpdateGuiLight();
const idSoundShader* snd_fireloop;
const idSoundShader* snd_electroloop;
const idSoundShader* snd_mainfire;
const idSoundShader* snd_cangrab;
const idSoundShader* snd_warning;
const idSoundShader* snd_stopfire;
private:
float next_attack;
float fireStartTime;
bool warningBeep1;
bool warningBeep2;
bool warningBeep3;
bool warningBeep4;
float grabberState;
};
@@ -0,0 +1,384 @@
// Weapon_handgrenade.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponHandgrenade )
END_CLASS
#define HANDGRENADE_MINRELEASETIME 0.05
#define HANDGRENADE_FUSE 3
#define HANDGRENADE_QUICKTHROWTIME .2
#define HANDGRENADE_MINPOWER 1.5
#define HANDGRENADE_MAXPOWER 6
#define HANDGRENADE_QUICKTHROWLAUNCH 0.55
#define HANDGRENADE_NORMALTHROWLAUNCH 0.3
#define HANDGRENADE_NUMPROJECTILES 1
// blend times
#define HANDGRENADE_IDLE_TO_LOWER 4
#define HANDGRENADE_IDLE_TO_FIRE 4
#define HANDGRENADE_RAISE_TO_IDLE 4
#define HANDGRENADE_FIRE_TO_IDLE 4
/*
===============
rvmWeaponHandgrenade::Init
===============
*/
void rvmWeaponHandgrenade::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
projectile = NULL;
spread = owner->GetFloatKey( "spread" );
skin_nade = owner->GetKey( "skin_nade" );
skin_nade_invis = owner->GetKey( "skin_nade_invis" );
skin_nonade = owner->GetKey( "skin_nonade" );
skin_nonade_invis = owner->GetKey( "skin_nonade_invis" );
GrenadeNade();
}
/*
===============
rvmWeaponHandgrenade::GrenadeNade
===============
*/
void rvmWeaponHandgrenade::GrenadeNade( void )
{
show_grenade = true;
UpdateSkin();
}
/*
===============
rvmWeaponHandgrenade::GrenadeNoNade
===============
*/
void rvmWeaponHandgrenade::GrenadeNoNade( void )
{
show_grenade = false;
UpdateSkin();
}
/*
===============
rvmWeaponHandgrenade::GrenadeNoNade
===============
*/
void rvmWeaponHandgrenade::UpdateSkin()
{
if( !show_grenade )
{
if( owner->Event_IsInvisible() )
{
owner->Event_SetSkin( skin_nonade_invis );
}
else
{
owner->Event_SetSkin( skin_nonade );
}
}
else
{
if( owner->Event_IsInvisible() )
{
owner->Event_SetSkin( skin_nade_invis );
}
else
{
owner->Event_SetSkin( skin_nade );
}
}
}
/*
===============
rvmWeaponHandgrenade::Raise
===============
*/
stateResult_t rvmWeaponHandgrenade::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, HANDGRENADE_RAISE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponHandgrenade::Lower
===============
*/
stateResult_t rvmWeaponHandgrenade::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponHandgrenade::Idle
===============
*/
stateResult_t rvmWeaponHandgrenade::Idle( stateParms_t* parms )
{
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT
};
switch( parms->stage )
{
case IDLE_NOTSET:
owner->Event_WeaponReady();
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle" );
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
// Do nothing.
return SRESULT_DONE;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponHandgrenade::OwnerDied
===============
*/
void rvmWeaponHandgrenade::OwnerDied( void )
{
float time_held;
if( projectile )
{
time_held = gameLocal.SysScriptTime() - fuse_start;
projectile->Show();
projectile->Unbind();
// allow grenade to drop
owner->Event_LaunchProjectiles( HANDGRENADE_NUMPROJECTILES, spread, time_held, 0, 1.0 );
projectile = NULL;
}
}
/*
===============
rvmWeaponHandgrenade::Fire
===============
*/
stateResult_t rvmWeaponHandgrenade::Fire( stateParms_t* parms )
{
if( parms->stage == 0 )
{
projectile = ( idProjectile* )owner->CreateProjectile();
if( projectile )
{
projectile->Event_StartSound( "snd_throw", SND_CHANNEL_BODY, true );
}
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "throw_start", false );
current_time = gameLocal.SysScriptTime();
fuse_start = current_time;
fuse_end = current_time + HANDGRENADE_FUSE;
parms->stage = 1;
return SRESULT_WAIT;
}
if( parms->stage == 1 )
{
if( current_time < fuse_end )
{
if( ( current_time > fuse_start + HANDGRENADE_MINRELEASETIME ) )
{
parms->stage = 2;
return SRESULT_WAIT;
}
current_time = gameLocal.SysScriptTime();
return SRESULT_WAIT;
}
parms->stage = 2;
return SRESULT_WAIT;
}
if( parms->stage == 2 )
{
time_held = current_time - fuse_start;
power = time_held + HANDGRENADE_MINPOWER;
if( power > HANDGRENADE_MAXPOWER )
{
power = HANDGRENADE_MAXPOWER;
}
if( time_held < HANDGRENADE_QUICKTHROWTIME )
{
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "throw_quick", false );
parms->Wait( HANDGRENADE_QUICKTHROWLAUNCH );
exploded = false;
}
else if( time_held < HANDGRENADE_FUSE )
{
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "throw", false );
parms->Wait( HANDGRENADE_NORMALTHROWLAUNCH );
exploded = false;
}
else
{
// no anim. grenade just blows up
ExplodeInHand();
exploded = true;
}
parms->stage = 3;
return SRESULT_WAIT;
}
if( parms->stage == 3 )
{
if( !exploded )
{
GrenadeNoNade();
current_time = gameLocal.SysScriptTime();
if( projectile )
{
projectile->Show();
projectile->Unbind();
owner->Event_LaunchProjectiles( HANDGRENADE_NUMPROJECTILES, spread, current_time - fuse_start, power, 1.0 );
projectile = NULL;
}
parms->stage = 4;
return SRESULT_WAIT;
}
parms->stage = 5;
return SRESULT_WAIT;
}
if( parms->stage == 4 )
{
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, HANDGRENADE_FIRE_TO_IDLE ) )
{
parms->stage = 5;
return SRESULT_WAIT;
}
return SRESULT_WAIT;
}
if( !owner->AmmoAvailable() )
{
stateThread.Clear();
stateThread.SetState( "Holstered" );
owner->GetOwner()->NextWeapon();
}
else
{
GrenadeNade();
}
return SRESULT_DONE;
}
/*
===============
rvmWeaponHandgrenade::Reload
===============
*/
stateResult_t rvmWeaponHandgrenade::Reload( stateParms_t* parms )
{
return SRESULT_DONE;
}
/*
===============
rvmWeaponHandgrenade::ExplodeInHand
===============
*/
void rvmWeaponHandgrenade::ExplodeInHand()
{
idStr entname;
idEntity* explosion;
idVec3 forward;
idAngles angles;
idPlayer* owner;
if( projectile )
{
projectile->Event_Remove();
projectile = NULL;
}
owner = this->owner->GetOwner();
GrenadeNoNade();
this->owner->Event_StartSound( "snd_explode", SND_CHANNEL_ANY, false );
//if( !common->IsClient() )
{
this->owner->Event_UseAmmo( HANDGRENADE_NUMPROJECTILES );
angles = owner->viewAngles;
forward = angles.ToForward();
entname = this->owner->GetKey( "def_explode_inhand" );
explosion = gameLocal.Spawn( entname );
explosion->SetOrigin( this->owner->GetOrigin() + forward * 16 );
explosion->SetShaderParm( SHADERPARM_TIMEOFFSET, -gameLocal.SysScriptTime() );
gameLocal.DelayRemoveEntity( explosion, 2 );
// this should kill us
gameLocal.RadiusDamage( this->owner->GetOrigin(), this->owner, owner, NULL, NULL, this->owner->GetKey( "def_damage_inhand" ), 1.0f );
}
}
@@ -0,0 +1,44 @@
// Weapon_handgrenade.h
//
#pragma once
class rvmWeaponHandgrenade : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponHandgrenade );
virtual void Init( idWeapon* weapon );
virtual void OwnerDied( void ) override;
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
private:
void GrenadeNade( void );
void GrenadeNoNade( void );
void UpdateSkin();
void ExplodeInHand();
private:
float spread;
float fuse_start;
idStr skin_nade;
idStr skin_nade_invis;
idStr skin_nonade;
idStr skin_nonade_invis;
idProjectile* projectile;
boolean show_grenade;
private:
float fuse_end;
float current_time;
float time_held;
float power;
boolean exploded;
const idSoundShader* snd_lowammo;
};
@@ -0,0 +1,205 @@
// Weapon_machinegun.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponMachineGun )
END_CLASS
#define MACHINEGUN_FIRERATE 0.1 // ~10 per second
#define MACHINEGUN_LOWAMMO 10
#define MACHINEGUN_NUMPROJECTILES 1
// blend times
#define MACHINEGUN_IDLE_TO_LOWER 4
#define MACHINEGUN_IDLE_TO_FIRE 0
#define MACHINEGUN_IDLE_TO_RELOAD 4
#define MACHINEGUN_RAISE_TO_IDLE 4
#define MACHINEGUN_FIRE_TO_IDLE 0
#define MACHINEGUN_RELOAD_TO_IDLE 4
/*
===============
rvmWeaponMachineGun::Init
===============
*/
void rvmWeaponMachineGun::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
next_attack = 0;
spread = weapon->GetFloat( "spread" );
snd_lowammo = FindSound( "snd_lowammo" );
}
/*
===============
rvmWeaponMachineGun::Raise
===============
*/
stateResult_t rvmWeaponMachineGun::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, MACHINEGUN_RAISE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponMachineGun::Lower
===============
*/
stateResult_t rvmWeaponMachineGun::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponMachineGun::Idle
===============
*/
stateResult_t rvmWeaponMachineGun::Idle( stateParms_t* parms )
{
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT
};
switch( parms->stage )
{
case IDLE_NOTSET:
owner->Event_WeaponReady();
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle" );
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
// Do nothing.
return SRESULT_DONE;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponMachineGun::Fire
===============
*/
stateResult_t rvmWeaponMachineGun::Fire( stateParms_t* parms )
{
int ammoClip = owner->AmmoInClip();
enum FIRE_State
{
FIRE_NOTSET = 0,
FIRE_WAIT
};
if( ammoClip == 0 && owner->AmmoAvailable() && parms->stage == 0 )
{
//owner->WeaponState( WP_RELOAD, PISTOL_IDLE_TO_RELOAD );
owner->Reload();
return SRESULT_DONE;
}
switch( parms->stage )
{
case FIRE_NOTSET:
next_attack = gameLocal.realClientTime + MS2SEC( MACHINEGUN_FIRERATE );
owner->Event_LaunchProjectiles( MACHINEGUN_NUMPROJECTILES, spread, 0, 1, 1 );
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "fire", false );
parms->stage = FIRE_WAIT;
return SRESULT_WAIT;
case FIRE_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, MACHINEGUN_FIRE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponMachineGun::Reload
===============
*/
stateResult_t rvmWeaponMachineGun::Reload( stateParms_t* parms )
{
enum RELOAD_State
{
RELOAD_NOTSET = 0,
RELOAD_WAIT
};
switch( parms->stage )
{
case RELOAD_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "reload", false );
parms->stage = RELOAD_WAIT;
return SRESULT_WAIT;
case RELOAD_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
owner->Event_AddToClip( owner->ClipSize() );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
@@ -0,0 +1,22 @@
// Weapon_machinegun.h
//
#pragma once
class rvmWeaponMachineGun : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponMachineGun );
virtual void Init( idWeapon* weapon );
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
private:
float spread;
const idSoundShader* snd_lowammo;
};
+133
View File
@@ -0,0 +1,133 @@
// Weapon_pda.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponPDA )
END_CLASS
/*
================
rvmWeaponPDA::Init
================
*/
void rvmWeaponPDA::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
}
/*
================
rvmWeaponPDA::Raise
================
*/
stateResult_t rvmWeaponPDA::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvmWeaponPDA::Lower
================
*/
stateResult_t rvmWeaponPDA::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
================
rvmWeaponPDA::Idle
================
*/
stateResult_t rvmWeaponPDA::Idle( stateParms_t* parms )
{
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT
};
switch( parms->stage )
{
case IDLE_NOTSET:
owner->GetOwner()->Event_OpenPDA();
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
if( !owner->GetOwner()->objectiveSystemOpen )
{
//owner->WeaponState( WP_LOWERING, 0 );
owner->LowerWeapon();
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
}
/*
================
rvmWeaponPDA::Fire
================
*/
stateResult_t rvmWeaponPDA::Fire( stateParms_t* parms )
{
return SRESULT_DONE;
}
/*
================
rvmWeaponPDA::Reload
================
*/
stateResult_t rvmWeaponPDA::Reload( stateParms_t* parms )
{
return SRESULT_DONE;
}
+18
View File
@@ -0,0 +1,18 @@
// Weapon_pda.h
//
#pragma once
class rvmWeaponPDA : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponPDA );
virtual void Init( idWeapon* weapon );
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
};
+217
View File
@@ -0,0 +1,217 @@
// Weapon_pistol.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponPistol )
END_CLASS
#define PISTOL_FIRERATE 0.4
#define PISTOL_LOWAMMO 4
#define PISTOL_NUMPROJECTILES 1
// blend times
#define PISTOL_IDLE_TO_LOWER 2
#define PISTOL_IDLE_TO_FIRE 1
#define PISTOL_IDLE_TO_RELOAD 3
#define PISTOL_RAISE_TO_IDLE 3
#define PISTOL_FIRE_TO_IDLE 4
#define PISTOL_RELOAD_TO_IDLE 40
/*
===============
rvmWeaponPistol::Init
===============
*/
void rvmWeaponPistol::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
next_attack = 0;
spread = weapon->GetFloat( "spread" );
snd_lowammo = FindSound( "snd_lowammo" );
}
/*
===============
rvmWeaponPistol::Raise
===============
*/
stateResult_t rvmWeaponPistol::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, PISTOL_RAISE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponPistol::Lower
===============
*/
stateResult_t rvmWeaponPistol::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponPistol::Idle
===============
*/
stateResult_t rvmWeaponPistol::Idle( stateParms_t* parms )
{
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT
};
switch( parms->stage )
{
case IDLE_NOTSET:
owner->Event_WeaponReady();
if( !owner->AmmoInClip() )
{
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle_empty" );
}
else
{
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle" );
}
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
// Do nothing.
return SRESULT_DONE;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponPistol::Fire
===============
*/
stateResult_t rvmWeaponPistol::Fire( stateParms_t* parms )
{
int ammoClip = owner->AmmoInClip();
enum FIRE_State
{
FIRE_NOTSET = 0,
FIRE_WAIT
};
if( ammoClip == 0 && owner->AmmoAvailable() && parms->stage == 0 )
{
//owner->WeaponState( WP_RELOAD, PISTOL_IDLE_TO_RELOAD );
owner->Reload();
return SRESULT_DONE;
}
switch( parms->stage )
{
case FIRE_NOTSET:
next_attack = gameLocal.realClientTime + SEC2MS( PISTOL_FIRERATE );
if( ammoClip == PISTOL_LOWAMMO )
{
int length;
owner->StartSoundShader( snd_lowammo, SND_CHANNEL_ITEM, 0, false, &length );
}
owner->Event_LaunchProjectiles( PISTOL_NUMPROJECTILES, spread, 0, 1, 1 );
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "fire", false );
parms->stage = FIRE_WAIT;
return SRESULT_WAIT;
case FIRE_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, PISTOL_FIRE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponPistol::Reload
===============
*/
stateResult_t rvmWeaponPistol::Reload( stateParms_t* parms )
{
enum RELOAD_State
{
RELOAD_NOTSET = 0,
RELOAD_WAIT
};
switch( parms->stage )
{
case RELOAD_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "reload", false );
parms->stage = RELOAD_WAIT;
return SRESULT_WAIT;
case RELOAD_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
owner->Event_AddToClip( owner->ClipSize() );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
+22
View File
@@ -0,0 +1,22 @@
// Weapon_pistol.h
//
#pragma once
class rvmWeaponPistol : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponPistol );
virtual void Init( idWeapon* weapon );
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
private:
float spread;
const idSoundShader* snd_lowammo;
};
+205
View File
@@ -0,0 +1,205 @@
// Weapon_plasmagun.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponPlasmaGun )
END_CLASS
#define PLASMAGUN_FIRERATE 0.125 //changed by Tim
#define PLASMAGUN_LOWAMMO 10
#define PLASMAGUN_NUMPROJECTILES 1
// blend times
#define PLASMAGUN_IDLE_TO_LOWER 4
#define PLASMAGUN_IDLE_TO_FIRE 1
#define PLASMAGUN_IDLE_TO_RELOAD 4
#define PLASMAGUN_RAISE_TO_IDLE 4
#define PLASMAGUN_FIRE_TO_IDLE 4
#define PLASMAGUN_RELOAD_TO_IDLE 4
/*
===============
rvmWeaponPlasmaGun::Init
===============
*/
void rvmWeaponPlasmaGun::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
next_attack = 0;
spread = weapon->GetFloat( "spread" );
snd_lowammo = FindSound( "snd_lowammo" );
}
/*
===============
rvmWeaponPlasmaGun::Raise
===============
*/
stateResult_t rvmWeaponPlasmaGun::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, PLASMAGUN_RAISE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponPlasmaGun::Lower
===============
*/
stateResult_t rvmWeaponPlasmaGun::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponPlasmaGun::Idle
===============
*/
stateResult_t rvmWeaponPlasmaGun::Idle( stateParms_t* parms )
{
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT
};
switch( parms->stage )
{
case IDLE_NOTSET:
owner->Event_WeaponReady();
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle" );
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
// Do nothing.
return SRESULT_DONE;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponPlasmaGun::Fire
===============
*/
stateResult_t rvmWeaponPlasmaGun::Fire( stateParms_t* parms )
{
int ammoClip = owner->AmmoInClip();
enum FIRE_State
{
FIRE_NOTSET = 0,
FIRE_WAIT
};
if( ammoClip == 0 && owner->AmmoAvailable() && parms->stage == 0 )
{
//owner->WeaponState( WP_RELOAD, PISTOL_IDLE_TO_RELOAD );
owner->Reload();
return SRESULT_DONE;
}
switch( parms->stage )
{
case FIRE_NOTSET:
next_attack = gameLocal.time + SEC2MS( PLASMAGUN_FIRERATE );
owner->Event_LaunchProjectiles( PLASMAGUN_NUMPROJECTILES, spread, 0, 1, 1 );
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "fire", false );
parms->stage = FIRE_WAIT;
return SRESULT_WAIT;
case FIRE_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, PLASMAGUN_FIRE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponPlasmaGun::Reload
===============
*/
stateResult_t rvmWeaponPlasmaGun::Reload( stateParms_t* parms )
{
enum RELOAD_State
{
RELOAD_NOTSET = 0,
RELOAD_WAIT
};
switch( parms->stage )
{
case RELOAD_NOTSET:
owner->Event_WeaponReloading();
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "reload", false );
parms->stage = RELOAD_WAIT;
return SRESULT_WAIT;
case RELOAD_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, PLASMAGUN_RELOAD_TO_IDLE ) )
{
owner->Event_AddToClip( owner->ClipSize() );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
+22
View File
@@ -0,0 +1,22 @@
// Weapon_plasmagun.h
//
#pragma once
class rvmWeaponPlasmaGun : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponPlasmaGun );
virtual void Init( idWeapon* weapon );
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
private:
float spread;
const idSoundShader* snd_lowammo;
};
@@ -0,0 +1,235 @@
// Weapon_rocketlauncher.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponRocketLauncher )
END_CLASS
#define ROCKETLAUNCHER_LOWAMMO 1
#define ROCKETLAUNCHER_NUMPROJECTILES 1
#define ROCKETLAUNCHER_FIREDELAY 1 // was .75 changed again by Tim to 1
// blend times
#define ROCKETLAUNCHER_IDLE_TO_LOWER 4
#define ROCKETLAUNCHER_IDLE_TO_FIRE 0
#define ROCKETLAUNCHER_IDLE_TO_RELOAD 4
#define ROCKETLAUNCHER_RAISE_TO_IDLE 4
#define ROCKETLAUNCHER_FIRE_TO_IDLE 0
#define ROCKETLAUNCHER_RELOAD_TO_IDLE 4
#define ROCKETLAUNCHER_RELOAD_FRAME 34 // how many frames from the end of "reload" to fill the clip
/*
===============
rvmWeaponRocketLauncher::Init
===============
*/
void rvmWeaponRocketLauncher::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
next_attack = 0;
spread = weapon->GetFloat( "spread" );
skin_invisible = weapon->GetKey( "skin_invisible" );
}
/*
===============
rvmWeaponRocketLauncher::UpdateSkin
===============
*/
void rvmWeaponRocketLauncher::UpdateSkin()
{
idStr skinname;
int ammoClip;
if( owner->Event_IsInvisible() )
{
skinname = skin_invisible;
}
else
{
ammoClip = owner->AmmoInClip();
if( ammoClip > 5 )
{
// can happen in MP - weapon Raising with slightly out-of-sync ammoClip
ammoClip = 5;
}
if( ammoClip < 0 )
{
ammoClip = 0;
}
skinname = va( "skins/models/weapons/%drox.skin", ammoClip );
}
owner->Event_SetSkin( skinname );
}
/*
===============
rvmWeaponRocketLauncher::Raise
===============
*/
stateResult_t rvmWeaponRocketLauncher::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, ROCKETLAUNCHER_RAISE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponRocketLauncher::Lower
===============
*/
stateResult_t rvmWeaponRocketLauncher::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponRocketLauncher::Idle
===============
*/
stateResult_t rvmWeaponRocketLauncher::Idle( stateParms_t* parms )
{
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT
};
switch( parms->stage )
{
case IDLE_NOTSET:
owner->Event_WeaponReady();
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle" );
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
// Do nothing.
return SRESULT_DONE;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponRocketLauncher::Fire
===============
*/
stateResult_t rvmWeaponRocketLauncher::Fire( stateParms_t* parms )
{
int ammoClip = owner->AmmoInClip();
enum FIRE_State
{
FIRE_NOTSET = 0,
FIRE_WAIT
};
if( ammoClip == 0 && owner->AmmoAvailable() && parms->stage == 0 )
{
//owner->WeaponState( WP_RELOAD, PISTOL_IDLE_TO_RELOAD );
owner->Reload();
return SRESULT_DONE;
}
switch( parms->stage )
{
case FIRE_NOTSET:
next_attack = gameLocal.realClientTime + SEC2MS( ROCKETLAUNCHER_FIREDELAY );
owner->Event_LaunchProjectiles( ROCKETLAUNCHER_NUMPROJECTILES, spread, 0, 1, 1 );
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "fire", false );
parms->stage = FIRE_WAIT;
return SRESULT_WAIT;
case FIRE_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, ROCKETLAUNCHER_FIRE_TO_IDLE ) )
{
UpdateSkin();
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponRocketLauncher::Reload
===============
*/
stateResult_t rvmWeaponRocketLauncher::Reload( stateParms_t* parms )
{
enum RELOAD_State
{
RELOAD_NOTSET = 0,
RELOAD_WAIT
};
switch( parms->stage )
{
case RELOAD_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "reload", false );
parms->stage = RELOAD_WAIT;
return SRESULT_WAIT;
case RELOAD_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
owner->Event_AddToClip( owner->ClipSize() );
UpdateSkin();
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
@@ -0,0 +1,23 @@
// Weapon_rocketlauncher.h
//
#pragma once
class rvmWeaponRocketLauncher : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponRocketLauncher );
virtual void Init( idWeapon* weapon );
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
private:
void UpdateSkin();
float spread;
idStr skin_invisible;
};
+245
View File
@@ -0,0 +1,245 @@
// Weapon_shotgun.cpp
//
#pragma hdrstop
#include "precompiled.h"
#include "../Game_local.h"
CLASS_DECLARATION( rvmWeaponObject, rvmWeaponShotgun )
END_CLASS
#define SHOTGUN_FIRERATE 1.333
#define SHOTGUN_LOWAMMO 2
#define SHOTGUN_RELOADRATE 2
#define SHOTGUN_NUMPROJECTILES 13
// blend times
#define SHOTGUN_IDLE_TO_IDLE 0
#define SHOTGUN_IDLE_TO_LOWER 4
#define SHOTGUN_IDLE_TO_FIRE 1
#define SHOTGUN_IDLE_TO_RELOAD 4
#define SHOTGUN_IDLE_TO_NOAMMO 4
#define SHOTGUN_NOAMMO_TO_RELOAD 4
#define SHOTGUN_NOAMMO_TO_IDLE 4
#define SHOTGUN_RAISE_TO_IDLE 1
#define SHOTGUN_FIRE_TO_IDLE 4
#define SHOTGUN_RELOAD_TO_IDLE 4
#define SHOTGUN_RELOAD_TO_FIRE 4
#define SHOTGUN_RELOAD_TO_LOWER 2
/*
===============
rvmWeaponShotgun::Init
===============
*/
void rvmWeaponShotgun::Init( idWeapon* weapon )
{
rvmWeaponObject::Init( weapon );
next_attack = 0;
spread = weapon->GetFloat( "spread" ); // weapon->GetFloat("spread")
snd_lowammo = FindSound( "snd_lowammo" );
}
/*
===============
rvmWeaponShotgun::Raise
===============
*/
stateResult_t rvmWeaponShotgun::Raise( stateParms_t* parms )
{
enum RisingState
{
RISING_NOTSET = 0,
RISING_WAIT
};
switch( parms->stage )
{
case RISING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "raise", false );
parms->stage = RISING_WAIT;
return SRESULT_WAIT;
case RISING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, SHOTGUN_RAISE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponShotgun::Lower
===============
*/
stateResult_t rvmWeaponShotgun::Lower( stateParms_t* parms )
{
enum LoweringState
{
LOWERING_NOTSET = 0,
LOWERING_WAIT
};
switch( parms->stage )
{
case LOWERING_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "putaway", false );
parms->stage = LOWERING_WAIT;
return SRESULT_WAIT;
case LOWERING_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
SetState( "Holstered" );
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponShotgun::Idle
===============
*/
stateResult_t rvmWeaponShotgun::Idle( stateParms_t* parms )
{
enum IdleState
{
IDLE_NOTSET = 0,
IDLE_WAIT
};
switch( parms->stage )
{
case IDLE_NOTSET:
owner->Event_WeaponReady();
owner->Event_PlayCycle( ANIMCHANNEL_ALL, "idle" );
parms->stage = IDLE_WAIT;
return SRESULT_WAIT;
case IDLE_WAIT:
// Do nothing.
return SRESULT_DONE;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponShotgun::Fire
===============
*/
stateResult_t rvmWeaponShotgun::Fire( stateParms_t* parms )
{
int ammoClip = owner->AmmoInClip();
enum FIRE_State
{
FIRE_NOTSET = 0,
FIRE_WAIT
};
if( ammoClip == 0 && owner->AmmoAvailable() && parms->stage == 0 )
{
//owner->WeaponState( WP_RELOAD, PISTOL_IDLE_TO_RELOAD );
owner->Reload();
return SRESULT_DONE;
}
switch( parms->stage )
{
case FIRE_NOTSET:
next_attack = gameLocal.realClientTime + SEC2MS( SHOTGUN_FIRERATE );
if( ammoClip == SHOTGUN_LOWAMMO )
{
int length;
owner->StartSoundShader( snd_lowammo, SND_CHANNEL_ITEM, 0, false, &length );
}
owner->Event_LaunchProjectiles( SHOTGUN_NUMPROJECTILES, spread, 0, 1, 1 );
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "fire", false );
parms->stage = FIRE_WAIT;
return SRESULT_WAIT;
case FIRE_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, SHOTGUN_FIRE_TO_IDLE ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
/*
===============
rvmWeaponShotgun::Reload
===============
*/
stateResult_t rvmWeaponShotgun::Reload( stateParms_t* parms )
{
float ammoClip;
float ammoAvail;
float clip_size;
clip_size = owner->ClipSize();
enum RELOAD_State
{
RELOAD_NOTSET = 0,
RELOAD_WAIT,
RELOAD_END
};
ammoAvail = owner->AmmoAvailable();
ammoClip = owner->AmmoInClip();
switch( parms->stage )
{
case RELOAD_NOTSET:
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "reload_loop", false );
parms->stage = RELOAD_WAIT;
return SRESULT_WAIT;
case RELOAD_WAIT:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
if( ( ammoClip < clip_size ) && ( ammoClip < ammoAvail ) )
{
parms->stage = RELOAD_NOTSET;
owner->Event_AddToClip( SHOTGUN_RELOADRATE );
return SRESULT_WAIT;
}
else
{
parms->stage = RELOAD_END;
owner->Event_PlayAnim( ANIMCHANNEL_ALL, "reload_end", false );
return SRESULT_WAIT;
}
owner->Event_AddToClip( owner->ClipSize() );
return SRESULT_DONE;
}
return SRESULT_WAIT;
case RELOAD_END:
if( owner->Event_AnimDone( ANIMCHANNEL_ALL, 0 ) )
{
return SRESULT_DONE;
}
return SRESULT_WAIT;
}
return SRESULT_ERROR;
}
+22
View File
@@ -0,0 +1,22 @@
// Weapon_shotgun.h
//
#pragma once
class rvmWeaponShotgun : public rvmWeaponObject
{
public:
CLASS_PROTOTYPE( rvmWeaponShotgun );
virtual void Init( idWeapon* weapon );
stateResult_t Raise( stateParms_t* parms );
stateResult_t Lower( stateParms_t* parms );
stateResult_t Idle( stateParms_t* parms );
stateResult_t Fire( stateParms_t* parms );
stateResult_t Reload( stateParms_t* parms );
private:
float spread;
const idSoundShader* snd_lowammo;
};