2006-02-24 04:48:15 +00:00
/*
* * info . cpp
* * Keeps track of available actors and their states
* *
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2006-06-11 01:37:00 +00:00
* * Copyright 1998 - 2006 Randy Heit
2006-02-24 04:48:15 +00:00
* * All rights reserved .
* *
* * Redistribution and use in source and binary forms , with or without
* * modification , are permitted provided that the following conditions
* * are met :
* *
* * 1. Redistributions of source code must retain the above copyright
* * notice , this list of conditions and the following disclaimer .
* * 2. Redistributions in binary form must reproduce the above copyright
* * notice , this list of conditions and the following disclaimer in the
* * documentation and / or other materials provided with the distribution .
* * 3. The name of the author may not be used to endorse or promote products
* * derived from this software without specific prior written permission .
* *
* * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ` ` AS IS ' ' AND ANY EXPRESS OR
* * IMPLIED WARRANTIES , INCLUDING , BUT NOT LIMITED TO , THE IMPLIED WARRANTIES
* * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED .
* * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT , INDIRECT ,
* * INCIDENTAL , SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT
* * NOT LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
* * DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
* * THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
* * ( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE OF
* * THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
* * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
* *
* * This is completely different from Doom ' s info . c .
* *
*/
2016-02-15 01:14:34 +00:00
# include "doomstat.h"
2006-02-24 04:48:15 +00:00
# include "info.h"
# include "m_fixed.h"
# include "c_dispatch.h"
2008-09-14 23:54:38 +00:00
# include "d_net.h"
2010-02-13 08:56:08 +00:00
# include "v_text.h"
2006-02-24 04:48:15 +00:00
# include "gi.h"
2009-09-17 01:36:14 +00:00
# include "vm.h"
2006-02-24 04:48:15 +00:00
# include "actor.h"
# include "r_state.h"
# include "i_system.h"
# include "p_local.h"
2006-10-31 14:53:21 +00:00
# include "templates.h"
2007-04-22 09:06:29 +00:00
# include "cmdlib.h"
2009-06-26 17:17:52 +00:00
# include "g_level.h"
2012-10-21 03:46:17 +00:00
# include "stats.h"
2016-02-19 02:39:40 +00:00
# include "thingdef/thingdef.h"
2016-02-15 01:14:34 +00:00
# include "d_player.h"
2006-02-24 04:48:15 +00:00
2008-10-25 17:38:00 +00:00
extern void LoadActors ( ) ;
2010-12-12 21:09:16 +00:00
extern void InitBotStuff ( ) ;
2010-12-14 00:50:02 +00:00
extern void ClearStrifeTypes ( ) ;
2006-02-24 04:48:15 +00:00
2010-04-16 02:57:51 +00:00
TArray < PClassActor * > PClassActor : : AllActorClasses ;
2012-11-10 03:36:30 +00:00
FRandom FState : : pr_statetics ( " StateTics " ) ;
2010-04-16 02:57:51 +00:00
2012-10-21 03:46:17 +00:00
cycle_t ActionCycles ;
2016-02-10 13:38:08 +00:00
void FState : : SetAction ( const char * name )
{
ActionFunc = FindGlobalActionFunction ( name ) - > Variants [ 0 ] . Implementation ;
}
2016-02-19 02:39:40 +00:00
bool FState : : CallAction ( AActor * self , AActor * stateowner , FState * * stateret )
2009-09-17 01:36:14 +00:00
{
if ( ActionFunc ! = NULL )
{
2012-10-21 03:46:17 +00:00
ActionCycles . Clock ( ) ;
2016-02-19 02:39:40 +00:00
2012-10-21 03:46:17 +00:00
static VMFrameStack stack ;
2012-07-17 05:31:41 +00:00
VMValue params [ 3 ] = { self , stateowner , VMValue ( this , ATAG_STATE ) } ;
2016-02-19 02:39:40 +00:00
// If the function returns a state, store it at *stateret.
// If it doesn't return a state but stateret is non-NULL, we need
// to set *stateret to NULL.
if ( stateret ! = NULL )
{
* stateret = NULL ;
if ( ActionFunc - > Proto = = NULL | |
ActionFunc - > Proto - > ReturnTypes . Size ( ) = = 0 | |
ActionFunc - > Proto - > ReturnTypes [ 0 ] ! = TypeState )
{
stateret = NULL ;
}
}
if ( stateret = = NULL )
{
stack . Call ( ActionFunc , params , countof ( params ) , NULL , 0 , NULL ) ;
}
else
{
VMReturn ret ;
ret . PointerAt ( ( void * * ) stateret ) ;
stack . Call ( ActionFunc , params , countof ( params ) , & ret , 1 , NULL ) ;
}
2012-10-21 03:46:17 +00:00
ActionCycles . Unclock ( ) ;
2009-09-17 01:36:14 +00:00
return true ;
}
else
{
return false ;
}
}
2009-06-26 17:17:52 +00:00
2006-10-31 14:53:21 +00:00
//==========================================================================
//
//
//==========================================================================
2011-07-04 20:22:55 +00:00
int GetSpriteIndex ( const char * spritename , bool add )
2006-07-13 10:17:56 +00:00
{
2008-12-07 12:11:59 +00:00
static char lastsprite [ 5 ] ;
static int lastindex ;
2008-09-21 18:02:38 +00:00
// Make sure that the string is upper case and 4 characters long
2008-10-05 18:45:05 +00:00
char upper [ 5 ] = { 0 , 0 , 0 , 0 , 0 } ;
2008-09-21 18:02:38 +00:00
for ( int i = 0 ; spritename [ i ] ! = 0 & & i < 4 ; i + + )
{
upper [ i ] = toupper ( spritename [ i ] ) ;
}
2008-12-07 12:11:59 +00:00
// cache the name so if the next one is the same the function doesn't have to perform a search.
if ( ! strcmp ( upper , lastsprite ) )
{
return lastindex ;
}
strcpy ( lastsprite , upper ) ;
2006-07-13 10:17:56 +00:00
for ( unsigned i = 0 ; i < sprites . Size ( ) ; + + i )
{
2008-12-07 12:11:59 +00:00
if ( strcmp ( sprites [ i ] . name , upper ) = = 0 )
2006-07-13 10:17:56 +00:00
{
2008-12-07 12:11:59 +00:00
return ( lastindex = ( int ) i ) ;
2006-07-13 10:17:56 +00:00
}
}
2011-07-04 20:22:55 +00:00
if ( ! add )
{
return ( lastindex = - 1 ) ;
}
2006-07-13 10:17:56 +00:00
spritedef_t temp ;
2008-09-21 18:02:38 +00:00
strcpy ( temp . name , upper ) ;
2006-07-13 10:17:56 +00:00
temp . numframes = 0 ;
temp . spriteframes = 0 ;
2008-12-07 12:11:59 +00:00
return ( lastindex = ( int ) sprites . Push ( temp ) ) ;
2006-07-13 10:17:56 +00:00
}
2010-03-25 20:38:00 +00:00
IMPLEMENT_POINTY_CLASS ( PClassActor )
DECLARE_POINTER ( DropItems )
END_POINTERS
2006-07-13 10:17:56 +00:00
2006-10-31 14:53:21 +00:00
//==========================================================================
//
2010-03-24 02:49:37 +00:00
// PClassActor :: StaticInit STATIC
2006-10-31 14:53:21 +00:00
//
//==========================================================================
2010-03-24 02:49:37 +00:00
void PClassActor : : StaticInit ( )
2006-02-24 04:48:15 +00:00
{
2010-12-13 10:02:45 +00:00
sprites . Clear ( ) ;
2006-02-24 04:48:15 +00:00
if ( sprites . Size ( ) = = 0 )
{
spritedef_t temp ;
// Sprite 0 is always TNT1
memcpy ( temp . name , " TNT1 " , 5 ) ;
temp . numframes = 0 ;
temp . spriteframes = 0 ;
sprites . Push ( temp ) ;
// Sprite 1 is always ----
memcpy ( temp . name , " ---- " , 5 ) ;
sprites . Push ( temp ) ;
2010-04-19 02:46:50 +00:00
// Sprite 2 is always ####
memcpy ( temp . name , " #### " , 5 ) ;
sprites . Push ( temp ) ;
2006-02-24 04:48:15 +00:00
}
2016-02-09 13:20:49 +00:00
if ( ! batchrun ) Printf ( " LoadActors: Load actor definitions. \n " ) ;
2010-12-14 00:50:02 +00:00
ClearStrifeTypes ( ) ;
2008-10-25 17:38:00 +00:00
LoadActors ( ) ;
2010-12-12 21:09:16 +00:00
InitBotStuff ( ) ;
2006-02-24 04:48:15 +00:00
}
2006-10-31 14:53:21 +00:00
//==========================================================================
//
2010-03-24 02:49:37 +00:00
// PClassActor :: StaticSetActorNums STATIC
//
2006-02-24 04:48:15 +00:00
// Called after Dehacked patches are applied
2006-10-31 14:53:21 +00:00
//
//==========================================================================
2010-03-24 02:49:37 +00:00
void PClassActor : : StaticSetActorNums ( )
2006-02-24 04:48:15 +00:00
{
2010-04-16 02:57:51 +00:00
for ( unsigned int i = 0 ; i < PClassActor : : AllActorClasses . Size ( ) ; + + i )
2006-02-24 04:48:15 +00:00
{
2010-04-16 02:57:51 +00:00
static_cast < PClassActor * > ( PClassActor : : AllActorClasses [ i ] ) - > RegisterIDs ( ) ;
2010-03-24 02:49:37 +00:00
}
}
//==========================================================================
//
// PClassActor Constructor
//
//==========================================================================
PClassActor : : PClassActor ( )
{
GameFilter = GAME_Any ;
SpawnID = 0 ;
DoomEdNum = - 1 ;
OwnedStates = NULL ;
NumOwnedStates = 0 ;
Replacement = NULL ;
Replacee = NULL ;
StateList = NULL ;
DamageFactors = NULL ;
PainChances = NULL ;
2010-03-25 20:38:00 +00:00
DeathHeight = - 1 ;
BurnHeight = - 1 ;
GibHealth = INT_MIN ;
WoundHealth = 6 ;
PoisonDamage = 0 ;
FastSpeed = FIXED_MIN ;
RDFactor = FRACUNIT ;
CameraHeight = FIXED_MIN ;
DropItems = NULL ;
DontHurtShooter = false ;
ExplosionRadius = - 1 ;
MeleeDamage = 0 ;
2010-04-16 02:57:51 +00:00
// Record this in the master list.
AllActorClasses . Push ( this ) ;
2010-03-24 02:49:37 +00:00
}
//==========================================================================
//
// PClassActor Destructor
//
//==========================================================================
PClassActor : : ~ PClassActor ( )
{
if ( OwnedStates ! = NULL )
{
delete [ ] OwnedStates ;
}
if ( DamageFactors ! = NULL )
{
delete DamageFactors ;
}
if ( PainChances ! = NULL )
{
delete PainChances ;
}
if ( StateList ! = NULL )
{
StateList - > Destroy ( ) ;
M_Free ( StateList ) ;
2006-02-24 04:48:15 +00:00
}
}
2010-03-25 20:38:00 +00:00
//==========================================================================
//
// PClassActor :: Derive
//
//==========================================================================
2016-02-09 23:17:00 +00:00
void PClassActor : : DeriveData ( PClass * newclass )
2010-03-25 20:38:00 +00:00
{
assert ( newclass - > IsKindOf ( RUNTIME_CLASS ( PClassActor ) ) ) ;
PClassActor * newa = static_cast < PClassActor * > ( newclass ) ;
newa - > Obituary = Obituary ;
newa - > HitObituary = HitObituary ;
newa - > DeathHeight = DeathHeight ;
newa - > BurnHeight = BurnHeight ;
newa - > BloodColor = BloodColor ;
newa - > GibHealth = GibHealth ;
newa - > WoundHealth = WoundHealth ;
newa - > PoisonDamage = PoisonDamage ;
newa - > FastSpeed = FastSpeed ;
newa - > RDFactor = RDFactor ;
newa - > CameraHeight = CameraHeight ;
newa - > HowlSound = HowlSound ;
newa - > BloodType = BloodType ;
newa - > BloodType2 = BloodType2 ;
newa - > BloodType3 = BloodType3 ;
newa - > DropItems = DropItems ;
newa - > DontHurtShooter = DontHurtShooter ;
newa - > ExplosionRadius = ExplosionRadius ;
newa - > ExplosionDamage = ExplosionDamage ;
newa - > MeleeDamage = MeleeDamage ;
newa - > MeleeSound = MeleeSound ;
newa - > MissileName = MissileName ;
newa - > MissileHeight = MissileHeight ;
2016-02-09 23:46:51 +00:00
newa - > VisibleToPlayerClass = VisibleToPlayerClass ;
if ( DamageFactors ! = NULL )
{
// copy damage factors from parent
newa - > DamageFactors = new DmgFactors ;
* newa - > DamageFactors = * DamageFactors ;
}
if ( PainChances ! = NULL )
{
// copy pain chances from parent
newa - > PainChances = new PainChanceList ;
* newa - > PainChances = * PainChances ;
}
2010-03-25 20:38:00 +00:00
}
2006-10-31 14:53:21 +00:00
//==========================================================================
//
2010-03-24 02:49:37 +00:00
// PClassActor :: PropagateMark
2006-10-31 14:53:21 +00:00
//
//==========================================================================
2010-03-24 02:49:37 +00:00
size_t PClassActor : : PropagateMark ( )
2006-02-24 04:48:15 +00:00
{
2010-03-24 02:49:37 +00:00
// Mark state functions
for ( int i = 0 ; i < NumOwnedStates ; + + i )
{
if ( OwnedStates [ i ] . ActionFunc ! = NULL )
{
GC : : Mark ( OwnedStates [ i ] . ActionFunc ) ;
}
}
2012-10-28 04:36:52 +00:00
// Mark damage function
2012-10-29 00:42:58 +00:00
if ( Defaults ! = NULL )
{
GC : : Mark ( ( ( AActor * ) Defaults ) - > Damage ) ;
}
2012-10-28 04:36:52 +00:00
2010-03-24 02:49:37 +00:00
// marked += ActorInfo->NumOwnedStates * sizeof(FState);
return Super : : PropagateMark ( ) ;
}
//==========================================================================
//
// PClassActor :: InitializeNativeDefaults
//
// This is used by DECORATE to assign ActorInfos to internal classes
//
//==========================================================================
void PClassActor : : InitializeNativeDefaults ( )
{
Symbols . SetParentTable ( & ParentClass - > Symbols ) ;
assert ( Defaults = = NULL ) ;
2016-02-05 02:03:34 +00:00
Defaults = ( BYTE * ) M_Malloc ( Size ) ;
2010-03-24 02:49:37 +00:00
if ( ParentClass - > Defaults ! = NULL )
{
memcpy ( Defaults , ParentClass - > Defaults , ParentClass - > Size ) ;
if ( Size > ParentClass - > Size )
{
memset ( Defaults + ParentClass - > Size , 0 , Size - ParentClass - > Size ) ;
}
}
else
{
memset ( Defaults , 0 , Size ) ;
}
}
//==========================================================================
//
// PClassActor :: RegisterIDs
//
// Registers this class's SpawnID and DoomEdNum in the appropriate tables.
//
//==========================================================================
void PClassActor : : RegisterIDs ( )
{
PClassActor * cls = PClass : : FindActor ( TypeName ) ;
2010-02-13 08:56:08 +00:00
2010-03-24 02:49:37 +00:00
if ( cls = = NULL )
{
Printf ( TEXTCOLOR_RED " The actor '%s' has been hidden by a non-actor of the same name \n " , TypeName . GetChars ( ) ) ;
return ;
}
2015-04-04 22:31:15 +00:00
// Conversation IDs have never been filtered by game so we cannot start doing that.
if ( ConversationID > 0 )
{
StrifeTypes [ ConversationID ] = cls ;
2015-04-28 12:45:13 +00:00
if ( cls ! = this )
2015-04-04 22:31:15 +00:00
{
Printf ( TEXTCOLOR_RED " Conversation ID %d refers to hidden class type '%s' \n " , SpawnID , cls - > TypeName . GetChars ( ) ) ;
}
}
2006-02-24 04:48:15 +00:00
if ( GameFilter = = GAME_Any | | ( GameFilter & gameinfo . gametype ) )
{
2012-11-09 23:53:58 +00:00
if ( SpawnID > 0 )
2006-02-24 04:48:15 +00:00
{
2010-02-13 08:56:08 +00:00
SpawnableThings [ SpawnID ] = cls ;
2010-03-24 02:49:37 +00:00
if ( cls ! = this )
2010-02-13 08:56:08 +00:00
{
Printf ( TEXTCOLOR_RED " Spawn ID %d refers to hidden class type '%s' \n " , SpawnID , cls - > TypeName . GetChars ( ) ) ;
}
2006-02-24 04:48:15 +00:00
}
if ( DoomEdNum ! = - 1 )
{
2015-04-03 14:51:45 +00:00
FDoomEdEntry * oldent = DoomEdMap . CheckKey ( DoomEdNum ) ;
if ( oldent ! = NULL & & oldent - > Special = = - 2 )
{
Printf ( TEXTCOLOR_RED " Editor number %d defined twice for classes '%s' and '%s' \n " , DoomEdNum , cls - > TypeName . GetChars ( ) , oldent - > Type - > TypeName . GetChars ( ) ) ;
}
FDoomEdEntry ent ;
memset ( & ent , 0 , sizeof ( ent ) ) ;
ent . Type = cls ;
ent . Special = - 2 ; // use -2 instead of -1 so that we can recognize DECORATE defined entries and print a warning message if duplicates occur.
DoomEdMap . Insert ( DoomEdNum , ent ) ;
2010-03-24 02:49:37 +00:00
if ( cls ! = this )
2010-02-13 08:56:08 +00:00
{
Printf ( TEXTCOLOR_RED " Editor number %d refers to hidden class type '%s' \n " , DoomEdNum , cls - > TypeName . GetChars ( ) ) ;
}
2006-02-24 04:48:15 +00:00
}
}
}
2006-10-31 14:53:21 +00:00
//==========================================================================
//
2010-03-24 02:49:37 +00:00
// PClassActor :: GetReplacement
2006-10-31 14:53:21 +00:00
//
//==========================================================================
2010-03-24 02:49:37 +00:00
PClassActor * PClassActor : : GetReplacement ( bool lookskill )
2006-07-08 02:17:35 +00:00
{
2009-10-03 17:07:11 +00:00
FName skillrepname ;
if ( lookskill & & AllSkills . Size ( ) > ( unsigned ) gameskill )
2009-06-26 21:06:49 +00:00
{
2010-03-24 02:49:37 +00:00
skillrepname = AllSkills [ gameskill ] . GetReplacement ( TypeName ) ;
2009-10-03 17:07:11 +00:00
if ( skillrepname ! = NAME_None & & PClass : : FindClass ( skillrepname ) = = NULL )
{
Printf ( " Warning: incorrect actor name in definition of skill %s: \n "
" class %s is replaced by non-existent class %s \n "
" Skill replacement will be ignored for this actor. \n " ,
AllSkills [ gameskill ] . Name . GetChars ( ) ,
2010-03-24 02:49:37 +00:00
TypeName . GetChars ( ) , skillrepname . GetChars ( ) ) ;
AllSkills [ gameskill ] . SetReplacement ( TypeName , NAME_None ) ;
2009-10-03 17:07:11 +00:00
AllSkills [ gameskill ] . SetReplacedBy ( skillrepname , NAME_None ) ;
lookskill = false ; skillrepname = NAME_None ;
}
2009-06-26 21:06:49 +00:00
}
2009-06-26 17:17:52 +00:00
if ( Replacement = = NULL & & ( ! lookskill | | skillrepname = = NAME_None ) )
2006-07-08 02:17:35 +00:00
{
return this ;
}
// The Replacement field is temporarily NULLed to prevent
// potential infinite recursion.
2010-03-24 02:49:37 +00:00
PClassActor * savedrep = Replacement ;
2006-07-08 02:17:35 +00:00
Replacement = NULL ;
2010-03-24 02:49:37 +00:00
PClassActor * rep = savedrep ;
2009-06-26 17:17:52 +00:00
// Handle skill-based replacement here. It has precedence on DECORATE replacement
// in that the skill replacement is applied first, followed by DECORATE replacement
// on the actor indicated by the skill replacement.
2009-06-26 21:06:49 +00:00
if ( lookskill & & ( skillrepname ! = NAME_None ) )
2009-06-26 17:17:52 +00:00
{
2010-03-24 02:49:37 +00:00
rep = PClass : : FindActor ( skillrepname ) ;
2009-06-26 17:17:52 +00:00
}
// Now handle DECORATE replacement chain
// Skill replacements are not recursive, contrarily to DECORATE replacements
rep = rep - > GetReplacement ( false ) ;
// Reset the temporarily NULLed field
2006-07-08 02:17:35 +00:00
Replacement = savedrep ;
return rep ;
}
2006-10-31 14:53:21 +00:00
//==========================================================================
//
2010-03-24 02:49:37 +00:00
// PClassActor :: GetReplacee
2006-10-31 14:53:21 +00:00
//
//==========================================================================
2010-03-24 02:49:37 +00:00
PClassActor * PClassActor : : GetReplacee ( bool lookskill )
2006-07-16 15:00:10 +00:00
{
2009-10-03 17:07:11 +00:00
FName skillrepname ;
if ( lookskill & & AllSkills . Size ( ) > ( unsigned ) gameskill )
2009-09-14 19:44:14 +00:00
{
2010-03-24 02:49:37 +00:00
skillrepname = AllSkills [ gameskill ] . GetReplacedBy ( TypeName ) ;
2009-10-03 17:07:11 +00:00
if ( skillrepname ! = NAME_None & & PClass : : FindClass ( skillrepname ) = = NULL )
{
Printf ( " Warning: incorrect actor name in definition of skill %s: \n "
" non-existent class %s is replaced by class %s \n "
" Skill replacement will be ignored for this actor. \n " ,
AllSkills [ gameskill ] . Name . GetChars ( ) ,
2010-03-24 02:49:37 +00:00
skillrepname . GetChars ( ) , TypeName . GetChars ( ) ) ;
AllSkills [ gameskill ] . SetReplacedBy ( TypeName , NAME_None ) ;
2009-10-03 17:07:11 +00:00
AllSkills [ gameskill ] . SetReplacement ( skillrepname , NAME_None ) ;
lookskill = false ;
}
2009-06-26 21:06:49 +00:00
}
2009-06-26 17:17:52 +00:00
if ( Replacee = = NULL & & ( ! lookskill | | skillrepname = = NAME_None ) )
2006-07-16 15:00:10 +00:00
{
return this ;
}
// The Replacee field is temporarily NULLed to prevent
// potential infinite recursion.
2010-03-24 02:49:37 +00:00
PClassActor * savedrep = Replacee ;
2006-07-16 15:00:10 +00:00
Replacee = NULL ;
2010-03-24 02:49:37 +00:00
PClassActor * rep = savedrep ;
2009-09-14 19:44:14 +00:00
if ( lookskill & & ( skillrepname ! = NAME_None ) & & ( PClass : : FindClass ( skillrepname ) ! = NULL ) )
{
2010-03-24 02:49:37 +00:00
rep = PClass : : FindActor ( skillrepname ) ;
2009-09-14 19:44:14 +00:00
}
2010-03-24 02:49:37 +00:00
rep = rep - > GetReplacee ( false ) ;
Replacee = savedrep ;
2006-07-16 15:00:10 +00:00
return rep ;
}
2008-08-23 08:48:19 +00:00
//==========================================================================
//
2010-03-24 02:49:37 +00:00
// PClassActor :: SetDamageFactor
2008-08-23 08:48:19 +00:00
//
//==========================================================================
2010-03-24 02:49:37 +00:00
void PClassActor : : SetDamageFactor ( FName type , fixed_t factor )
2008-08-23 08:48:19 +00:00
{
2010-03-22 21:18:54 +00:00
if ( DamageFactors = = NULL )
2008-08-23 08:48:19 +00:00
{
2010-03-22 21:18:54 +00:00
DamageFactors = new DmgFactors ;
2008-08-23 08:48:19 +00:00
}
2010-03-22 21:18:54 +00:00
DamageFactors - > Insert ( type , factor ) ;
2008-08-23 08:48:19 +00:00
}
//==========================================================================
//
2010-03-24 02:49:37 +00:00
// PClassActor :: SetPainChance
2008-08-23 08:48:19 +00:00
//
//==========================================================================
2010-03-24 02:49:37 +00:00
void PClassActor : : SetPainChance ( FName type , int chance )
2008-08-23 08:48:19 +00:00
{
if ( chance > = 0 )
{
2010-03-24 02:49:37 +00:00
if ( PainChances = = NULL )
{
PainChances = new PainChanceList ;
}
2010-03-22 21:18:54 +00:00
PainChances - > Insert ( type , MIN ( chance , 256 ) ) ;
2008-08-23 08:48:19 +00:00
}
2010-03-24 02:49:37 +00:00
else if ( PainChances ! = NULL )
2008-08-23 08:48:19 +00:00
{
2010-03-24 02:49:37 +00:00
PainChances - > Remove ( type ) ;
2008-08-23 08:48:19 +00:00
}
}
2011-06-06 22:23:43 +00:00
2016-02-09 22:08:51 +00:00
//==========================================================================
//
// PClassActor :: ReplaceClassRef
//
//==========================================================================
void PClassActor : : ReplaceClassRef ( PClass * oldclass , PClass * newclass )
{
for ( unsigned i = 0 ; i < VisibleToPlayerClass . Size ( ) ; i + + )
{
if ( VisibleToPlayerClass [ i ] = = oldclass )
VisibleToPlayerClass [ i ] = static_cast < PClassPlayerPawn * > ( newclass ) ;
}
AActor * def = ( AActor * ) Defaults ;
if ( def ! = NULL )
{
if ( def - > TeleFogSourceType = = oldclass ) def - > TeleFogSourceType = static_cast < PClassActor * > ( newclass ) ;
if ( def - > TeleFogDestType = = oldclass ) def - > TeleFogDestType = static_cast < PClassActor * > ( newclass ) ;
}
}
2012-03-23 01:20:45 +00:00
//==========================================================================
//
// DmgFactors :: CheckFactor
//
// Checks for the existance of a certain damage type. If that type does not
// exist, the damage factor for type 'None' will be returned, if present.
//
//==========================================================================
fixed_t * DmgFactors : : CheckFactor ( FName type )
{
fixed_t * pdf = CheckKey ( type ) ;
if ( pdf = = NULL & & type ! = NAME_None )
{
pdf = CheckKey ( NAME_None ) ;
}
return pdf ;
}
2008-12-16 01:23:44 +00:00
static void SummonActor ( int command , int command2 , FCommandLine argv )
2006-02-24 04:48:15 +00:00
{
if ( CheckCheatmode ( ) )
return ;
if ( argv . argc ( ) > 1 )
{
2012-07-14 03:04:41 +00:00
PClassActor * type = PClass : : FindActor ( argv [ 1 ] ) ;
2006-02-24 04:48:15 +00:00
if ( type = = NULL )
{
2012-07-14 03:04:41 +00:00
Printf ( " Unknown actor '%s' \n " , argv [ 1 ] ) ;
2006-02-24 04:48:15 +00:00
return ;
}
2008-12-16 01:23:44 +00:00
Net_WriteByte ( argv . argc ( ) > 2 ? command2 : command ) ;
2006-05-10 02:40:43 +00:00
Net_WriteString ( type - > TypeName . GetChars ( ) ) ;
2008-12-16 01:23:44 +00:00
2012-07-14 03:04:41 +00:00
if ( argv . argc ( ) > 2 )
{
2009-08-03 20:40:45 +00:00
Net_WriteWord ( atoi ( argv [ 2 ] ) ) ; // angle
2012-07-14 03:04:41 +00:00
Net_WriteWord ( ( argv . argc ( ) > 3 ) ? atoi ( argv [ 3 ] ) : 0 ) ; // TID
Net_WriteByte ( ( argv . argc ( ) > 4 ) ? atoi ( argv [ 4 ] ) : 0 ) ; // special
for ( int i = 5 ; i < 10 ; i + + )
{ // args[5]
Net_WriteLong ( ( i < argv . argc ( ) ) ? atoi ( argv [ i ] ) : 0 ) ;
2009-08-03 20:40:45 +00:00
}
}
2006-02-24 04:48:15 +00:00
}
}
2008-12-16 01:23:44 +00:00
CCMD ( summon )
2006-02-24 04:48:15 +00:00
{
2008-12-16 01:23:44 +00:00
SummonActor ( DEM_SUMMON , DEM_SUMMON2 , argv ) ;
}
2006-02-24 04:48:15 +00:00
2008-12-16 01:23:44 +00:00
CCMD ( summonfriend )
{
SummonActor ( DEM_SUMMONFRIEND , DEM_SUMMONFRIEND2 , argv ) ;
2006-02-24 04:48:15 +00:00
}
2007-01-16 03:04:00 +00:00
2009-09-14 19:44:14 +00:00
CCMD ( summonmbf )
{
SummonActor ( DEM_SUMMONMBF , DEM_SUMMONFRIEND2 , argv ) ;
}
2007-01-16 03:04:00 +00:00
CCMD ( summonfoe )
{
2008-12-16 01:23:44 +00:00
SummonActor ( DEM_SUMMONFOE , DEM_SUMMONFOE2 , argv ) ;
2007-01-16 03:04:00 +00:00
}
2012-04-07 12:11:17 +00:00
// Damage type defaults / global settings
TMap < FName , DamageTypeDefinition > GlobalDamageDefinitions ;
2015-02-07 16:02:46 +00:00
void DamageTypeDefinition : : Apply ( FName type )
2012-04-07 12:11:17 +00:00
{
GlobalDamageDefinitions [ type ] = * this ;
}
2015-02-07 16:02:46 +00:00
DamageTypeDefinition * DamageTypeDefinition : : Get ( FName type )
2012-04-07 12:11:17 +00:00
{
return GlobalDamageDefinitions . CheckKey ( type ) ;
}
2015-02-07 16:02:46 +00:00
bool DamageTypeDefinition : : IgnoreArmor ( FName type )
2012-04-07 12:11:17 +00:00
{
DamageTypeDefinition * dtd = Get ( type ) ;
if ( dtd ) return dtd - > NoArmor ;
return false ;
}
//==========================================================================
//
// DamageTypeDefinition :: ApplyMobjDamageFactor
//
// Calculates mobj damage based on original damage, defined damage factors
// and damage type.
//
// If the specific damage type is not defined, the damage factor for
// type 'None' will be used (with 1.0 as a default value).
//
// Globally declared damage types may override or multiply the damage
// factor when 'None' is used as a fallback in this function.
//
//==========================================================================
2015-02-07 16:02:46 +00:00
int DamageTypeDefinition : : ApplyMobjDamageFactor ( int damage , FName type , DmgFactors const * const factors )
2012-04-07 12:11:17 +00:00
{
if ( factors )
{
// If the actor has named damage factors, look for a specific factor
fixed_t const * pdf = factors - > CheckKey ( type ) ;
if ( pdf ) return FixedMul ( damage , * pdf ) ; // type specific damage type
// If this was nonspecific damage, don't fall back to nonspecific search
if ( type = = NAME_None ) return damage ;
}
// If this was nonspecific damage, don't fall back to nonspecific search
else if ( type = = NAME_None )
{
return damage ;
}
else
{
// Normal is unsupplied / 1.0, so there's no difference between modifying and overriding
DamageTypeDefinition * dtd = Get ( type ) ;
return dtd ? FixedMul ( damage , dtd - > DefaultFactor ) : damage ;
}
{
fixed_t const * pdf = factors - > CheckKey ( NAME_None ) ;
2012-04-07 15:29:47 +00:00
DamageTypeDefinition * dtd = Get ( type ) ;
2012-04-07 12:11:17 +00:00
// Here we are looking for modifications to untyped damage
// If the calling actor defines untyped damage factor, that is contained in "pdf".
if ( pdf ) // normal damage available
{
if ( dtd )
{
if ( dtd - > ReplaceFactor ) return FixedMul ( damage , dtd - > DefaultFactor ) ; // use default instead of untyped factor
return FixedMul ( damage , FixedMul ( * pdf , dtd - > DefaultFactor ) ) ; // use default as modification of untyped factor
}
return FixedMul ( damage , * pdf ) ; // there was no default, so actor default is used
}
2012-04-07 15:29:47 +00:00
else if ( dtd )
{
return FixedMul ( damage , dtd - > DefaultFactor ) ; // implicit untyped factor 1.0 does not need to be applied/replaced explicitly
}
2012-04-07 12:11:17 +00:00
}
return damage ;
}