2016-03-27 11:49:47 +02:00
/*
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
2023-08-12 03:03:48 +02:00
Copyright ( C ) 2023 the OpenMoHAA team
2016-03-27 11:49:47 +02:00
This file is part of OpenMoHAA source code .
OpenMoHAA 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 2 of the License ,
or ( at your option ) any later version .
OpenMoHAA 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 OpenMoHAA source code ; if not , write to the Free Software
Foundation , Inc . , 51 Franklin St , Fifth Floor , Boston , MA 02110 - 1301 USA
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =
*/
// scriptmaster.cpp : Spawns at the beginning of the maps, parse scripts.
2023-08-12 03:03:26 +02:00
# include "g_local.h"
2016-03-27 11:49:47 +02:00
# include "scriptmaster.h"
2023-01-29 22:57:04 +01:00
# include "scriptthread.h"
2023-01-30 18:20:50 +01:00
# include "scriptclass.h"
2016-03-27 11:49:47 +02:00
# include "gamescript.h"
# include "game.h"
# include "g_spawn.h"
# include "object.h"
2023-10-08 00:07:12 +02:00
# include "worldspawn.h"
2023-01-30 18:20:50 +01:00
# include "scriptcompiler.h"
2023-04-29 21:56:38 +02:00
# include "scriptexception.h"
2016-03-27 11:49:47 +02:00
# ifdef WIN32
2023-08-12 03:03:26 +02:00
# include <direct.h>
2016-03-27 11:49:47 +02:00
# else
2023-08-12 03:03:26 +02:00
# include <sys / stat.h>
# include <unistd.h>
2016-03-27 11:49:47 +02:00
# endif
2023-08-12 03:03:26 +02:00
# if defined(CGAME_DLL)
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
# include <hud.h>
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
# define SCRIPT_Printf cgi.Printf
# define SCRIPT_DPrintf cgi.DPrintf
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
# elif defined(GAME_DLL)
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
# include "hud.h"
2023-06-17 01:24:20 +02:00
2023-08-12 03:03:26 +02:00
# include "dm_manager.h"
# include "player.h"
# include "entity.h"
# include "huddraw.h"
# include "weaputils.h"
# include "camera.h"
# include "consoleevent.h"
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
# define SCRIPT_Printf gi.Printf
# define SCRIPT_DPrintf gi.DPrintf
2016-03-27 11:49:47 +02:00
# endif
2023-08-12 03:03:26 +02:00
con_set < str , ScriptThreadLabel > m_scriptCmds ;
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
str vision_current ;
2016-03-27 11:49:47 +02:00
qboolean disable_team_change ;
qboolean disable_team_spectate ;
ScriptMaster Director ;
2023-08-12 03:03:26 +02:00
ScriptEvent scriptedEvents [ SE_MAX ] ;
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
CLASS_DECLARATION ( Class , ScriptEvent , NULL ) {
{ NULL , NULL }
2016-03-27 11:49:47 +02:00
} ;
2023-01-29 22:57:04 +01:00
//
// world stuff
//
2023-10-27 20:02:21 +02:00
Event EV_SetTiki
(
2023-08-12 03:03:26 +02:00
" settiki " ,
EV_DEFAULT ,
NULL ,
NULL ,
" Not implemented - used to stop script error on dedicated server "
2016-03-27 11:49:47 +02:00
) ;
2023-01-29 22:57:04 +01:00
Event EV_RegisterAliasAndCache
2016-03-27 11:49:47 +02:00
(
2023-08-12 03:03:26 +02:00
" aliascache " ,
EV_DEFAULT ,
" ssSSSS " ,
" alias_name real_name arg1 arg2 arg3 arg4 " ,
" Sets up an alias and caches the resourse. "
) ;
Event EV_RegisterAlias
(
" alias " ,
EV_DEFAULT ,
" ssSSSS " ,
" alias_name real_name arg1 arg2 arg3 arg4 " ,
" Sets up an alias. "
2016-03-27 11:49:47 +02:00
) ;
2023-01-29 22:57:04 +01:00
Event EV_Cache
2016-03-27 11:49:47 +02:00
(
2023-08-12 03:03:26 +02:00
" cache " ,
EV_CACHE ,
" s " ,
" resourceName " ,
" pre-cache the given resource. "
2016-03-27 11:49:47 +02:00
) ;
2023-08-12 03:03:26 +02:00
CLASS_DECLARATION ( Listener , ScriptMaster , NULL ) {
{ & EV_RegisterAliasAndCache , & ScriptMaster : : RegisterAliasAndCache } ,
{ & EV_RegisterAlias , & ScriptMaster : : RegisterAlias } ,
{ & EV_Cache , & ScriptMaster : : Cache } ,
{ NULL , NULL }
2023-01-29 22:57:04 +01:00
} ;
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
const char * ScriptMaster : : ConstStrings [ ] = {
" " ,
" touch " ,
" block " ,
" trigger " ,
" use " ,
" damage " ,
" location " ,
" say " ,
" fail " ,
" bump " ,
" default " ,
" all " ,
" move_action " ,
" resume " ,
" open " ,
" close " ,
" pickup " ,
" reach " ,
" start " ,
" teleport " ,
" move " ,
" move_end " ,
" moveto " ,
" walkto " ,
" runto " ,
" crouchto " ,
" crawlto " ,
" stop " ,
" reset " ,
" prespawn " ,
" spawn " ,
" playerspawn " ,
" skip " ,
2023-08-20 01:43:59 +02:00
" roundstart " ,
2023-08-12 03:03:26 +02:00
" visible " ,
" not_visible " ,
" done " ,
" animdone " ,
" upperanimdone " ,
" saydone " ,
" flaggedanimdone " ,
" idle " ,
" walk " ,
" shuffle " ,
" anim/crouch.scr " ,
" forgot " ,
" jog_hunch " ,
" jog_hunch_rifle " ,
" killed " ,
" alarm " ,
" scriptclass " ,
" ai/utils/fact_script_factory.scr " ,
" death " ,
" death_fall_to_knees " ,
" enemy " ,
" dead " ,
" mood " ,
" patrol " ,
" runner " ,
" follow " ,
" action " ,
" move_begin " ,
" action_begin " ,
" action_end " ,
" success " ,
" entry " ,
" exit " ,
" path " ,
" node " ,
" ask_count " ,
" attacker " ,
" usecover " ,
" waitcover " ,
" void " ,
" end " ,
" attack " ,
" near " ,
" papers " ,
" check_papers " ,
" timeout " ,
" hostile " ,
" leader " ,
" gamemap " ,
" bored " ,
" nervous " ,
" curious " ,
" alert " ,
" greet " ,
" depend " ,
" anim " ,
" anim_scripted " ,
" anim_curious " ,
" animloop " ,
" undefined " ,
" notset " ,
" increment " ,
" decrement " ,
" toggle " ,
" normal " ,
" suspend " ,
" mystery " ,
" surprise " ,
" anim/crouch_run.scr " ,
" anim/aim.scr " ,
" anim/shoot.scr " ,
" anim/mg42_shoot.scr " ,
" anim/mg42_idle.scr " ,
2024-02-20 23:29:47 +01:00
" anim/mg42_reload.scr " ,
2023-08-12 03:03:26 +02:00
" drive " ,
" global/weapon.scr " ,
" global/moveto.scr " ,
" global/anim.scr " ,
" global/anim_scripted.scr " ,
" global/anim_noclip.scr " ,
2023-10-11 19:27:02 +02:00
" global/anim_attached.scr " ,
2023-08-12 03:03:26 +02:00
" global/walkto.scr " ,
" global/runto.scr " ,
" aimat " ,
" global/disabled_ai.scr " ,
" global/crouchto.scr " ,
" global/crawlto.scr " ,
" global/killed.scr " ,
" global/pain.scr " ,
" pain " ,
" track " ,
" hasenemy " ,
" anim/cower.scr " ,
" anim/stand.scr " ,
" anim/idle.scr " ,
" anim/surprise.scr " ,
" anim/standshock.scr " ,
2023-10-23 19:26:57 +02:00
" anim/standidentify.scr " ,
2023-08-12 03:03:26 +02:00
" anim/standflinch.scr " ,
" anim/dog_idle.scr " ,
" anim/dog_attack.scr " ,
" anim/dog_curious.scr " ,
" anim/dog_chase.scr " ,
" cannon " ,
" grenade " ,
2023-10-11 19:27:02 +02:00
" badplace " ,
2023-08-12 03:03:26 +02:00
" heavy " ,
" item " ,
" items " ,
" item1 " ,
" item2 " ,
" item3 " ,
" item4 " ,
" stand " ,
" mg " ,
" pistol " ,
" rifle " ,
" smg " ,
" turnto " ,
" standing " ,
" crouching " ,
" prone " ,
" offground " ,
" walking " ,
" running " ,
" falling " ,
" anim_nothing " ,
" anim_direct " ,
" anim_path " ,
" anim_waypoint " ,
" anim_direct_nogravity " ,
" emotion_none " ,
" emotion_neutral " ,
" emotion_worry " ,
" emotion_panic " ,
" emotion_fear " ,
" emotion_disgust " ,
" emotion_anger " ,
" emotion_aiming " ,
" emotion_determined " ,
" emotion_dead " ,
" emotion_curious " ,
" anim/emotion.scr " ,
" forceanim " ,
" forceanim_scripted " ,
" turret " ,
" cover " ,
" anim/pain.scr " ,
" anim/killed.scr " ,
" anim/attack.scr " ,
" anim/sniper.scr " ,
2023-10-11 19:27:02 +02:00
" anim/suppress.scr " ,
2023-08-12 03:03:26 +02:00
" knees " ,
" crawl " ,
" floor " ,
" anim/patrol.scr " ,
" anim/run.scr " ,
" crouch " ,
" crouchwalk " ,
" crouchrun " ,
" anim/crouch_walk.scr " ,
" anim/walk.scr " ,
" anim/prone.scr " ,
" anim/runawayfiring.scr " ,
" anim/run_shoot.scr " ,
" anim/runto_alarm.scr " ,
" anim/runto_casual.scr " ,
" anim/runto_cover.scr " ,
" anim/runto_danger.scr " ,
" anim/runto_dive.scr " ,
" anim/runto_flee.scr " ,
" anim/runto_inopen.scr " ,
" anim/disguise_salute.scr " ,
" anim/disguise_wait.scr " ,
" anim/disguise_papers.scr " ,
" anim/disguise_enemy.scr " ,
" anim/disguise_halt.scr " ,
" anim/disguise_accept.scr " ,
" anim/disguise_deny.scr " ,
" anim/cornerleft.scr " ,
" anim/cornerright.scr " ,
" anim/overattack.scr " ,
2023-10-11 19:27:02 +02:00
" anim/lowwall.scr " ,
" anim/highwall.scr " ,
2023-08-12 03:03:26 +02:00
" anim/continue_last_anim.scr " ,
" flagged " ,
" anim/fullbody.scr " ,
" salute " ,
" sentry " ,
" officier " ,
" rover " ,
" none " ,
" machinegunner " ,
" disguise " ,
" dog_idle " ,
" dog_attack " ,
" dog_curious " ,
" dog_grenade " ,
" anim/grenadeturn.scr " ,
" anim/grenadekick.scr " ,
" anim/grenadethrow.scr " ,
" anim/grenadetoss.scr " ,
" anim/grenademartyr.scr " ,
" movedone " ,
" aim " ,
" ontarget " ,
" unarmed " ,
" balcony_idle " ,
" balcony_curious " ,
" balcony_attack " ,
" balcony_disguise " ,
" balcony_grenade " ,
" balcony_pain " ,
" balcony_killed " ,
" weaponless " ,
" death_balcony_intro " ,
" death_balcony_loop " ,
" death_balcony_outtro " ,
" sounddone " ,
" noclip " ,
" german " ,
" american " ,
" spectator " ,
" freeforall " ,
" allies " ,
" axis " ,
" draw " ,
" kills " ,
" allieswin " ,
" axiswin " ,
" anim/say_curious_sight.scr " ,
" anim/say_curious_sound.scr " ,
" anim/say_grenade_sighted.scr " ,
" anim/say_kill.scr " ,
" anim/say_mandown.scr " ,
" anim/say_sighted.scr " ,
" vehicleanimdone " ,
" postthink " ,
" turndone " ,
" anim/no_anim_killed.scr " ,
" mg42 " ,
" mp40 " ,
2024-09-19 21:23:19 +02:00
// Added in 2.0
2023-08-12 03:03:26 +02:00
" auto " ,
" both " ,
2024-09-19 21:23:19 +02:00
// Added in 2.30
2023-08-12 03:03:26 +02:00
" runandshoot " ,
2023-12-28 20:34:49 +01:00
// Added in OPM
2023-08-19 21:06:25 +02:00
" respawn " ,
" viewmodelanim_done "
} ;
2023-08-12 03:03:26 +02:00
ScriptMaster : : ~ ScriptMaster ( )
2023-01-29 22:57:04 +01:00
{
2023-08-12 03:03:26 +02:00
Reset ( false ) ;
2023-01-29 22:57:04 +01:00
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
static int bLoadForMap ( char * psMapsBuffer , const char * name )
2023-01-29 22:57:04 +01:00
{
2023-08-12 03:03:26 +02:00
cvar_t * mapname = gi . Cvar_Get ( " mapname " , " " , 0 ) ;
const char * token ;
if ( ! strncmp ( " test " , mapname - > string , sizeof ( " test " ) ) ) {
return true ;
}
token = COM_Parse ( & psMapsBuffer ) ;
if ( ! token | | ! * token ) {
Com_Printf ( " ERROR bLoadForMap: %s alias with empty maps specification. \n " , name ) ;
return false ;
}
while ( token & & * token ) {
if ( ! Q_stricmpn ( token , mapname - > string , strlen ( token ) ) ) {
return true ;
}
token = COM_Parse ( & psMapsBuffer ) ;
}
return false ;
2023-01-29 22:57:04 +01:00
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
void ScriptMaster : : RegisterAliasInternal ( Event * ev , bool bCache )
2023-01-29 22:57:04 +01:00
{
2023-08-12 03:03:26 +02:00
int i ;
char parameters [ MAX_STRING_CHARS ] ;
char * psMapsBuffer ;
int subtitle ;
bool bAlwaysLoaded = false ;
// Get the parameters for this alias command
parameters [ 0 ] = 0 ;
subtitle = 0 ;
psMapsBuffer = NULL ;
for ( i = 3 ; i < = ev - > NumArgs ( ) ; i + + ) {
str s ;
// MOHAA doesn't check that
if ( ev - > IsListenerAt ( i ) ) {
Listener * l = ev - > GetListener ( i ) ;
if ( l & & l = = Director . CurrentThread ( ) ) {
s = " local " ;
} else {
s = ev - > GetString ( i ) ;
}
} else {
s = ev - > GetString ( i ) ;
}
if ( subtitle ) {
strcat ( parameters , " \" " ) ;
strcat ( parameters , s ) ;
strcat ( parameters , " \" " ) ;
subtitle = 0 ;
} else if ( ! s . icmp ( " maps " ) ) {
i + + ;
psMapsBuffer = ( char * ) ev - > GetToken ( i ) . c_str ( ) ;
} else if ( ! s . icmp ( " always " ) ) {
bAlwaysLoaded = true ;
} else {
subtitle = s . icmp ( " subtitle " ) = = 0 ;
strcat ( parameters , s ) ;
strcat ( parameters , " " ) ;
}
}
if ( bAlwaysLoaded | | bLoadForMap ( psMapsBuffer , ev - > GetString ( 1 ) ) ) {
gi . GlobalAlias_Add ( ev - > GetString ( 1 ) , ev - > GetString ( 2 ) , parameters ) ;
if ( bCache ) {
CacheResource ( ev - > GetString ( 2 ) ) ;
}
}
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
void ScriptMaster : : RegisterAliasAndCache ( Event * ev )
2023-01-29 22:57:04 +01:00
{
2023-08-12 03:03:26 +02:00
RegisterAliasInternal ( ev , true ) ;
2023-01-29 22:57:04 +01:00
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
void ScriptMaster : : RegisterAlias ( Event * ev )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
RegisterAliasInternal ( ev ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : Cache ( Event * ev )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
# ifdef GAME_DLL
if ( ! precache - > integer ) {
return ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
CacheResource ( ev - > GetString ( 1 ) ) ;
# endif
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : InitConstStrings ( void )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
EventDef * eventDef ;
const_str name ;
unsigned int eventnum ;
con_map_enum < Event * , EventDef > en ;
2024-09-19 21:23:19 +02:00
int i ;
2023-08-12 03:03:26 +02:00
2024-09-19 21:23:19 +02:00
static_assert ( ARRAY_LEN ( ConstStrings ) = = ( STRING_LENGTH_ - 1 ) , " Constant strings don't match. Make sure the 'const_str' enum match with the 'ConstStrings' string array " ) ;
for ( i = 0 ; i < ARRAY_LEN ( ConstStrings ) ; i + + ) {
2023-08-12 03:03:26 +02:00
AddString ( ConstStrings [ i ] ) ;
}
Event : : normalCommandList . clear ( ) ;
Event : : returnCommandList . clear ( ) ;
Event : : getterCommandList . clear ( ) ;
Event : : setterCommandList . clear ( ) ;
en = Event : : eventDefList ;
for ( en . NextValue ( ) ; en . CurrentValue ( ) ! = NULL ; en . NextValue ( ) ) {
eventDef = en . CurrentValue ( ) ;
eventnum = ( * en . CurrentKey ( ) ) - > eventnum ;
str command = eventDef - > command . c_str ( ) ;
2024-04-22 20:10:01 +02:00
if ( eventDef - > type = = EV_NORMAL | | eventDef - > type = = EV_RETURN ) {
command . tolower ( ) ;
}
2023-08-12 03:03:26 +02:00
name = AddString ( command ) ;
if ( eventDef - > type = = EV_NORMAL ) {
Event : : normalCommandList [ name ] = eventnum ;
} else if ( eventDef - > type = = EV_RETURN ) {
Event : : returnCommandList [ name ] = eventnum ;
} else if ( eventDef - > type = = EV_GETTER ) {
Event : : getterCommandList [ name ] = eventnum ;
} else if ( eventDef - > type = = EV_SETTER ) {
Event : : setterCommandList [ name ] = eventnum ;
}
}
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
ScriptThread * ScriptMaster : : CreateThread ( str filename , str label , Listener * self )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
GameScript * scr = GetScript ( filename ) ;
if ( ! scr ) {
return NULL ;
}
return CreateThread ( scr , label , self ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
ScriptThread * ScriptMaster : : CreateThread ( GameScript * scr , str label , Listener * self )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
try {
return CreateScriptThread ( scr , self , label ) ;
} catch ( ScriptException & exc ) {
gi . DPrintf ( " ScriptMaster::CreateThread: %s \n " , exc . string . c_str ( ) ) ;
return NULL ;
}
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : ExecuteThread ( str filename , str label )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
GameScript * scr = GetScript ( filename ) ;
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
if ( ! scr ) {
return ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
ExecuteThread ( scr , label ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : ExecuteThread ( GameScript * scr , str label )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
ScriptThread * thread = CreateThread ( scr , label ) ;
try {
if ( thread ) {
thread - > Execute ( ) ;
}
} catch ( ScriptException & exc ) {
gi . DPrintf ( " ScriptMaster::ExecuteThread: %s \n " , exc . string . c_str ( ) ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : ExecuteThread ( str filename , str label , Event & parms )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
GameScript * scr = GetScript ( filename ) ;
if ( ! scr ) {
return ;
}
ExecuteThread ( scr , label , parms ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : ExecuteThread ( GameScript * scr , str label , Event & parms )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
ScriptThread * thread = CreateThread ( scr , label ) ;
try {
thread - > Execute ( parms ) ;
} catch ( ScriptException & exc ) {
gi . DPrintf ( " ScriptMaster::ExecuteThread: %s \n " , exc . string . c_str ( ) ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
ScriptThread * ScriptMaster : : CreateScriptThread ( GameScript * scr , Listener * self , const_str label )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
ScriptClass * scriptClass = new ScriptClass ( scr , self ) ;
return CreateScriptThread ( scriptClass , label ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
ScriptThread * ScriptMaster : : CreateScriptThread ( ScriptClass * scriptClass , unsigned char * m_pCodePos )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
return new ScriptThread ( scriptClass , m_pCodePos ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
ScriptThread * ScriptMaster : : CreateScriptThread ( ScriptClass * scriptClass , const_str label )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
unsigned char * m_pCodePos = scriptClass - > FindLabel ( label ) ;
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
if ( ! m_pCodePos ) {
throw ScriptException (
" ScriptMaster::CreateScriptThread: label '%s' does not exist in '%s'. " ,
Director . GetString ( label ) . c_str ( ) ,
scriptClass - > Filename ( ) . c_str ( )
) ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
return CreateScriptThread ( scriptClass , m_pCodePos ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
ScriptThread * ScriptMaster : : CreateScriptThread ( GameScript * scr , Listener * self , str label )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
return CreateScriptThread ( scr , self , Director . AddString ( label ) ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
ScriptThread * ScriptMaster : : CreateScriptThread ( ScriptClass * scriptClass , str label )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
if ( label . length ( ) & & * label ) {
return CreateScriptThread ( scriptClass , Director . AddString ( label ) ) ;
} else {
return CreateScriptThread ( scriptClass , STRING_EMPTY ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : Reset ( qboolean samemap )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
ScriptClass_allocator . FreeAll ( ) ;
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
stackCount = 0 ;
cmdCount = 0 ;
cmdTime = 0 ;
maxTime = MAX_EXECUTION_TIME ;
//pTop = &avar_Stack[ 0 ];
iPaused = 0 ;
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
# if defined(GAME_DLL)
for ( int i = 1 ; i < = m_menus . NumObjects ( ) ; i + + ) {
Hidemenu ( m_menus . ObjectAt ( i ) , true ) ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
m_menus . ClearObjectList ( ) ;
# endif
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
if ( ! samemap ) {
for ( int i = 0 ; i < SE_MAX ; i + + ) {
scriptedEvents [ i ] = ScriptEvent ( ) ;
}
CloseGameScript ( ) ;
StringDict . clear ( ) ;
InitConstStrings ( ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : ExecuteRunning ( void )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
int i ;
int startTime ;
2023-10-27 20:02:21 +02:00
int startMs ;
str fileName ;
str sourcePosString ;
2023-08-12 03:03:26 +02:00
if ( stackCount ) {
return ;
}
2016-03-27 11:49:47 +02:00
2023-10-27 20:02:21 +02:00
if ( ! timerList . IsDirty ( ) ) {
return ;
}
2023-08-12 03:03:26 +02:00
2023-10-27 20:02:21 +02:00
cmdTime = 0 ;
cmdCount = 0 ;
startTime = level . svsTime ;
2023-08-12 03:03:26 +02:00
2023-10-27 20:02:21 +02:00
try {
while ( ( m_CurrentThread = ( ScriptThread * ) timerList . GetNextElement ( i ) ) ) {
if ( g_timescripts - > integer ) {
fileName = m_CurrentThread - > FileName ( ) ;
sourcePosString = m_CurrentThread - > m_ScriptVM - > GetSourcePos ( ) ;
startMs = gi . Milliseconds ( ) ;
2023-10-24 23:18:44 +02:00
}
2023-08-12 03:03:26 +02:00
2023-10-27 20:02:21 +02:00
level . setTime ( level . svsStartTime + i ) ;
m_CurrentThread - > m_ScriptVM - > m_ThreadState = THREAD_RUNNING ;
m_CurrentThread - > m_ScriptVM - > Execute ( ) ;
if ( g_timescripts - > integer ) {
str string ;
string = " Execute Running: " ;
string + = str ( gi . Milliseconds ( ) - startMs / 1000.f ) ;
string + = " file: " ;
string + = fileName ;
string + = " codepos: " ;
string + = sourcePosString ;
gi . DebugPrintf ( " %s \n " , string . c_str ( ) ) ;
}
}
} catch ( const ScriptException & e ) {
gi . Error ( ERR_DROP , " %s " , e . string . c_str ( ) ) ;
2023-08-12 03:03:26 +02:00
}
2023-10-27 20:02:21 +02:00
level . setTime ( startTime ) ;
level . m_LoopProtection = true ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : SetTime ( int time )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
timerList . SetTime ( time ) ;
2016-03-27 11:49:47 +02:00
}
2023-10-27 21:02:18 +02:00
void ScriptMaster : : AddTiming ( ScriptThread * thread , int time )
2016-03-27 11:49:47 +02:00
{
2023-10-27 21:02:18 +02:00
timerList . AddElement ( thread , time ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : RemoveTiming ( ScriptThread * thread )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
timerList . RemoveElement ( thread ) ;
2023-01-29 22:57:04 +01:00
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
ScriptClass * ScriptMaster : : CurrentScriptClass ( void )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
return CurrentThread ( ) - > GetScriptClass ( ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : CloseGameScript ( void )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
con_map_enum < const_str , GameScript * > en ( m_GameScripts ) ;
GameScript * * g ;
Container < GameScript * > gameScripts ;
for ( g = en . NextValue ( ) ; g ! = NULL ; g = en . NextValue ( ) ) {
gameScripts . AddObject ( * g ) ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
for ( int i = gameScripts . NumObjects ( ) ; i > 0 ; i - - ) {
delete gameScripts . ObjectAt ( i ) ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
m_GameScripts . clear ( ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
GameScript * ScriptMaster : : GetGameScriptInternal ( str & filename )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
void * sourceBuffer = NULL ;
int sourceLength ;
char filepath [ MAX_QPATH ] ;
GameScript * scr ;
2023-01-29 22:57:04 +01:00
2023-08-12 03:03:26 +02:00
if ( filename . length ( ) > = MAX_QPATH ) {
gi . Error ( ERR_DROP , " Script filename '%s' exceeds maximum length of %d \n " , filename . c_str ( ) , MAX_QPATH ) ;
}
2016-03-27 11:49:47 +02:00
2024-09-20 21:53:48 +02:00
Q_strncpyz ( filepath , filename . c_str ( ) , sizeof ( filepath ) ) ;
2024-05-01 17:54:41 +02:00
gi . FS_CanonicalFilename ( filepath ) ;
filename = filepath ;
2023-08-12 03:03:26 +02:00
scr = m_GameScripts [ StringDict . findKeyIndex ( filename ) ] ;
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
if ( scr ! = NULL ) {
return scr ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
scr = new GameScript ( filename ) ;
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
m_GameScripts [ StringDict . addKeyIndex ( filename ) ] = scr ;
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
if ( GetCompiledScript ( scr ) ) {
scr - > m_Filename = Director . AddString ( filename ) ;
return scr ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
sourceLength = gi . FS_ReadFile ( filename . c_str ( ) , & sourceBuffer , true ) ;
2016-03-27 11:49:47 +02:00
2023-08-19 20:46:24 +02:00
if ( sourceLength = = - 1 ) {
2023-08-12 03:03:26 +02:00
throw ScriptException ( " Can't find '%s' \n " , filename . c_str ( ) ) ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
scr - > Load ( sourceBuffer , sourceLength ) ;
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
gi . FS_FreeFile ( sourceBuffer ) ;
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
if ( ! scr - > successCompile ) {
throw ScriptException ( " Script '%s' was not properly loaded " , filename . c_str ( ) ) ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
return scr ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
GameScript * ScriptMaster : : GetGameScript ( const_str filename , qboolean recompile )
{
return GetGameScript ( Director . GetString ( filename ) , recompile ) ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
GameScript * ScriptMaster : : GetGameScript ( str filename , qboolean recompile )
{
const_str s = StringDict . findKeyIndex ( filename ) ;
GameScript * scr = m_GameScripts [ s ] ;
int i ;
if ( scr ! = NULL & & ! recompile ) {
if ( ! scr - > successCompile ) {
throw ScriptException ( " Script '%s' was not properly loaded \n " , filename . c_str ( ) ) ;
}
return scr ;
} else {
if ( scr & & recompile ) {
Container < ScriptClass * > list ;
MEM_BlockAlloc_enum < ScriptClass > en = ScriptClass_allocator ;
ScriptClass * scriptClass ;
m_GameScripts [ s ] = NULL ;
for ( scriptClass = en . NextElement ( ) ; scriptClass ! = NULL ; scriptClass = en . NextElement ( ) ) {
if ( scriptClass - > GetScript ( ) = = scr ) {
list . AddObject ( scriptClass ) ;
}
}
for ( i = 1 ; i < = list . NumObjects ( ) ; i + + ) {
delete list . ObjectAt ( i ) ;
}
delete scr ;
}
return GetGameScriptInternal ( filename ) ;
}
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
GameScript * ScriptMaster : : GetScript ( const_str filename , qboolean recompile )
{
try {
return GetGameScript ( filename , recompile ) ;
} catch ( ScriptException & exc ) {
gi . DPrintf ( " ScriptMaster::GetScript: %s \n " , exc . string . c_str ( ) ) ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
return NULL ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
GameScript * ScriptMaster : : GetScript ( str filename , qboolean recompile )
{
try {
return GetGameScript ( filename , recompile ) ;
} catch ( ScriptException & exc ) {
gi . DPrintf ( " ScriptMaster::GetScript: %s \n " , exc . string . c_str ( ) ) ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
return NULL ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : ArchiveString ( Archiver & arc , const_str & s )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
str s2 ;
byte b ;
if ( arc . Loading ( ) ) {
arc . ArchiveByte ( & b ) ;
if ( b ) {
arc . ArchiveString ( & s2 ) ;
s = AddString ( s2 ) ;
} else {
s = 0 ;
}
} else {
if ( s ) {
b = 1 ;
arc . ArchiveByte ( & b ) ;
s2 = Director . GetString ( s ) ;
arc . ArchiveString ( & s2 ) ;
} else {
b = 0 ;
arc . ArchiveByte ( & b ) ;
}
}
2023-01-29 22:57:04 +01:00
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
void ScriptMaster : : Archive ( Archiver & arc )
2016-03-27 11:49:47 +02:00
{
2023-11-27 19:30:40 +01:00
int count ;
int i , j ;
ScriptClass * c ;
int num ;
ScriptVM * scriptVM ;
ScriptVM * prevScriptVM ;
2023-08-12 03:03:26 +02:00
if ( arc . Saving ( ) ) {
2023-11-27 19:30:40 +01:00
count = ( int ) ScriptClass_allocator . Count ( ) ;
arc . ArchiveInteger ( & count ) ;
2023-08-12 03:03:26 +02:00
MEM_BlockAlloc_enum < ScriptClass > en = ScriptClass_allocator ;
2023-11-27 19:30:40 +01:00
for ( c = en . NextElement ( ) ; c ! = NULL ; c = en . NextElement ( ) ) {
c - > ArchiveInternal ( arc ) ;
2023-08-12 03:03:26 +02:00
2023-11-27 19:30:40 +01:00
num = 0 ;
for ( scriptVM = c - > m_Threads ; scriptVM ! = NULL ; scriptVM = scriptVM - > next ) {
num + + ;
2023-08-12 03:03:26 +02:00
}
2023-11-27 19:30:40 +01:00
arc . ArchiveInteger ( & num ) ;
2023-08-12 03:03:26 +02:00
2023-11-27 19:30:40 +01:00
for ( scriptVM = c - > m_Threads ; scriptVM ! = NULL ; scriptVM = scriptVM - > next ) {
scriptVM - > m_Thread - > ArchiveInternal ( arc ) ;
2023-08-12 03:03:26 +02:00
}
}
} else {
2023-11-27 19:30:40 +01:00
arc . ArchiveInteger ( & count ) ;
2023-08-12 03:03:26 +02:00
2023-11-27 19:30:40 +01:00
for ( i = 0 ; i < count ; i + + ) {
c = new ScriptClass ( ) ;
c - > ArchiveInternal ( arc ) ;
2023-08-12 03:03:26 +02:00
2023-11-27 19:30:40 +01:00
arc . ArchiveInteger ( & num ) ;
2023-08-12 03:03:26 +02:00
2023-11-27 19:30:40 +01:00
c - > m_Threads = NULL ;
prevScriptVM = NULL ;
for ( j = 0 ; j < num ; j + + ) {
scriptVM = new ScriptVM ;
scriptVM - > m_Thread = new ScriptThread ;
scriptVM - > m_Thread - > m_ScriptVM = scriptVM ;
scriptVM - > m_ScriptClass = c ;
scriptVM - > next = NULL ;
if ( prevScriptVM ) {
prevScriptVM - > next = scriptVM ;
} else {
c - > m_Threads = scriptVM ;
}
prevScriptVM = scriptVM ;
scriptVM - > m_Thread - > ArchiveInternal ( arc ) ;
2023-08-12 03:03:26 +02:00
}
}
}
timerList . Archive ( arc ) ;
m_menus . Archive ( arc ) ;
2023-01-29 22:57:04 +01:00
}
2018-08-19 08:26:59 +02:00
2023-08-12 03:03:26 +02:00
GameScript * ScriptMaster : : GetTempScript ( const char * data )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
GameScript * scr = new GameScript ;
2023-01-29 22:57:04 +01:00
2023-08-12 03:03:26 +02:00
scr - > Load ( ( void * ) data , strlen ( data ) ) ;
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
if ( ! scr - > successCompile ) {
return NULL ;
}
2023-01-29 22:57:04 +01:00
2023-08-12 03:03:26 +02:00
return scr ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
void ScriptMaster : : AddMenu ( str name )
{
m_menus . AddUniqueObject ( name ) ;
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
void ScriptMaster : : RemoveMenu ( str name )
{
if ( m_menus . IndexOfObject ( name ) ) {
m_menus . RemoveObject ( name ) ;
}
}
2016-03-27 11:49:47 +02:00
2023-08-12 03:03:26 +02:00
void ScriptMaster : : LoadMenus ( void )
{
for ( int i = 1 ; i < = m_menus . NumObjects ( ) ; i + + ) {
Showmenu ( m_menus . ObjectAt ( i ) , true ) ;
}
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
ScriptThread * ScriptMaster : : PreviousThread ( void )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
return m_PreviousThread ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
ScriptThread * ScriptMaster : : CurrentThread ( void )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
return m_CurrentThread ;
2023-01-29 22:57:04 +01:00
}
2023-08-12 03:03:26 +02:00
ScriptThread * ScriptMaster : : CurrentScriptThread ( void )
2023-01-29 22:57:04 +01:00
{
2023-08-12 03:03:26 +02:00
assert ( m_CurrentThread ) ;
if ( ! m_CurrentThread ) {
ScriptError ( " current thread is NULL " ) ;
}
return m_CurrentThread ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
const_str ScriptMaster : : AddString ( const char * s )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
return StringDict . addKeyIndex ( s ) ;
2016-03-27 11:49:47 +02:00
}
2023-08-12 03:03:26 +02:00
const_str ScriptMaster : : AddString ( str & s )
2016-03-27 11:49:47 +02:00
{
2023-08-12 03:03:26 +02:00
return StringDict . addKeyIndex ( s ) ;
2017-06-08 11:46:08 +02:00
}
2023-08-12 03:03:26 +02:00
const_str ScriptMaster : : GetString ( const char * s )
2017-06-08 11:46:08 +02:00
{
2023-08-12 03:03:26 +02:00
const_str cs = StringDict . findKeyIndex ( s ) ;
return cs ? cs : STRING_EMPTY ;
2017-06-08 11:46:08 +02:00
}
2023-08-12 03:03:26 +02:00
const_str ScriptMaster : : GetString ( str s )
2017-06-08 11:46:08 +02:00
{
2023-08-12 03:03:26 +02:00
return GetString ( s . c_str ( ) ) ;
2017-06-08 11:46:08 +02:00
}
2023-08-12 03:03:26 +02:00
str & ScriptMaster : : GetString ( const_str s )
2017-06-08 11:46:08 +02:00
{
2023-08-12 03:03:26 +02:00
return StringDict [ s ] ;
}
2017-06-08 11:46:08 +02:00
2023-08-12 03:03:26 +02:00
void ScriptMaster : : Pause ( )
{
iPaused + + ;
}
void ScriptMaster : : Unpause ( )
{
2023-10-31 23:24:11 +01:00
iPaused - - ;
if ( iPaused = = 0 ) {
2023-08-12 03:03:26 +02:00
ExecuteRunning ( ) ;
}
2023-01-29 22:57:04 +01:00
}
2023-08-12 02:40:03 +02:00
2023-08-12 03:03:26 +02:00
void ScriptMaster : : AllowPause ( bool allow )
2023-08-12 02:40:03 +02:00
{
2023-08-12 03:03:26 +02:00
if ( allow ) {
iPaused = 0 ;
} else {
iPaused = - 1 ;
}
2023-08-12 02:40:03 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : PrintStatus ( void )
2023-08-12 02:40:03 +02:00
{
2023-08-12 03:03:26 +02:00
str status ;
int iThreadNum = 0 ;
int iThreadRunning = 0 ;
int iThreadWaiting = 0 ;
int iThreadSuspended = 0 ;
MEM_BlockAlloc_enum < ScriptClass > en = ScriptClass_allocator ;
ScriptClass * scriptClass ;
char szBuffer [ MAX_STRING_TOKENS ] ;
status = " num state label script \n " ;
status + = " ------- ---------- --------------- --------------- \n " ;
for ( scriptClass = en . NextElement ( ) ; scriptClass ! = NULL ; scriptClass = en . NextElement ( ) ) {
ScriptVM * vm ;
for ( vm = scriptClass - > m_Threads ; vm ! = NULL ; vm = vm - > next ) {
2024-09-20 21:53:48 +02:00
Com_sprintf ( szBuffer , sizeof ( szBuffer ) , " %.7d " , iThreadNum ) ;
2023-08-12 03:03:26 +02:00
status + = szBuffer + str ( " " ) ;
switch ( vm - > ThreadState ( ) ) {
case THREAD_RUNNING :
2024-09-20 21:53:48 +02:00
Com_sprintf ( szBuffer , sizeof ( szBuffer ) , " %8s " , " running " ) ;
2023-08-12 03:03:26 +02:00
iThreadRunning + + ;
break ;
case THREAD_WAITING :
2024-09-20 21:53:48 +02:00
Com_sprintf ( szBuffer , sizeof ( szBuffer ) , " %8s " , " waiting " ) ;
2023-08-12 03:03:26 +02:00
iThreadWaiting + + ;
break ;
case THREAD_SUSPENDED :
2024-09-20 21:53:48 +02:00
Com_sprintf ( szBuffer , sizeof ( szBuffer ) , " %8s " , " suspended " ) ;
2023-08-12 03:03:26 +02:00
iThreadSuspended + + ;
break ;
}
status + = szBuffer ;
2024-09-20 21:53:48 +02:00
Com_sprintf ( szBuffer , sizeof ( szBuffer ) , " %15s " , vm - > Label ( ) . c_str ( ) ) ;
2023-08-12 03:03:26 +02:00
status + = szBuffer + str ( " " ) ;
2024-09-20 21:53:48 +02:00
Com_sprintf ( szBuffer , sizeof ( szBuffer ) , " %15s " , vm - > Filename ( ) . c_str ( ) ) ;
2023-08-12 03:03:26 +02:00
status + = szBuffer ;
status + = " \n " ;
iThreadNum + + ;
}
}
status + = " ------- ---------- --------------- --------------- \n " ;
status + = str ( m_GameScripts . size ( ) ) + " total scripts compiled \n " ;
status + = str ( iThreadNum ) + " total threads ( " + str ( iThreadRunning ) + " running thread(s), " + str ( iThreadWaiting )
+ " waiting thread(s), " + str ( iThreadSuspended ) + " suspended thread(s) ) \n " ;
gi . Printf ( status . c_str ( ) ) ;
2023-08-12 02:40:03 +02:00
}
2023-08-12 03:03:26 +02:00
void ScriptMaster : : PrintThread ( int iThreadNum )
2023-08-12 02:40:03 +02:00
{
2023-08-12 03:03:26 +02:00
int iThread = 0 ;
ScriptVM * vm ;
bool bFoundThread = false ;
str status ;
MEM_BlockAlloc_enum < ScriptClass > en = ScriptClass_allocator ;
ScriptClass * scriptClass ;
for ( scriptClass = en . NextElement ( ) ; scriptClass ! = NULL ; scriptClass = en . NextElement ( ) ) {
for ( vm = scriptClass - > m_Threads ; vm ! = NULL ; vm = vm - > next ) {
if ( iThread = = iThreadNum ) {
bFoundThread = true ;
break ;
}
iThread + + ;
}
if ( bFoundThread ) {
break ;
}
}
if ( ! bFoundThread ) {
gi . Printf ( " Can't find thread id %i. \n " , iThreadNum ) ;
}
status = " ------------------------- \n " ;
status + = " num: " + str ( iThreadNum ) + " \n " ;
switch ( vm - > ThreadState ( ) ) {
case THREAD_RUNNING :
status + = " state: running \n " ;
break ;
case THREAD_WAITING :
status + = " state: waiting \n " ;
break ;
case THREAD_SUSPENDED :
status + = " state: suspended \n " ;
break ;
}
status + = " script: ' " + vm - > Filename ( ) + " ' \n " ;
status + = " label: ' " + vm - > Label ( ) + " ' \n " ;
status + = " waittill: " ;
if ( ! vm - > m_Thread - > m_WaitForList ) {
status + = " (none) \n " ;
} else {
2023-10-24 23:18:44 +02:00
con_set_enum < const_str , ConList > en = * vm - > m_Thread - > m_WaitForList ;
2023-08-19 02:56:51 +02:00
con_set < const_str , ConList > : : Entry * entry ;
2023-10-24 23:18:44 +02:00
int i = 0 ;
2023-08-12 03:03:26 +02:00
for ( entry = en . NextElement ( ) ; entry ! = NULL ; entry = en . NextElement ( ) ) {
2023-11-28 19:28:19 +01:00
str & name = Director . GetString ( entry - > GetKey ( ) ) ;
2023-08-12 03:03:26 +02:00
if ( i > 0 ) {
status + = " , " ;
}
status + = " ' " + name + " ' " ;
for ( int j = 1 ; j < = entry - > value . NumObjects ( ) ; j + + ) {
Listener * l = entry - > value . ObjectAt ( j ) ;
if ( j > 1 ) {
status + = " , " ;
}
if ( l ) {
status + = " on " + str ( l - > getClassname ( ) ) ;
} else {
status + = " on (null) " ;
}
}
i + + ;
}
status + = " \n " ;
}
gi . Printf ( status . c_str ( ) ) ;
2023-08-12 02:40:03 +02:00
}