2016-03-27 11:49:47 +02:00
|
|
|
/*
|
|
|
|
===========================================================================
|
2023-10-28 00:01:57 +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
|
|
|
|
===========================================================================
|
|
|
|
*/
|
|
|
|
|
|
|
|
// actor.cpp: Base class for character AI.
|
|
|
|
|
|
|
|
#include "g_local.h"
|
|
|
|
#include "actor.h"
|
2023-01-29 22:57:04 +01:00
|
|
|
#include "scriptthread.h"
|
2023-01-31 19:28:10 +01:00
|
|
|
#include "scriptclass.h"
|
2016-03-27 11:49:47 +02:00
|
|
|
#include "doors.h"
|
|
|
|
#include "gibs.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "specialfx.h"
|
|
|
|
#include "object.h"
|
|
|
|
#include "scriptslave.h"
|
|
|
|
#include "explosion.h"
|
|
|
|
#include "misc.h"
|
|
|
|
#include "playerstart.h"
|
|
|
|
#include "characterstate.h"
|
|
|
|
#include "weaputils.h"
|
|
|
|
#include "player.h"
|
2018-08-02 15:12:07 +02:00
|
|
|
#include "bg_local.h"
|
|
|
|
#include "weapturret.h"
|
2018-08-05 17:56:40 +02:00
|
|
|
#include "sentient.h"
|
2023-04-29 21:56:38 +02:00
|
|
|
#include "g_phys.h"
|
|
|
|
#include "debuglines.h"
|
|
|
|
#include "scriptexception.h"
|
2023-06-17 01:24:20 +02:00
|
|
|
#include "parm.h"
|
|
|
|
#include "../qcommon/tiki.h"
|
2023-10-15 15:08:01 +02:00
|
|
|
#include "smokesprite.h"
|
2023-01-30 00:23:47 +01:00
|
|
|
|
2019-08-18 22:06:49 +02:00
|
|
|
#include <cmath>
|
2018-08-02 15:12:07 +02:00
|
|
|
|
2018-08-19 08:26:59 +02:00
|
|
|
extern Vector PLAYER_BASE_MIN;
|
|
|
|
extern Vector PLAYER_BASE_MAX;
|
|
|
|
|
|
|
|
bool bEntinfoInit = false;
|
|
|
|
|
2018-08-02 15:12:07 +02:00
|
|
|
cvar_t *g_showinfo;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
const char *gAmericanVoices[] = {"a", "c", "h"};
|
|
|
|
const char *gGermanVoices[] = {"a", "c", "d"};
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-14 18:59:35 +02:00
|
|
|
static const float DEFAULT_NEARBY_SQUAD_DIST = 1024;
|
2023-10-16 00:29:41 +02:00
|
|
|
static const float MIN_BADPLACE_UPDATE_DIST = 256;
|
2023-10-14 18:59:35 +02:00
|
|
|
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetGun
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"gun",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"s",
|
|
|
|
"specifies the gun to use",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetGun2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"gun",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"s",
|
|
|
|
"specifies the gun to use",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetGun
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"gun",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"gets the gun to being used",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_WeaponInternal
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"weapon_internal",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"s",
|
|
|
|
"internal use",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_TestAnim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"testanim",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_DistToEnemy
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"distancetoenemy",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Get the distance from the Actor to its enemy",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_MoveTo
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"moveto",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"ss",
|
|
|
|
"anim dest",
|
|
|
|
"Specify the location to move to, with animation anim.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_WalkTo
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"walkto",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"dest",
|
|
|
|
"Specify the location to walk to.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_RunTo
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"runto",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"dest",
|
|
|
|
"Specify the location to run to.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_CrouchTo
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"crouchto",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"dest",
|
|
|
|
"Specify the location to crouch to.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_CrawlTo
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"crawlto",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"dest",
|
|
|
|
"Specify the location to crawl to.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_AimAt
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"aimat",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"target",
|
|
|
|
"Specify the target to aim at.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_Follow
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"follow",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"e",
|
|
|
|
"entity",
|
|
|
|
"Specify the entity to follow.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_DeathEmbalm
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"deathembalm",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"preps the dead actor for turning nonsolid gradually over time",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_Anim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"anim",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"name",
|
|
|
|
"Play animation.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_Anim_Scripted
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"anim_scripted",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"name",
|
|
|
|
"Play scripted animation.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_Anim_Noclip
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"anim_noclip",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"name",
|
|
|
|
"Play noclip animation.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
Event EV_Actor_Anim_Attached
|
|
|
|
(
|
|
|
|
"anim_attached",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"name",
|
|
|
|
"Play attached animation.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_AnimLoop
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"animloop",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"name",
|
|
|
|
"Loop animation.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_AnimScript
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"animscript",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"name",
|
|
|
|
"Play the animation script",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_AnimScript_Scripted
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"animscript_scripted",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"name",
|
|
|
|
"Play the scripted animation script",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_AnimScript_Noclip
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"animscript_noclip",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"name",
|
|
|
|
"Play the noclip animation script",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2024-09-01 20:04:02 +02:00
|
|
|
// Added in 2.0
|
|
|
|
//====
|
2023-10-11 22:49:06 +02:00
|
|
|
Event EV_Actor_AnimScript_Attached
|
|
|
|
(
|
|
|
|
"animscript_attached",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"name",
|
|
|
|
"Play a noclip animation even when attached",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2024-09-01 20:04:02 +02:00
|
|
|
//====
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_Reload_mg42
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"reload_mg42",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Reload the mg42 - only used by machinegunner",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_Dumb
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"dumb",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Make Actor dumb.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_Physics_On
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"physics_on",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"turn physics on.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_Physics_Off
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"physics_off",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"turn physics off.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAnim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"setanim",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"sifs",
|
|
|
|
"anim slot weight flagged",
|
|
|
|
"Set animation slot",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAnimLength
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"setanimlength",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"time",
|
|
|
|
"Set the maximum time an animation will play",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_EndActionAnim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"endactionanim",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"",
|
|
|
|
"",
|
|
|
|
"End any aiming/action animation which is currently playing",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetMotionAnim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"setmotionanim",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"anim",
|
|
|
|
"Set motion animation (handler scripts only)",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAimMotionAnim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"setaimmotionanim",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"ss",
|
|
|
|
"anim_crouch anim_stand",
|
|
|
|
"Set aim motion animation (handler scripts only)",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetActionAnim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"setactionanim",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"sff",
|
|
|
|
"base_anim lower_limit upper_limit",
|
|
|
|
"Set the base action animation and range that they cover",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_UpperAnim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"upperanim",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"anim",
|
|
|
|
"Set the upper body animation",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetUpperAnim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"setupperanim",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"anim",
|
|
|
|
"Set the upper body animation - used by animation script only",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetCrossblendTime
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"blendtime",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Set the crossblend time to something other than the default, in seconds",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetCrossblendTime
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"blendtime",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Get the crossblend time",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetPosition
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"position",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"The Position the Actor wants to be and should animate towards",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetPosition
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"position",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"The Position the Actor wants to be and should animate towards",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetEmotion
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"emotion",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"The method of setting the facial expression of the Actor",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAnimFinal
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"animfinal",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Whether the animation was succesfully finished",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetWeaponType
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"weapontype",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"The Weapon Type of the Actor",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetWeaponGroup
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"weapongroup",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Specifies weapon animation set to use in anim scripts",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Entity_Start
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"entitystart",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Initialize a Actor.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_LookAt
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"lookat",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"e",
|
|
|
|
"entity",
|
|
|
|
"The actor will look at this entity.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_EyesLookAt
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"eyeslookat",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"e",
|
|
|
|
"entity",
|
|
|
|
"The actor will look at this entity.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_PointAt
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"pointat",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"e",
|
|
|
|
"entity",
|
|
|
|
"The actor will point at this entity.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_TurnTo
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"turnto",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"e",
|
|
|
|
"entity",
|
|
|
|
"The actor will turn to this entity.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetTurnDoneError
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"turndoneerror",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"error",
|
|
|
|
"The error amount that turndone will occur for the turnto command.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetTurnDoneError2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"turndoneerror",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"error",
|
|
|
|
"The error amount that turndone will occur for the turnto command.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetTurnDoneError
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"turndoneerror",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"The error amount that turndone will occur for the turnto command.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_IdleSayAnim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"idlesay",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"animation",
|
|
|
|
"The name of an idle dialog animation to play",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SayAnim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"say",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"animation",
|
|
|
|
"The name of a dialog animation to play",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetSayAnim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"setsay",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"animation",
|
|
|
|
"The name of a dialog animation to play - used by animation script only",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_DamagePuff
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"damagepuff",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"vv",
|
|
|
|
"position direction",
|
2024-09-19 10:52:47 +02:00
|
|
|
"Spawns a puff of 'blood' smoke at the specified location in the specified direction.",
|
2023-10-11 22:49:06 +02:00
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAngleYawSpeed
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"turnspeed",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"speed",
|
|
|
|
"The turn speed of the actor.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAngleYawSpeed2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"turnspeed",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"speed",
|
|
|
|
"The turn speed of the actor.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetAngleYawSpeed
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"turnspeed",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"The turn speed of the actor.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAimTarget
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"setaimtarget",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"ei",
|
|
|
|
"entity bMakeEnemy",
|
|
|
|
"Sets the primary weapon's aim target. if you pass a 1 for p2, the target will become the current enemy...",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_ReadyToFire
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"ReadyToFire",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Returns if ready to fire",
|
|
|
|
EV_RETURN
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_AIOff
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"ai_off",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Turns the AI off for this actor.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_AIOn
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"ai_on",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Turns the AI on for this actor.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetSight
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"sight",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the vision distance of the actor.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetSight
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"sight",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"max_sight_range",
|
|
|
|
"Sets the vision distance of the actor.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetSight2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"sight",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"max_sight_range",
|
|
|
|
"Sets the vision distance of the actor.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetHearing
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"hearing",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"radius",
|
|
|
|
"The hearing radius of the actor",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetHearing
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"hearing",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"radius",
|
|
|
|
"The hearing radius of the actor",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetHearing2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"hearing",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"radius",
|
|
|
|
"The hearing radius of the actor",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetFov
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"fov",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"The fov angle of the actor",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetFov
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"fov",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"angle",
|
|
|
|
"The fov angle of the actor",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetFov2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"fov",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"angle",
|
|
|
|
"The fov angle of the actor",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetTypeIdle
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"type_idle",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the idle type of the actor.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetTypeIdle2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"type_idle",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the idle type of the actor.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetTypeIdle
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"type_idle",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the idle type of the actor.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetTypeAttack
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"type_attack",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the attack type of the actor.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetTypeAttack2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"type_attack",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the attack type of the actor.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetTypeAttack
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"type_attack",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the attack type of the actor.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetTypeDisguise
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"type_disguise",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the disguise type of the actor.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetTypeDisguise2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"type_disguise",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the disguise type of the actor.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetTypeDisguise
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"type_disguise",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the disguise type of the actor.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetDisguiseLevel
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"disguise_level",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"value",
|
|
|
|
"Sets the disguise level of the actor. May be 1 or 2",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetDisguiseLevel2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"disguise_level",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"value",
|
|
|
|
"Sets the disguise level of the actor. May be 1 or 2",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetDisguiseLevel
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"disguise_level",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the disguise level of the actor. May be 1 or 2",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetTypeGrenade
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"type_grenade",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the grenade type of the actor.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetTypeGrenade2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"type_grenade",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the grenade type of the actor.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetTypeGrenade
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"type_grenade",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the grenade type of the actor.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetPatrolPath
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"patrolpath",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the name of the patrol path for the actor (must have type set to patrol for effect)",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetPatrolPath2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"patrolpath",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the name of the patrol path for the actor (must have type set to patrol for effect)",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetPatrolPath
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"patrolpath",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the name of the patrol path for the actor (must have type set to patrol for effect)",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetPatrolWaitTrigger
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"waittrigger",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"b",
|
|
|
|
"bool",
|
|
|
|
"If true, patrol guys and running men wait until triggered to move",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetPatrolWaitTrigger2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"waittrigger",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"b",
|
|
|
|
"bool",
|
|
|
|
"If true, patrol guys and running men wait until triggered to move",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetPatrolWaitTrigger
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"waittrigger",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"If true, patrol guys and running men wait until triggered to move",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAlarmNode
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"alarmnode",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the name of the alarm node for the actor (must have type set to alarm for effect)",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAlarmNode2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"alarmnode",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the name of the alarm node for the actor (must have type set to alarm for effect)",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetAlarmNode
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"alarmnode",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the name of the alarm node for the actor (must have type set to alarm for effect)",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2024-09-01 20:04:02 +02:00
|
|
|
// Added in 2.30
|
|
|
|
//====
|
2023-10-11 22:49:06 +02:00
|
|
|
Event EV_Actor_SetPreAlarmThread
|
|
|
|
(
|
|
|
|
"prealarmthread",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the name of the pre alarm thread for the actor (must have type set to alarm for effect)",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
Event EV_Actor_SetPreAlarmThread2
|
|
|
|
(
|
|
|
|
"prealarmthread",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the name of the pre alarm thread for the actor (must have type set to alarm for effect)",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2024-09-01 20:04:02 +02:00
|
|
|
//====
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAlarmThread
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"alarmthread",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the name of the alarm thread for the actor (must have type set to alarm for effect)",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAlarmThread2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"alarmthread",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the name of the alarm thread for the actor (must have type set to alarm for effect)",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetAlarmThread
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"alarmthread",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the name of the alarm thread for the actor (must have type set to alarm for effect)",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetDisguiseAcceptThread
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"disguise_accept_thread",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the name of the thread for the actor to start when accepting papers",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetDisguiseAcceptThread2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"disguise_accept_thread",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"value",
|
|
|
|
"Sets the name of the thread for the actor to start when accepting papers",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetDisguiseAcceptThread
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"disguise_accept_thread",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the name of the thread for the actor to start when accepting papers",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAccuracy
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"accuracy",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"value",
|
|
|
|
"Set percent to hit",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAccuracy2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"accuracy",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"value",
|
|
|
|
"Set percent to hit",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetAccuracy
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"accuracy",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Set percent to hit",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetMinDistance
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"mindist",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"distance",
|
|
|
|
"Sets the minimum distance the AI tries to keep between itself and the player",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetMinDistance2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"mindist",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"distance",
|
|
|
|
"Sets the minimum distance the AI tries to keep between itself and the player",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetMinDistance
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"mindist",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the minimum distance the AI tries to keep between itself and the player",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetMaxDistance
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"maxdist",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"distance",
|
|
|
|
"Sets the maximum distance the AI tries to allow between itself and the player",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetMaxDistance2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"maxdist",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"distance",
|
|
|
|
"Sets the maximum distance the AI tries to allow between itself and the player",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetMaxDistance
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"maxdist",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the maximum distance the AI tries to keep between itself and the player",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetLeash
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"leash",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the maximum distance the AI will wander from its leash home",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetLeash
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"leash",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"distance",
|
|
|
|
"Sets the maximum distance the AI will wander from its leash home",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetLeash2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"leash",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"distance",
|
|
|
|
"Sets the maximum distance the AI will wander from its leash home",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetInterval
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"interval",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the distance AI tries to keep between squadmates while moving.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetInterval
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"interval",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"distance",
|
|
|
|
"Sets the distance AI tries to keep between squadmates while moving.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetInterval2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"interval",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"distance",
|
|
|
|
"Sets the distance AI tries to keep between squadmates while moving.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetRunAnim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"GetRunAnim",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Internal usage",
|
|
|
|
EV_RETURN
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetWalkAnim
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"GetWalkAnim",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Internal usage",
|
|
|
|
EV_RETURN
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetAnimName
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"animname",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the animname.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAnimName
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"animname",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Sets the animname.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetDisguiseRange
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"disguise_range",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"range_in_units",
|
|
|
|
"Sets the maximum distance for disguise behavior to get triggered",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetDisguiseRange2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"disguise_range",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"range_in_units",
|
|
|
|
"Sets the maximum distance for disguise behavior to get triggered",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetDisguiseRange
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"disguise_range",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the maximum distance for disguise behavior to get triggered",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetDisguisePeriod
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"disguise_period",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"period_in_seconds",
|
|
|
|
"Sets the time between the end of one disguise behavior and start of the next",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetDisguisePeriod2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"disguise_period",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"period_in_seconds",
|
|
|
|
"Sets the time between the end of one disguise behavior and start of the next",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetDisguisePeriod
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"disguise_period",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the time between the end of one disguise behavior and start of the next",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_AttackPlayer
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"attackplayer",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Force Actor to attack the player",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetSoundAwareness
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"sound_awareness",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"awareness_percent",
|
|
|
|
"sets the awareness of sounds in 0-100 percent chance of hearing a sound withinhalf of the sound's radius' fades "
|
|
|
|
"to z"
|
|
|
|
"ero outside sound's radius",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetSoundAwareness2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"sound_awareness",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"awareness_percent",
|
|
|
|
"sets the awareness of sounds in 0-100 percent chance of hearing a sound withinhalf of the sound's radius' fades "
|
|
|
|
"to z"
|
|
|
|
"ero outside sound's radius",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetSoundAwareness
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"sound_awareness",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"gets the awareness of sounds in 0-100 percent chance of hearing a sound withinhalf of the sound's radius' fades "
|
|
|
|
"to z"
|
|
|
|
"ero outside sound's radius",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetGrenadeAwareness
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"gren_awareness",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"awareness_percent",
|
|
|
|
"sets the awareness of grenades in 0-100 percent chance of responding to a grenadewhen the AI sees it (applied "
|
|
|
|
"once e"
|
|
|
|
"very 0.4 seconds)",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetGrenadeAwareness2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"gren_awareness",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"awareness_percent",
|
|
|
|
"sets the awareness of grenades in 0-100 percent chance of responding to a grenadewhen the AI sees it (applied "
|
|
|
|
"once e"
|
|
|
|
"very 0.4 seconds)",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetGrenadeAwareness
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"gren_awareness",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"gets the awareness of grenades in 0-100 percent chance of responding to a grenadewhen the AI sees it (applied "
|
|
|
|
"once e"
|
|
|
|
"very 0.4 seconds)",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetTurret
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"turret",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"turret",
|
|
|
|
"Sets the turret of the actor.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetTurret2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"turret",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"turret",
|
|
|
|
"Sets the turret of the actor.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetTurret
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"turret",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the turret of the actor.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_AttachGrenade
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"attachgrenade",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Used only by grenade return animations to tell the code when to attach the grenade to the actor",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_DetachGrenade
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"detachgrenade",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Used only by grenade return animations to tell the code when to throw the grenade",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_FireGrenade
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"fire_grenade",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Used only by grenade throw animations to tell the code when to throw a grenade",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_EnableEnemy
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"enableEnemy",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"sets enableEnemy variable",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_EnablePain
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"enablePain",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"sets enablePain variable",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetPainHandler
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"painhandler",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Sets the current script that will handle pain events",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetPainHandler
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"painhandler",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the current script that will handle pain events",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetDeathHandler
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"deathhandler",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Sets the current script that will handle death events",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetDeathHandler
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"deathhandler",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the current script that will handle death events",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAttackHandler
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"attackhandler",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Sets the current script that will handle attack events",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetAttackHandler
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"attackhandler",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the current script that will handle attack events",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAmmoGrenade
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"ammo_grenade",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"grenade_count",
|
|
|
|
"Gives the AI some grenades",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAmmoGrenade2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"ammo_grenade",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"grenade_count",
|
|
|
|
"Gives the AI some grenades",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetAmmoGrenade
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"ammo_grenade",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Returns how many grenades an AI has",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetMood
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"mood",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"new_mood",
|
|
|
|
"sets the AI mood... must be 'bored', 'nervous', 'curious', or 'alert'.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetMood
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"mood",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"gets the AI mood: 'bored', 'nervous', 'curious', or 'alert'.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetHeadModel
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"headmodel",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"headmodel",
|
|
|
|
"sets the head model",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetHeadModel
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"headmodel",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"gets the head model",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetHeadSkin
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"headskin",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"headskin",
|
|
|
|
"sets the head skin",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetHeadSkin
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"headskin",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"gets the head skin",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_ShareEnemy
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"share_enemy",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"internal code use only - shares an AI's enemy with his squad mates.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_ShareGrenade
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"share_grenade",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"internal code use only - shares an AI's grenade with his squad mates.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_InterruptPoint
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"interrupt_point",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"hint from animation scripts to AI code that now is a good time to switch animations",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetNoIdle
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"no_idle",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Specifies if the actor will not go into idle after playing an animation",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetNoIdle
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"no_idle",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets if the actor will not go into idle after playing an animation",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetEnemy
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"enemy",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Get the actor's current enemy",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetMaxNoticeTimeScale
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"noticescale",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Get the max multiplier in time to notice an enemy (default 100, half as big notices twice as fast)",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetMaxNoticeTimeScale
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"noticescale",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"multiplier",
|
|
|
|
"Set the max multiplier in time to notice an enemy (default 100, half as big notices twice as fast)",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetMaxNoticeTimeScale2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"noticescale",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"multiplier",
|
|
|
|
"Set the max multiplier in time to notice an enemy (default 100, half as big notices twice as fast)",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2023-10-12 18:19:22 +02:00
|
|
|
Event EV_Actor_GetFixedLeash(
|
2023-10-11 22:49:06 +02:00
|
|
|
"fixedleash",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"if non-zero, the leash will never auto-reset; if zero, the leash may auto-reset",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2023-10-12 18:19:22 +02:00
|
|
|
Event EV_Actor_SetFixedLeash(
|
2023-10-11 22:49:06 +02:00
|
|
|
"fixedleash",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"multiplier",
|
|
|
|
"if non-zero, the leash will never auto-reset; if zero, the leash may auto-reset",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2023-10-12 18:19:22 +02:00
|
|
|
Event EV_Actor_SetFixedLeash2(
|
2023-10-11 22:49:06 +02:00
|
|
|
"fixedleash",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"multiplier",
|
|
|
|
"if non-zero, the leash will never auto-reset; if zero, the leash may auto-reset",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_Holster
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"holster",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
2023-12-28 20:50:47 +01:00
|
|
|
"holster",
|
|
|
|
"If non-zero, affects offhand. Holster weapon",
|
2023-10-11 22:49:06 +02:00
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_Unholster
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"unholster",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
2023-12-28 20:50:47 +01:00
|
|
|
"holster",
|
|
|
|
"If non-zero, affects offhand. Unholster weapon",
|
2023-10-11 22:49:06 +02:00
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_IsEnemyVisible
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"is_enemy_visible",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"0 if the enemy is not currently visible, 1 if he is",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetEnemyVisibleChangeTime
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"enemy_visible_change_time",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Get the last time whether or not the enemy is visible changed, in seconds",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetLastEnemyVisibleTime
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"last_enemy_visible_time",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Get the last time the enemy was visible, in seconds",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetFallHeight
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"fallheight",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"height",
|
|
|
|
"Set the fallheight",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetFallHeight2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"fallheight",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"height",
|
|
|
|
"Set the fallheight",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetFallHeight
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"fallheight",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Set the fallheight",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
|
|
|
Event EV_Actor_CanMoveTo(
|
|
|
|
"canmoveto",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"v",
|
|
|
|
"position",
|
|
|
|
"returns a boolean if the AI can move to a point; for use in anim scripts",
|
|
|
|
EV_RETURN
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_MoveDir
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"movedir",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Returns a unit vector pointing in the current direction of motion, or zero if not moving.This still has meaning "
|
|
|
|
"if v"
|
|
|
|
"elocity is zero but the AI is starting to move on a path.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_ResetLeash
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"resetleash",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"resets the AI's leash to their current position",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_IntervalDir
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"intervaldir",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"the direction the AI would like to move to maintain its interval",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_Tether
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"tether",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"e",
|
|
|
|
"entity",
|
|
|
|
"the entity to which the AI's leash should be tethered",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
Event EV_Actor_GetThinkState(
|
|
|
|
"thinkstate",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"current ai think state; can be void, idle, pain, killed, attack, curious, disguise, or grenade.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetEnemyShareRange
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"enemysharerange",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"gets the range outside which the AI will not receive notification that a teammate has a new enemy",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetEnemyShareRange
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"enemysharerange",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"range",
|
|
|
|
"sets the range outside which the AI will not receive notification that a teammate has a new enemy",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetEnemyShareRange2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"enemysharerange",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"range",
|
|
|
|
"sets the range outside which the AI will not receive notification that a teammate has a new enemy",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetWeapon
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"weapon",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"weapon_modelname",
|
|
|
|
"Sets the weapon.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetWeapon
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"weapon",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the weapon.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetVoiceType
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"voicetype",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the voice type",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetVoiceType
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"voicetype",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Set voicetype to magic letter postfix",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetVoiceType2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"voicetype",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Set voicetype to magic letter postfix",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_KickDir
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"kickdir",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets the direction the AI wants to kick",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetNoLongPain
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"nolongpain",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Returns 1 if long pain is not allowed, or 0 if long pain is allowed.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetNoLongPain
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"nolongpain",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"allow",
|
|
|
|
"Set to 1 if long pain is not allowed, or 0 if long pain is allowed.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetNoLongPain2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"nolongpain",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"allow",
|
|
|
|
"Set to 1 if long pain is not allowed, or 0 if long pain is allowed.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetFavoriteEnemy
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"favoriteenemy",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Gets this AI's favorite enemy",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetFavoriteEnemy
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"favoriteenemy",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"e",
|
|
|
|
"ai_or_player",
|
|
|
|
"Gets this AI's favorite enemy",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetFavoriteEnemy2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"favoriteenemy",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"e",
|
|
|
|
"ai_or_player",
|
|
|
|
"Gets this AI's favorite enemy",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetMumble
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"mumble",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Returns 1 if this guy is allowed to mumble, or 0 if he is not",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetMumble
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"mumble",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"can_mumble",
|
|
|
|
"Set to 1 if this guy is allowed to mumble, or 0 if he is not",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetMumble2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
2023-10-12 18:19:22 +02:00
|
|
|
"mumble",
|
|
|
|
EV_DEFAULT,
|
2023-10-11 22:49:06 +02:00
|
|
|
"i",
|
|
|
|
"can_mumble",
|
|
|
|
"Set to 1 if this guy is allowed to mumble, or 0 if he is not",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetBreathSteam
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"breathsteam",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Returns 1 if this guy is allowed to have steamy breath, or 0 if he is not",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetBreathSteam
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"breathsteam",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"can_breathe_out",
|
|
|
|
"Set to 1 if this guy is allowed to have steamy breath, or 0 if he is not",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetBreathSteam2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"breathsteam",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"can_breathe_out",
|
|
|
|
"Set to 1 if this guy is allowed to have steamy breath, or 0 if he is not",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetNextBreathTime
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"nextbreathtime",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"time_in_sec",
|
|
|
|
"Sets the next time the guy will breath out",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_CalcGrenadeToss
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"calcgrenadetoss",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"v",
|
|
|
|
"target_position",
|
|
|
|
"Called to calculate a grenade toss. Must be called before a grenade throwing animation.\n"
|
|
|
|
"Returns the name of the script to call with animscript if the toss can succeed, or if the toss won't work.\n"
|
|
|
|
"Should be called infrequently, and never during the middle of a grenade toss.",
|
|
|
|
EV_RETURN
|
|
|
|
);
|
|
|
|
Event EV_Actor_CalcGrenadeToss2
|
|
|
|
(
|
|
|
|
"calcgrenadetoss2",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"vf",
|
|
|
|
"target_position speed",
|
|
|
|
"Called to calculate a grenade toss. Must be called before a grenade throwing animation.\n"
|
|
|
|
"Returns the name of the script to call with animscript if the toss can succeed, or if the toss won't work.\n"
|
|
|
|
"Should be called infrequently, and never during the middle of a grenade toss.\n"
|
|
|
|
" The speed parameter is optional. Pass a speed if you just want to override and throw no matter what...",
|
|
|
|
EV_RETURN
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetNoSurprise
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"nosurprise",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"gets whether or not this guy is allowed to play a surprised animation when first encountering an enemy.\n",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetNoSurprise
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"nosurprise",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"nosurprise",
|
|
|
|
"set to 0 to allow this guy to play a surprised animation when first encountering an enemy.\n",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetNoSurprise2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"nosurprise",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"nosurprise",
|
|
|
|
"set to 0 to allow this guy to play a surprised animation when first encountering an enemy.\n",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetSilent
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"silent",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"gets whether or not this guy is allowed to say stuff besides pain and death sounds",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetSilent
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"silent",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"silent",
|
|
|
|
"set to 0 to prevent this guy from saying stuff besides pain and death sounds.\n",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetSilent2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"silent",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"silent",
|
|
|
|
"set to 0 to prevent this guy from saying stuff besides pain and death sounds.\n",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetAvoidPlayer
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"avoidplayer",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"is 0 if this AI won't automatically get out of the way, non-zero if he will\n",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAvoidPlayer
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"avoidplayer",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"allowavoid",
|
|
|
|
"set to 0 if this AI shouldn't automatically get out of the way, non-zero if he should.\n",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetAvoidPlayer2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"avoidplayer",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"allowavoid",
|
|
|
|
"set to 0 if this AI shouldn't automatically get out of the way, non-zero if he should.\n",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetMoveDoneRadius
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"movedoneradius",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"radius",
|
|
|
|
"Set the waittill movedone radius, default 0 means don't use manual radius",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
|
|
|
Event EV_Actor_GetMoveDoneRadius
|
|
|
|
(
|
|
|
|
"movedoneradius",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"radius",
|
|
|
|
"Set the waittill movedone radius, default 0 means don't use manual radius",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2023-10-12 18:19:22 +02:00
|
|
|
Event EV_Actor_BeDead(
|
2023-10-11 22:49:06 +02:00
|
|
|
"bedead",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Forces the actor to be instantly and totally dead; no death animation is played",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetLookAroundAngle
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"lookaroundangle",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"gets the angle in degrees left or right of center that the AI will look around while patrolling",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetLookAroundAngle
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"lookaroundangle",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"angle",
|
|
|
|
"gets the angle in degrees left or right of center that the AI will look around while patrolling",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetLookAroundAngle2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"lookaroundangle",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"angle",
|
|
|
|
"gets the angle in degrees left or right of center that the AI will look around while patrolling",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_HasCompleteLookahead
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"hascompletelookahead",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"returns true if there are no corners to turn on the rest of the AI's current path",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_PathDist
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"pathdist",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"returns total distance along current path to the path goal",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_CanShootEnemyFrom
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"canshootenemyfrom",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"v",
|
|
|
|
"shootOrigin",
|
|
|
|
"Determines if it would be possible to shoot the sentient's enemy from the given position.",
|
|
|
|
EV_RETURN
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_CanShoot
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"canshoot",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"v",
|
|
|
|
"shootOrigin",
|
|
|
|
"Determines if it would be possible to shoot the sentient's enemy from the given position.",
|
|
|
|
EV_RETURN
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetInReload
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"inreload",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"returns non-zero if the AI is in a reload",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetInReload
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"inreload",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"reloading",
|
|
|
|
"set to non-zero to indicate the AI is in a reload",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2023-10-12 18:19:22 +02:00
|
|
|
Event EV_Actor_SetReloadCover(
|
2023-10-11 22:49:06 +02:00
|
|
|
"setreloadcover",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"do this command to let the ai know it needs to reload; used to reload while going to cover",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_BreakSpecial
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"breakspecial",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"tell ai to break special attack",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetBalconyHeight
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"balconyheight",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"height",
|
|
|
|
"minimum height a balcony guy must fall to do special balcony death",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_SetBalconyHeight2
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"balconyheight",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"height",
|
|
|
|
"minimum height a balcony guy must fall to do special balcony death",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
Event EV_Actor_GetBalconyHeight
|
2023-10-11 22:49:06 +02:00
|
|
|
(
|
|
|
|
"balconyheight",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"minimum height a balcony guy must fall to do special balcony death",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2024-09-01 20:04:02 +02:00
|
|
|
//
|
|
|
|
// Added in 2.0
|
|
|
|
//====
|
2023-10-11 22:49:06 +02:00
|
|
|
Event EV_Actor_SetVisibilityThreshold
|
|
|
|
(
|
|
|
|
"nonvislevel",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"visibility level in range 0-1 below which an enemy is treated as non-visible",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
Event EV_Actor_SetVisibilityThreshold2
|
|
|
|
(
|
|
|
|
"nonvislevel",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"visibility level in range 0-1 below which an enemy is treated as non-visible",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
|
|
|
Event EV_Actor_GetVisibilityThreshold
|
|
|
|
(
|
|
|
|
"nonvislevel",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"visibility level in range 0-1 below which an enemy is treated as non-visible",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
|
|
|
Event EV_Actor_SetDefaultVisibilityThreshold
|
|
|
|
(
|
|
|
|
"defaultnonvislevel",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"updates the default value for 'nonvislevel'",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
Event EV_Actor_SetSuppressChance
|
|
|
|
(
|
|
|
|
"suppresschance",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"sets the percent chance of doing suppressing fire when appropriate (0-100)",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
Event EV_Actor_SetSuppressChance2
|
|
|
|
(
|
|
|
|
"suppresschance",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"sets the percent chance of doing suppressing fire when appropriate (0-100)",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
|
|
|
Event EV_Actor_GetSuppressChance
|
|
|
|
(
|
|
|
|
"suppresschance",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"sets the percent chance of doing suppressing fire when appropriate (0-100)",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
|
|
|
Event EV_Actor_SetIgnoreBadPlace
|
|
|
|
(
|
|
|
|
"ignorebadplaces",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"ignore",
|
|
|
|
"sets whether or not this AI guy will ignore bad places (0 = not suicidal)",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
Event EV_Actor_SetIgnoreBadPlace2
|
|
|
|
(
|
|
|
|
"ignorebadplaces",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"i",
|
|
|
|
"ignore",
|
|
|
|
"sets whether or not this AI guy will ignore bad places (0 = not suicidal)",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
|
|
|
Event EV_Actor_GetIgnoreBadPlace
|
|
|
|
(
|
|
|
|
"ignorebadplaces",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"gets whether or not this AI guy will ignore bad places (0 = not suicidal)",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
|
|
|
Event EV_Actor_FindEnemy
|
|
|
|
(
|
|
|
|
"findenemy",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Finds the best enemy to target",
|
|
|
|
EV_RETURN
|
|
|
|
);
|
|
|
|
Event EV_Actor_DisableEnemySwitch
|
|
|
|
(
|
|
|
|
"enemyswitchdisable",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Disable enemy switching...",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
Event EV_Actor_EnableEnemySwitch
|
|
|
|
(
|
|
|
|
"enemyswitchenable",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Enable enemy switching...",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
Event EV_Actor_SetRunAnimRate
|
|
|
|
(
|
|
|
|
"runanimrate",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"multiplier",
|
|
|
|
"Set the rate at which the run animation plays back",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
|
|
|
Event EV_Actor_SetRunAnimRate2
|
|
|
|
(
|
|
|
|
"runanimrate",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"f",
|
|
|
|
"multiplier",
|
|
|
|
"Set the rate at which the run animation plays back",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
Event EV_Actor_GetRunAnimRate
|
|
|
|
(
|
|
|
|
"runanimrate",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Get the rate at which the run animation plays back",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
2024-09-01 20:04:02 +02:00
|
|
|
//====
|
|
|
|
//
|
|
|
|
// Added in 2.30
|
|
|
|
//====
|
2023-10-11 22:49:06 +02:00
|
|
|
Event EV_Actor_SetNationality
|
|
|
|
(
|
|
|
|
"nationality",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"nationality",
|
|
|
|
"Set the nationality of an actor. Valid entries are default, ger, it, usa, uk, and ussr.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
Event EV_Actor_SetNationality2
|
|
|
|
(
|
|
|
|
"nationality",
|
|
|
|
EV_DEFAULT,
|
|
|
|
"s",
|
|
|
|
"nationality",
|
|
|
|
"Set the nationality of an actor. Valid entries are default, ger, it, usa, uk, and ussr.",
|
|
|
|
EV_SETTER
|
|
|
|
);
|
|
|
|
Event EV_Actor_GetNationality
|
|
|
|
(
|
|
|
|
"nationality",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Get the nationality of an actor. Return values are ger, it, usa, uk, ussr and unset.",
|
|
|
|
EV_GETTER
|
|
|
|
);
|
|
|
|
Event EV_Actor_WriteStats
|
|
|
|
(
|
|
|
|
"writestats",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Used internally to write stats to a CSV file.",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
Event EV_Actor_CuriousOff
|
|
|
|
(
|
|
|
|
"curiousoff",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Turn off an actor's curious state",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
|
|
|
Event EV_Actor_CuriousOn
|
|
|
|
(
|
|
|
|
"curiouson",
|
|
|
|
EV_DEFAULT,
|
|
|
|
NULL,
|
|
|
|
NULL,
|
|
|
|
"Turn on an actor's curious state",
|
|
|
|
EV_NORMAL
|
|
|
|
);
|
2024-09-01 20:04:02 +02:00
|
|
|
//====
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
CLASS_DECLARATION(SimpleActor, Actor, "Actor") {
|
2023-10-16 00:29:41 +02:00
|
|
|
{&EV_Entity_Start, &Actor::EventStart },
|
|
|
|
{&EV_Actor_MoveTo, &Actor::MoveTo },
|
|
|
|
{&EV_Actor_WalkTo, &Actor::WalkTo },
|
|
|
|
{&EV_Actor_RunTo, &Actor::RunTo },
|
|
|
|
{&EV_Actor_CrouchTo, &Actor::CrouchTo },
|
|
|
|
{&EV_Actor_CrawlTo, &Actor::CrawlTo },
|
|
|
|
{&EV_Actor_AimAt, &Actor::AimAt },
|
|
|
|
{&EV_Pain, &Actor::EventPain },
|
|
|
|
{&EV_Killed, &Actor::EventKilled },
|
|
|
|
{&EV_Actor_DeathEmbalm, &Actor::DeathEmbalm },
|
|
|
|
{&EV_Actor_Anim, &Actor::PlayAnimation },
|
|
|
|
{&EV_Actor_AnimLoop, &Actor::PlayAnimation },
|
|
|
|
{&EV_Actor_Anim_Scripted, &Actor::PlayScriptedAnimation },
|
|
|
|
{&EV_Actor_Anim_Noclip, &Actor::PlayNoclipAnimation },
|
|
|
|
{&EV_Actor_Anim_Attached, &Actor::PlayAttachedAnimation },
|
|
|
|
{&EV_Actor_AnimScript, &Actor::EventAnimScript },
|
|
|
|
{&EV_Actor_AnimScript_Scripted, &Actor::EventAnimScript_Scripted },
|
|
|
|
{&EV_Actor_AnimScript_Noclip, &Actor::EventAnimScript_Noclip },
|
2024-09-01 20:04:02 +02:00
|
|
|
// Added in 2.0
|
|
|
|
//====
|
2023-10-16 00:29:41 +02:00
|
|
|
{&EV_Actor_AnimScript_Attached, &Actor::EventAnimScript_Attached },
|
2024-09-01 20:04:02 +02:00
|
|
|
//====
|
2023-10-16 00:29:41 +02:00
|
|
|
{&EV_Actor_Reload_mg42, &Actor::EventReload_mg42 },
|
|
|
|
{&EV_Actor_Dumb, &Actor::Dumb },
|
|
|
|
{&EV_Actor_Physics_On, &Actor::PhysicsOn },
|
|
|
|
{&EV_Actor_Physics_Off, &Actor::PhysicsOff },
|
|
|
|
{&EV_Actor_SetAnim, &Actor::EventSetAnim },
|
|
|
|
{&EV_Actor_SetAnimLength, &SimpleActor::EventSetAnimLength },
|
|
|
|
{&EV_Actor_EndActionAnim, &Actor::EventEndActionAnim },
|
|
|
|
{&EV_Actor_SetMotionAnim, &Actor::EventSetMotionAnim },
|
|
|
|
{&EV_Actor_SetAimMotionAnim, &Actor::EventSetAimMotionAnim },
|
|
|
|
{&EV_Actor_SetActionAnim, &Actor::EventSetActionAnim },
|
|
|
|
{&EV_Actor_UpperAnim, &Actor::EventUpperAnim },
|
|
|
|
{&EV_Actor_SetUpperAnim, &Actor::EventSetUpperAnim },
|
|
|
|
{&EV_Actor_SetCrossblendTime, &SimpleActor::EventSetCrossblendTime },
|
|
|
|
{&EV_Actor_GetCrossblendTime, &SimpleActor::EventGetCrossblendTime },
|
|
|
|
{&EV_Actor_GetPosition, &SimpleActor::EventGetPosition },
|
|
|
|
{&EV_Actor_SetPosition, &SimpleActor::EventSetPosition },
|
|
|
|
{&EV_Actor_SetEmotion, &SimpleActor::EventSetEmotion },
|
|
|
|
{&EV_Actor_SetAnimFinal, &SimpleActor::EventSetAnimFinal },
|
|
|
|
{&EV_Actor_GetWeaponType, &SimpleActor::EventGetWeaponType },
|
|
|
|
{&EV_Actor_GetWeaponGroup, &SimpleActor::EventGetWeaponGroup },
|
|
|
|
{&EV_Actor_LookAt, &Actor::EventLookAt },
|
|
|
|
{&EV_Actor_EyesLookAt, &Actor::EventEyesLookAt },
|
|
|
|
{&EV_Actor_PointAt, &Actor::EventPointAt },
|
|
|
|
{&EV_Actor_TurnTo, &Actor::EventTurnTo },
|
|
|
|
{&EV_Actor_SetTurnDoneError, &Actor::EventSetTurnDoneError },
|
|
|
|
{&EV_Actor_SetTurnDoneError2, &Actor::EventSetTurnDoneError },
|
|
|
|
{&EV_Actor_GetTurnDoneError, &Actor::EventGetTurnDoneError },
|
|
|
|
{&EV_Actor_IdleSayAnim, &Actor::EventIdleSayAnim },
|
|
|
|
{&EV_Actor_SayAnim, &Actor::EventSayAnim },
|
|
|
|
{&EV_Actor_SetSayAnim, &Actor::EventSetSayAnim },
|
|
|
|
{&EV_Sentient_UseItem, &Actor::EventGiveWeapon },
|
|
|
|
{&EV_Sentient_GiveWeapon, &Actor::EventGiveWeapon },
|
|
|
|
{&EV_Actor_SetWeapon, &Actor::EventGiveWeapon },
|
|
|
|
{&EV_Actor_GetWeapon, &Actor::EventGetWeapon },
|
|
|
|
{&EV_Actor_SetGun, &Actor::EventGiveWeapon },
|
|
|
|
{&EV_Actor_SetGun2, &Actor::EventGiveWeapon },
|
|
|
|
{&EV_Actor_GetGun, &Actor::EventGetWeapon },
|
|
|
|
{&EV_Actor_WeaponInternal, &Actor::EventGiveWeaponInternal },
|
|
|
|
{&EV_Actor_DamagePuff, &Actor::EventDamagePuff },
|
|
|
|
{&EV_Actor_SetAngleYawSpeed, &Actor::EventSetAngleYawSpeed },
|
|
|
|
{&EV_Actor_SetAngleYawSpeed2, &Actor::EventSetAngleYawSpeed },
|
|
|
|
{&EV_Actor_GetAngleYawSpeed, &Actor::EventGetAngleYawSpeed },
|
|
|
|
{&EV_Actor_SetAimTarget, &Actor::EventSetAimTarget },
|
|
|
|
{&EV_Actor_ReadyToFire, &Actor::ReadyToFire },
|
|
|
|
{&EV_Actor_AIOn, &SimpleActor::EventAIOn },
|
|
|
|
{&EV_Actor_AIOff, &SimpleActor::EventAIOff },
|
|
|
|
{&EV_DeathSinkStart, &Actor::DeathSinkStart },
|
|
|
|
{&EV_Actor_GetSight, &Actor::EventGetSight },
|
|
|
|
{&EV_Actor_SetSight, &Actor::EventSetSight },
|
|
|
|
{&EV_Actor_SetSight2, &Actor::EventSetSight },
|
|
|
|
{&EV_Actor_GetHearing, &Actor::EventGetHearing },
|
|
|
|
{&EV_Actor_SetHearing, &Actor::EventSetHearing },
|
|
|
|
{&EV_Actor_SetHearing2, &Actor::EventSetHearing },
|
|
|
|
{&EV_Actor_SetFov, &Actor::EventSetFov },
|
|
|
|
{&EV_Actor_SetFov2, &Actor::EventSetFov },
|
|
|
|
{&EV_Actor_GetFov, &Actor::EventGetFov },
|
|
|
|
{&EV_Actor_DistToEnemy, &Actor::EventDistToEnemy },
|
|
|
|
{&EV_Actor_SetPatrolPath, &Actor::EventSetPatrolPath },
|
|
|
|
{&EV_Actor_SetPatrolPath2, &Actor::EventSetPatrolPath },
|
|
|
|
{&EV_Actor_GetPatrolPath, &Actor::EventGetPatrolPath },
|
|
|
|
{&EV_Actor_SetPatrolWaitTrigger, &Actor::EventSetPatrolWaitTrigger },
|
|
|
|
{&EV_Actor_SetPatrolWaitTrigger2, &Actor::EventSetPatrolWaitTrigger },
|
|
|
|
{&EV_Actor_GetPatrolWaitTrigger, &Actor::EventGetPatrolWaitTrigger },
|
|
|
|
{&EV_Actor_SetAccuracy, &Actor::EventSetAccuracy },
|
|
|
|
{&EV_Actor_SetAccuracy2, &Actor::EventSetAccuracy },
|
|
|
|
{&EV_Actor_GetAccuracy, &Actor::EventGetAccuracy },
|
|
|
|
{&EV_Actor_SetTypeIdle, &Actor::EventSetTypeIdle },
|
|
|
|
{&EV_Actor_SetTypeIdle2, &Actor::EventSetTypeIdle },
|
|
|
|
{&EV_Actor_GetTypeIdle, &Actor::EventGetTypeIdle },
|
|
|
|
{&EV_Actor_SetTypeAttack, &Actor::EventSetTypeAttack },
|
|
|
|
{&EV_Actor_SetTypeAttack2, &Actor::EventSetTypeAttack },
|
|
|
|
{&EV_Actor_GetTypeAttack, &Actor::EventGetTypeAttack },
|
|
|
|
{&EV_Actor_SetTypeDisguise, &Actor::EventSetTypeDisguise },
|
|
|
|
{&EV_Actor_SetTypeDisguise2, &Actor::EventSetTypeDisguise },
|
|
|
|
{&EV_Actor_GetTypeDisguise, &Actor::EventGetTypeDisguise },
|
|
|
|
{&EV_Actor_SetDisguiseLevel, &Actor::EventSetDisguiseLevel },
|
|
|
|
{&EV_Actor_SetDisguiseLevel2, &Actor::EventSetDisguiseLevel },
|
|
|
|
{&EV_Actor_GetDisguiseLevel, &Actor::EventGetDisguiseLevel },
|
|
|
|
{&EV_Actor_SetTypeGrenade, &Actor::EventSetTypeGrenade },
|
|
|
|
{&EV_Actor_SetTypeGrenade2, &Actor::EventSetTypeGrenade },
|
|
|
|
{&EV_Actor_GetTypeGrenade, &Actor::EventGetTypeGrenade },
|
|
|
|
{&EV_Actor_SetMinDistance, &Actor::EventSetMinDistance },
|
|
|
|
{&EV_Actor_SetMinDistance2, &Actor::EventSetMinDistance },
|
|
|
|
{&EV_Actor_GetMinDistance, &Actor::EventGetMinDistance },
|
|
|
|
{&EV_Actor_SetMaxDistance, &Actor::EventSetMaxDistance },
|
|
|
|
{&EV_Actor_SetMaxDistance2, &Actor::EventSetMaxDistance },
|
|
|
|
{&EV_Actor_GetMaxDistance, &Actor::EventGetMaxDistance },
|
|
|
|
{&EV_Actor_GetLeash, &Actor::EventGetLeash },
|
|
|
|
{&EV_Actor_SetLeash, &Actor::EventSetLeash },
|
|
|
|
{&EV_Actor_SetLeash2, &Actor::EventSetLeash },
|
|
|
|
{&EV_Actor_GetInterval, &Actor::EventGetInterval },
|
|
|
|
{&EV_Actor_SetInterval, &Actor::EventSetInterval },
|
|
|
|
{&EV_Actor_SetInterval2, &Actor::EventSetInterval },
|
|
|
|
{&EV_Actor_GetRunAnim, &Actor::EventGetRunAnim },
|
|
|
|
{&EV_Actor_GetWalkAnim, &Actor::EventGetWalkAnim },
|
|
|
|
{&EV_Actor_GetAnimName, &Actor::EventGetAnimName },
|
|
|
|
{&EV_Actor_SetAnimName, &Actor::EventSetAnimName },
|
|
|
|
{&EV_Actor_SetDisguiseRange, &Actor::EventSetDisguiseRange },
|
|
|
|
{&EV_Actor_SetDisguiseRange2, &Actor::EventSetDisguiseRange },
|
|
|
|
{&EV_Actor_GetDisguiseRange, &Actor::EventGetDisguiseRange },
|
|
|
|
{&EV_Actor_SetDisguisePeriod, &Actor::EventSetDisguisePeriod },
|
|
|
|
{&EV_Actor_SetDisguisePeriod2, &Actor::EventSetDisguisePeriod },
|
|
|
|
{&EV_Actor_GetDisguisePeriod, &Actor::EventGetDisguisePeriod },
|
|
|
|
{&EV_Actor_SetDisguiseAcceptThread, &Actor::EventSetDisguiseAcceptThread },
|
|
|
|
{&EV_Actor_SetDisguiseAcceptThread2, &Actor::EventSetDisguiseAcceptThread },
|
|
|
|
{&EV_Actor_GetDisguiseAcceptThread, &Actor::EventGetDisguiseAcceptThread },
|
|
|
|
{&EV_Actor_AttackPlayer, &Actor::EventAttackPlayer },
|
|
|
|
{&EV_Actor_SetAlarmNode, &Actor::EventSetAlarmNode },
|
|
|
|
{&EV_Actor_SetAlarmNode2, &Actor::EventSetAlarmNode },
|
|
|
|
{&EV_Actor_GetAlarmNode, &Actor::EventGetAlarmNode },
|
2024-09-01 20:04:02 +02:00
|
|
|
// Added in 2.30
|
|
|
|
//====
|
2023-10-16 00:29:41 +02:00
|
|
|
{&EV_Actor_SetPreAlarmThread, &Actor::EventSetPreAlarmThread },
|
|
|
|
{&EV_Actor_SetPreAlarmThread2, &Actor::EventSetPreAlarmThread },
|
2024-09-01 20:04:02 +02:00
|
|
|
//====
|
2023-10-16 00:29:41 +02:00
|
|
|
{&EV_Actor_SetAlarmThread, &Actor::EventSetAlarmThread },
|
|
|
|
{&EV_Actor_SetAlarmThread2, &Actor::EventSetAlarmThread },
|
|
|
|
{&EV_Actor_GetAlarmThread, &Actor::EventGetAlarmThread },
|
|
|
|
{&EV_Actor_SetSoundAwareness, &Actor::EventSetSoundAwareness },
|
|
|
|
{&EV_Actor_SetSoundAwareness2, &Actor::EventSetSoundAwareness },
|
|
|
|
{&EV_Actor_GetSoundAwareness, &Actor::EventGetSoundAwareness },
|
|
|
|
{&EV_Actor_SetGrenadeAwareness, &Actor::EventSetGrenadeAwareness },
|
|
|
|
{&EV_Actor_SetGrenadeAwareness2, &Actor::EventSetGrenadeAwareness },
|
|
|
|
{&EV_Actor_GetGrenadeAwareness, &Actor::EventGetGrenadeAwareness },
|
|
|
|
{&EV_Actor_SetTurret, &Actor::EventSetTurret },
|
|
|
|
{&EV_Actor_SetTurret2, &Actor::EventSetTurret },
|
|
|
|
{&EV_Actor_GetTurret, &Actor::EventGetTurret },
|
|
|
|
{&EV_Actor_AttachGrenade, &Actor::Grenade_EventAttach },
|
|
|
|
{&EV_Actor_DetachGrenade, &Actor::Grenade_EventDetach },
|
|
|
|
{&EV_Actor_FireGrenade, &Actor::Grenade_EventFire },
|
|
|
|
{&EV_Actor_EnableEnemy, &Actor::EventEnableEnemy },
|
|
|
|
{&EV_Actor_EnablePain, &Actor::EventEnablePain },
|
|
|
|
{&EV_Activate, &Actor::EventActivate },
|
|
|
|
{&EV_Actor_GetAmmoGrenade, &Actor::EventGetAmmoGrenade },
|
|
|
|
{&EV_Actor_SetAmmoGrenade, &Actor::EventSetAmmoGrenade },
|
|
|
|
{&EV_Actor_SetAmmoGrenade2, &Actor::EventSetAmmoGrenade },
|
|
|
|
{&EV_Actor_GetMood, &Actor::EventGetMood },
|
|
|
|
{&EV_Actor_SetMood, &Actor::EventSetMood },
|
|
|
|
{&EV_Actor_ShareEnemy, &Actor::EventShareEnemy },
|
|
|
|
{&EV_Actor_ShareGrenade, &Actor::EventShareGrenade },
|
|
|
|
{&EV_Actor_InterruptPoint, &Actor::EventInterruptPoint },
|
2024-09-01 20:04:02 +02:00
|
|
|
// Added in 2.0
|
|
|
|
//====
|
2023-10-16 00:29:41 +02:00
|
|
|
{&EV_Actor_GetVisibilityThreshold, &Actor::EventGetVisibilityThreshold },
|
|
|
|
{&EV_Actor_SetVisibilityThreshold, &Actor::EventSetVisibilityThreshold },
|
|
|
|
{&EV_Actor_SetVisibilityThreshold2, &Actor::EventSetVisibilityThreshold },
|
|
|
|
{&EV_Actor_SetDefaultVisibilityThreshold, &Actor::EventSetDefaultVisibilityThreshold},
|
|
|
|
{&EV_Actor_GetSuppressChance, &Actor::EventGetSuppressChance },
|
|
|
|
{&EV_Actor_SetSuppressChance, &Actor::EventSetSuppressChance },
|
|
|
|
{&EV_Actor_SetSuppressChance2, &Actor::EventSetSuppressChance },
|
2024-09-01 20:04:02 +02:00
|
|
|
//====
|
2023-10-16 00:29:41 +02:00
|
|
|
{&EV_Actor_GetPainHandler, &Actor::EventGetPainHandler },
|
|
|
|
{&EV_Actor_SetPainHandler, &Actor::EventSetPainHandler },
|
|
|
|
{&EV_Actor_GetDeathHandler, &Actor::EventGetDeathHandler },
|
|
|
|
{&EV_Actor_SetDeathHandler, &Actor::EventSetDeathHandler },
|
|
|
|
{&EV_Actor_GetAttackHandler, &Actor::EventGetAttackHandler },
|
|
|
|
{&EV_Actor_SetAttackHandler, &Actor::EventSetAttackHandler },
|
|
|
|
{&EV_Actor_SetHeadModel, &Actor::EventSetHeadModel },
|
|
|
|
{&EV_Actor_GetHeadModel, &Actor::EventGetHeadModel },
|
|
|
|
{&EV_Actor_SetHeadSkin, &Actor::EventSetHeadSkin },
|
|
|
|
{&EV_Actor_GetHeadSkin, &Actor::EventGetHeadSkin },
|
|
|
|
{&EV_Actor_SetNoIdle, &Actor::EventSetNoIdle },
|
|
|
|
{&EV_Actor_GetNoIdle, &Actor::EventGetNoIdle },
|
|
|
|
{&EV_Actor_GetEnemy, &Actor::EventGetEnemy },
|
|
|
|
{&EV_Actor_GetMaxNoticeTimeScale, &Actor::EventGetMaxNoticeTimeScale },
|
|
|
|
{&EV_Actor_SetMaxNoticeTimeScale, &Actor::EventSetMaxNoticeTimeScale },
|
|
|
|
{&EV_Actor_SetMaxNoticeTimeScale2, &Actor::EventSetMaxNoticeTimeScale },
|
|
|
|
{&EV_Actor_GetFixedLeash, &Actor::EventGetFixedLeash },
|
|
|
|
{&EV_Actor_SetFixedLeash, &Actor::EventSetFixedLeash },
|
|
|
|
{&EV_Actor_SetFixedLeash2, &Actor::EventSetFixedLeash },
|
|
|
|
{&EV_Actor_Holster, &Actor::EventHolster },
|
|
|
|
{&EV_Actor_Unholster, &Actor::EventUnholster },
|
|
|
|
{&EV_SoundDone, &Actor::EventSoundDone },
|
|
|
|
{&EV_Sound, &Actor::EventSound },
|
|
|
|
{&EV_Actor_IsEnemyVisible, &Actor::EventIsEnemyVisible },
|
|
|
|
{&EV_Actor_GetEnemyVisibleChangeTime, &Actor::EventGetEnemyVisibleChangeTime },
|
|
|
|
{&EV_Actor_GetLastEnemyVisibleTime, &Actor::EventGetLastEnemyVisibleTime },
|
|
|
|
{&EV_Actor_SetFallHeight, &Actor::EventSetFallHeight },
|
|
|
|
{&EV_Actor_GetFallHeight, &Actor::EventGetFallHeight },
|
|
|
|
{&EV_Actor_CanMoveTo, &Actor::EventCanMoveTo },
|
|
|
|
{&EV_Actor_MoveDir, &Actor::EventMoveDir },
|
|
|
|
{&EV_Actor_IntervalDir, &Actor::EventIntervalDir },
|
|
|
|
{&EV_Actor_ResetLeash, &Actor::EventResetLeash },
|
|
|
|
{&EV_Actor_Tether, &Actor::EventTether },
|
|
|
|
{&EV_Actor_GetThinkState, &Actor::EventGetThinkState },
|
|
|
|
{&EV_Actor_GetEnemyShareRange, &Actor::EventGetEnemyShareRange },
|
|
|
|
{&EV_Actor_SetEnemyShareRange, &Actor::EventSetEnemyShareRange },
|
|
|
|
{&EV_Actor_SetEnemyShareRange2, &Actor::EventSetEnemyShareRange },
|
|
|
|
{&EV_Actor_GetVoiceType, &Actor::GetVoiceType },
|
|
|
|
{&EV_Actor_SetVoiceType, &Actor::SetVoiceType },
|
|
|
|
{&EV_Actor_SetVoiceType2, &Actor::SetVoiceType },
|
|
|
|
{&EV_Remove, &Actor::Remove },
|
|
|
|
{&EV_Delete, &Actor::Remove },
|
|
|
|
{&EV_ScriptRemove, &Actor::Remove },
|
|
|
|
{&EV_Actor_KickDir, &Actor::EventGetKickDir },
|
|
|
|
{&EV_Actor_GetNoLongPain, &Actor::EventGetNoLongPain },
|
|
|
|
{&EV_Actor_SetNoLongPain, &Actor::EventSetNoLongPain },
|
|
|
|
{&EV_Actor_SetNoLongPain2, &Actor::EventSetNoLongPain },
|
|
|
|
{&EV_Actor_GetFavoriteEnemy, &Actor::EventGetFavoriteEnemy },
|
|
|
|
{&EV_Actor_SetFavoriteEnemy, &Actor::EventSetFavoriteEnemy },
|
|
|
|
{&EV_Actor_SetFavoriteEnemy2, &Actor::EventSetFavoriteEnemy },
|
|
|
|
{&EV_Actor_GetMumble, &Actor::EventGetMumble },
|
|
|
|
{&EV_Actor_SetMumble, &Actor::EventSetMumble },
|
|
|
|
{&EV_Actor_SetMumble2, &Actor::EventSetMumble },
|
2024-09-01 20:04:02 +02:00
|
|
|
// Removed in 2.0
|
|
|
|
//====
|
|
|
|
//{&EV_Actor_GetBreathSteam, &Actor::EventGetBreathSteam },
|
|
|
|
//{&EV_Actor_SetBreathSteam, &Actor::EventSetBreathSteam },
|
|
|
|
//{&EV_Actor_SetBreathSteam2, &Actor::EventSetBreathSteam },
|
|
|
|
//====
|
2023-10-16 00:29:41 +02:00
|
|
|
{&EV_Actor_CalcGrenadeToss, &Actor::EventCalcGrenadeToss },
|
|
|
|
{&EV_Actor_CalcGrenadeToss2, &Actor::EventCalcGrenadeToss },
|
|
|
|
{&EV_Actor_GetNoSurprise, &Actor::EventGetNoSurprise },
|
|
|
|
{&EV_Actor_SetNoSurprise, &Actor::EventSetNoSurprise },
|
|
|
|
{&EV_Actor_SetNoSurprise2, &Actor::EventSetNoSurprise },
|
|
|
|
{&EV_Actor_GetSilent, &Actor::EventGetSilent },
|
|
|
|
{&EV_Actor_SetSilent, &Actor::EventSetSilent },
|
|
|
|
{&EV_Actor_SetSilent2, &Actor::EventSetSilent },
|
|
|
|
{&EV_Actor_GetAvoidPlayer, &Actor::EventGetAvoidPlayer },
|
|
|
|
{&EV_Actor_SetAvoidPlayer, &Actor::EventSetAvoidPlayer },
|
|
|
|
{&EV_Actor_SetAvoidPlayer2, &Actor::EventSetAvoidPlayer },
|
|
|
|
{&EV_Actor_SetMoveDoneRadius, &Actor::EventSetMoveDoneRadius },
|
|
|
|
{&EV_Actor_GetMoveDoneRadius, &Actor::EventGetMoveDoneRadius },
|
|
|
|
{&EV_Actor_BeDead, &Actor::EventBeDead },
|
|
|
|
{&EV_Actor_GetLookAroundAngle, &Actor::EventGetLookAroundAngle },
|
|
|
|
{&EV_Actor_SetLookAroundAngle, &Actor::EventSetLookAroundAngle },
|
|
|
|
{&EV_Actor_SetLookAroundAngle2, &Actor::EventSetLookAroundAngle },
|
|
|
|
{&EV_Actor_HasCompleteLookahead, &Actor::EventHasCompleteLookahead },
|
|
|
|
{&EV_Actor_PathDist, &Actor::EventPathDist },
|
|
|
|
{&EV_Actor_CanShootEnemyFrom, &Actor::EventCanShootEnemyFrom },
|
|
|
|
{&EV_Actor_CanShoot, &Actor::EventCanShoot },
|
|
|
|
{&EV_Actor_GetInReload, &Actor::EventGetInReload },
|
|
|
|
{&EV_Actor_SetInReload, &Actor::EventSetInReload },
|
|
|
|
{&EV_Actor_SetReloadCover, &Actor::EventSetReloadCover },
|
|
|
|
{&EV_Actor_BreakSpecial, &Actor::EventBreakSpecial },
|
|
|
|
{&EV_Actor_SetBalconyHeight, &Actor::EventSetBalconyHeight },
|
|
|
|
{&EV_Actor_SetBalconyHeight2, &Actor::EventSetBalconyHeight },
|
|
|
|
{&EV_Actor_GetBalconyHeight, &Actor::EventGetBalconyHeight },
|
2024-09-01 20:04:02 +02:00
|
|
|
// Removed in 2.0
|
|
|
|
//====
|
|
|
|
//{&EV_CanSee, &Actor::CanSee },
|
|
|
|
//====
|
|
|
|
// Added in 2.0
|
|
|
|
//====
|
2023-10-16 00:29:41 +02:00
|
|
|
{&EV_Actor_SetIgnoreBadPlace, &Actor::EventSetIgnoreBadPlace },
|
|
|
|
{&EV_Actor_SetIgnoreBadPlace2, &Actor::EventSetIgnoreBadPlace },
|
|
|
|
{&EV_Actor_GetIgnoreBadPlace, &Actor::EventGetIgnoreBadPlace },
|
|
|
|
{&EV_Actor_FindEnemy, &Actor::EventFindEnemy },
|
|
|
|
{&EV_Actor_EnableEnemySwitch, &Actor::EventEnableEnemySwitch },
|
|
|
|
{&EV_Actor_DisableEnemySwitch, &Actor::EventDisableEnemySwitch },
|
|
|
|
{&EV_Actor_SetRunAnimRate, &Actor::EventSetRunAnimRate },
|
|
|
|
{&EV_Actor_SetRunAnimRate2, &Actor::EventSetRunAnimRate },
|
|
|
|
{&EV_Actor_GetRunAnimRate, &Actor::EventGetRunAnimRate },
|
2024-09-01 20:04:02 +02:00
|
|
|
//====
|
|
|
|
// Added in 2.30
|
|
|
|
//====
|
2023-10-16 00:29:41 +02:00
|
|
|
{&EV_Stop, &Actor::Landed },
|
|
|
|
{&EV_Actor_SetNationality, &Actor::SetNationality },
|
|
|
|
{&EV_Actor_SetNationality2, &Actor::SetNationality },
|
|
|
|
{&EV_Actor_GetNationality, &Actor::GetNationality },
|
|
|
|
{&EV_Actor_WriteStats, &Actor::EventWriteStats },
|
|
|
|
{&EV_Actor_CuriousOff, &Actor::EventCuriousOff },
|
|
|
|
{&EV_Actor_CuriousOn, &Actor::EventCuriousOn },
|
2024-09-01 20:04:02 +02:00
|
|
|
//====
|
2023-10-16 00:29:41 +02:00
|
|
|
{NULL, NULL }
|
2016-03-27 11:49:47 +02:00
|
|
|
};
|
|
|
|
|
2019-06-29 23:43:30 +02:00
|
|
|
Actor::GlobalFuncs_t Actor::GlobalFuncs[NUM_THINKS];
|
2023-10-12 18:19:22 +02:00
|
|
|
const_str Actor::m_csThinkNames[NUM_THINKS] = {
|
2023-10-11 22:49:06 +02:00
|
|
|
STRING_VOID,
|
|
|
|
STRING_TURRET,
|
|
|
|
STRING_COVER,
|
|
|
|
STRING_PATROL,
|
|
|
|
STRING_RUNNER,
|
|
|
|
STRING_PAIN,
|
|
|
|
STRING_KILLED,
|
|
|
|
STRING_MOVETO,
|
|
|
|
STRING_IDLE,
|
|
|
|
STRING_CURIOUS,
|
|
|
|
STRING_DISGUISE_SALUTE,
|
|
|
|
STRING_DISGUISE_SENTRY,
|
|
|
|
STRING_DISGUISE_OFFICER,
|
|
|
|
STRING_DISGUISE_ROVER,
|
|
|
|
STRING_DISGUISE_NONE,
|
|
|
|
STRING_ALARM,
|
|
|
|
STRING_GRENADE,
|
|
|
|
STRING_MACHINEGUNNER,
|
|
|
|
STRING_DOG_IDLE,
|
|
|
|
STRING_DOG_ATTACK,
|
|
|
|
STRING_DOG_CURIOUS,
|
|
|
|
STRING_DOG_GRENADE,
|
|
|
|
STRING_ANIM,
|
|
|
|
STRING_ANIM_CURIOUS,
|
|
|
|
STRING_AIM,
|
|
|
|
STRING_BALCONY_IDLE,
|
|
|
|
STRING_BALCONY_CURIOUS,
|
|
|
|
STRING_BALCONY_ATTACK,
|
|
|
|
STRING_BALCONY_DISGUISE,
|
|
|
|
STRING_BALCONY_GRENADE,
|
|
|
|
STRING_BALCONY_PAIN,
|
|
|
|
STRING_BALCONY_KILLED,
|
|
|
|
STRING_WEAPONLESS,
|
|
|
|
STRING_NOCLIP,
|
2024-02-17 20:10:00 +01:00
|
|
|
STRING_DEAD,
|
|
|
|
// Added in 2.0
|
|
|
|
STRING_BADPLACE,
|
|
|
|
// Added in 2.30
|
|
|
|
STRING_RUNANDSHOOT
|
|
|
|
};
|
2023-10-12 18:19:22 +02:00
|
|
|
const_str Actor::m_csThinkStateNames[NUM_THINKSTATES] = {
|
2023-10-11 22:49:06 +02:00
|
|
|
STRING_VOID,
|
|
|
|
STRING_IDLE,
|
|
|
|
STRING_PAIN,
|
|
|
|
STRING_KILLED,
|
|
|
|
STRING_ATTACK,
|
|
|
|
STRING_CURIOUS,
|
|
|
|
STRING_DISGUISE,
|
|
|
|
STRING_GRENADE,
|
2024-02-17 20:10:00 +01:00
|
|
|
STRING_BADPLACE, // Added in 2.0
|
|
|
|
STRING_NOCLIP
|
|
|
|
};
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
SafePtr<Actor> Actor::mBodyQueue[MAX_BODYQUEUE];
|
|
|
|
int Actor::mCurBody;
|
2018-09-17 23:50:38 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::Actor
|
|
|
|
|
|
|
|
Constructor
|
|
|
|
===============
|
|
|
|
*/
|
2016-03-27 11:49:47 +02:00
|
|
|
Actor::Actor()
|
2023-10-12 19:42:20 +02:00
|
|
|
: mVoiceType(-1)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-11-16 23:11:48 +01:00
|
|
|
entflags |= ECF_ACTOR;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 19:42:20 +02:00
|
|
|
m_pszDebugState = "";
|
2023-10-16 00:29:41 +02:00
|
|
|
m_pFallPath = NULL;
|
|
|
|
m_iOriginTime = -1;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (LoadingSavegame) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_PainState = 500;
|
2023-10-12 19:42:20 +02:00
|
|
|
m_iEnemyShowPapersTime = 0;
|
2023-10-16 00:29:41 +02:00
|
|
|
m_eGrenadeState = eGrenadeState::AI_GRENSTATE_FLEE;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
edict->s.eType = ET_MODELANIM;
|
|
|
|
edict->r.svFlags |= SVF_MONSTER;
|
|
|
|
edict->r.ownerNum = ENTITYNUM_NONE;
|
2023-10-12 18:19:22 +02:00
|
|
|
edict->clipmask = MASK_MONSTERSOLID;
|
|
|
|
setMoveType(MOVETYPE_WALK);
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
mass = 175;
|
|
|
|
flags |= FL_THINK;
|
|
|
|
flags &= ~FL_ANIMATE;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
setContentsSolid();
|
2023-10-12 18:19:22 +02:00
|
|
|
setSolidType(SOLID_BBOX);
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_fFov = 90.0f;
|
|
|
|
takedamage = DAMAGE_AIM;
|
|
|
|
m_fFovDot = cos(DEG2RAD(m_fFov / 2.0));
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-14 14:10:16 +02:00
|
|
|
m_eAnimMode = ANIM_MODE_NONE;
|
2023-10-11 22:49:06 +02:00
|
|
|
Anim_Emotion(EMOTION_NONE);
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_bDoPhysics = true;
|
|
|
|
path_failed_time = 0;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
health = 100;
|
|
|
|
max_health = 100;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
m_fAngleYawSpeed = 360;
|
|
|
|
m_fHeadMaxTurnSpeed = 520;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bHeadAnglesAchieved = true;
|
2023-10-12 18:19:22 +02:00
|
|
|
VectorClear(m_vHeadDesiredAngles);
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
m_fLUpperArmTurnSpeed = 360;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bLUpperArmAnglesAchieved = true;
|
2023-10-12 18:19:22 +02:00
|
|
|
VectorClear(m_vLUpperArmDesiredAngles);
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
m_fTorsoMaxTurnSpeed = 120;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fTorsoCurrentTurnSpeed = 0;
|
2023-10-12 18:19:22 +02:00
|
|
|
m_bTorsoAnglesAchieved = true;
|
|
|
|
VectorClear(m_vTorsoDesiredAngles);
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
m_pLookEntity = NULL;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_pPointEntity = NULL;
|
2023-10-12 18:19:22 +02:00
|
|
|
m_pTurnEntity = NULL;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
VectorClear(edict->s.eyeVector);
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
m_bDoAI = true;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bTurretNoInitialCover = false;
|
2023-10-12 18:19:22 +02:00
|
|
|
m_bThink = false;
|
2023-10-12 19:42:20 +02:00
|
|
|
m_fSight = world->m_fAIVisionDistance;
|
2023-10-12 18:19:22 +02:00
|
|
|
m_fHearing = 2048;
|
|
|
|
m_PainTime = 0;
|
|
|
|
m_bNoLongPain = false;
|
|
|
|
hit_obstacle_time = 0;
|
|
|
|
VectorClear2D(obstacle_vel);
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_bLockThinkState = false;
|
|
|
|
m_bAutoAvoidPlayer = true;
|
|
|
|
m_bIsCurious = true;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
InitThinkStates();
|
2023-10-15 20:52:06 +02:00
|
|
|
SetThinkState(THINKSTATE_IDLE, THINKLEVEL_IDLE);
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
m_fMinDistance = 128;
|
2023-10-12 19:42:20 +02:00
|
|
|
m_fMinDistanceSquared = Square(m_fMinDistance);
|
2023-10-12 18:19:22 +02:00
|
|
|
m_fMaxDistance = 1024;
|
2024-02-14 19:22:19 +01:00
|
|
|
m_fMaxDistanceSquared = Square(m_fMaxDistance);
|
2023-10-12 18:19:22 +02:00
|
|
|
m_fLeash = 512;
|
2024-02-13 16:42:54 +01:00
|
|
|
m_fLeashSquared = Square(m_fLeash);
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_iEyeUpdateTime = level.inttime;
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_iEyeUpdateTime < 1000) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iEyeUpdateTime = 1000;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iEyeUpdateTime += rand() % 100 + 100;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_vIntervalDir = vec_zero;
|
|
|
|
m_iIntervalDirTime = 0;
|
|
|
|
edict->r.lastNetTime = -10000000;
|
|
|
|
|
2023-10-12 19:42:20 +02:00
|
|
|
m_bNewEnemy = false;
|
2023-10-12 18:19:22 +02:00
|
|
|
m_iEnemyCheckTime = 0;
|
|
|
|
m_iEnemyChangeTime = 0;
|
|
|
|
m_bEnemyIsDisguised = false;
|
|
|
|
m_bEnemyVisible = false;
|
2023-10-12 19:42:20 +02:00
|
|
|
m_iEnemyVisibleCheckTime = 0;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iEnemyVisibleChangeTime = 0;
|
2023-10-12 18:19:22 +02:00
|
|
|
m_iLastEnemyVisibleTime = 0;
|
2023-10-12 19:42:20 +02:00
|
|
|
m_fVisibilityAlpha = 0;
|
|
|
|
m_fVisibilityThreshold = 0.5f;
|
|
|
|
m_bHasVisibilityThreshold = false;
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_bEnemyInFOV = false;
|
|
|
|
m_iEnemyFovCheckTime = 0;
|
|
|
|
m_iEnemyFovChangeTime = 0;
|
|
|
|
m_iIgnoreSoundsMask = 0;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_State = -1;
|
|
|
|
m_iStateTime = 0;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
m_iGunPositionCheckTime = 0;
|
2023-10-12 19:42:20 +02:00
|
|
|
m_vLastEnemyPos = vec3_origin;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iLastEnemyPosChangeTime = 0;
|
2023-10-12 19:42:20 +02:00
|
|
|
m_vScriptGoal = vec3_origin;
|
|
|
|
m_bScriptGoalValid = false;
|
2023-10-12 18:19:22 +02:00
|
|
|
m_iNextWatchStepTime = 0;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_iCuriousTime = 0;
|
|
|
|
m_iCuriousLevel = 0;
|
2023-10-11 22:49:06 +02:00
|
|
|
SetCuriousAnimHint(0);
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_bNoSurprise = false;
|
2023-10-12 18:19:22 +02:00
|
|
|
memset(&m_pPotentialCoverNode, 0, sizeof(m_pPotentialCoverNode));
|
2023-10-16 00:29:41 +02:00
|
|
|
m_iPotentialCoverCount = 0;
|
|
|
|
m_pCoverNode = NULL;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_csSpecialAttack = STRING_NULL;
|
|
|
|
m_bNeedReload = false;
|
|
|
|
m_bInReload = false;
|
|
|
|
m_bFaceEnemy = true;
|
|
|
|
m_sCurrentPathNodeIndex = -1;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
|
|
|
m_iNextDisguiseTime = 1;
|
|
|
|
m_iDisguisePeriod = 30000;
|
2024-02-14 19:22:19 +01:00
|
|
|
m_fMaxDisguiseDistSquared = Square(256);
|
2023-10-12 19:42:20 +02:00
|
|
|
m_iDisguiseLevel = 1;
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_patrolCurrentNode = NULL;
|
|
|
|
m_csPatrolCurrentAnim = STRING_ANIM_RUN_SCR;
|
|
|
|
m_bPatrolWaitTrigger = false;
|
|
|
|
m_fInterval = 128;
|
|
|
|
m_iSquadStandTime = 0;
|
|
|
|
m_aimNode = NULL;
|
|
|
|
|
|
|
|
m_vHome = vec3_origin;
|
|
|
|
m_bFixedLeash = false;
|
|
|
|
m_pTetherEnt = NULL;
|
|
|
|
|
|
|
|
m_pGrenade = NULL;
|
|
|
|
m_vGrenadePos = vec3_origin;
|
|
|
|
m_iFirstGrenadeTime = 0;
|
|
|
|
m_bGrenadeBounced = false;
|
|
|
|
m_eGrenadeMode = AI_GREN_TOSS_NONE;
|
|
|
|
m_vGrenadeVel = vec_zero;
|
|
|
|
m_vKickDir = vec_zero;
|
|
|
|
|
|
|
|
m_fSoundAwareness = 100;
|
|
|
|
m_fGrenadeAwareness = 20;
|
|
|
|
m_fMaxNoticeTimeScale = 1.0f;
|
|
|
|
m_fNoticeTimeScale = 1.0f;
|
|
|
|
|
|
|
|
m_iCanShootCheckTime = 0;
|
|
|
|
m_bCanShootEnemy = false;
|
|
|
|
m_bEnableEnemy = true;
|
|
|
|
m_bDesiredEnableEnemy = true;
|
|
|
|
m_bEnablePain = true;
|
|
|
|
|
|
|
|
m_csAnimScript = STRING_ANIM_IDLE_SCR;
|
|
|
|
m_bAnimScriptSet = false;
|
|
|
|
m_AnimMode = ANIM_MODE_NORMAL;
|
|
|
|
m_csAnimName = STRING_EMPTY;
|
|
|
|
m_csSayAnim = STRING_EMPTY;
|
|
|
|
m_csUpperAnim = STRING_EMPTY;
|
|
|
|
|
|
|
|
m_fRunAnimRate = 1;
|
|
|
|
m_fDfwRequestedYaw = 0;
|
|
|
|
m_fDfwDerivedYaw = 0;
|
|
|
|
m_vDfwPos = vec_zero;
|
|
|
|
m_fDfwTime = 0;
|
|
|
|
|
|
|
|
m_AlarmNode = NULL;
|
|
|
|
|
|
|
|
m_iWallDodgeTimeout = 0;
|
|
|
|
m_WallDir = 0;
|
2023-10-12 19:42:20 +02:00
|
|
|
VectorClear2D(m_PrevObstacleNormal);
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_csHeadModel = STRING_EMPTY;
|
|
|
|
m_csHeadSkin = STRING_EMPTY;
|
|
|
|
m_bNoIdleAfterAnim = false;
|
|
|
|
m_csWeapon = STRING_EMPTY;
|
|
|
|
m_csLoadOut = STRING_EMPTY;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_fMaxShareDistSquared = 0;
|
|
|
|
m_iRunHomeTime = 0;
|
|
|
|
m_iSuppressChance = 50;
|
|
|
|
|
|
|
|
m_bBreathSteam = false;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fMoveDoneRadiusSquared = 0;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_bForceAttackPlayer = false;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_iLookFlags = 0;
|
|
|
|
m_iNextLookTime = 0;
|
|
|
|
m_fLookAroundFov = 45;
|
|
|
|
m_bHasDesiredLookDest = false;
|
|
|
|
m_bHasDesiredLookAngles = false;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_eDontFaceWallMode = 0;
|
|
|
|
m_iLastFaceDecideTime = 0;
|
|
|
|
m_iOriginTime = -1;
|
|
|
|
m_fTurnDoneError = 0;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_fBalconyHeight = 128;
|
|
|
|
m_bNoPlayerCollision = false;
|
2023-10-12 18:19:22 +02:00
|
|
|
for (int i = 0; i < MAX_ORIGIN_HISTORY; i++) {
|
|
|
|
VectorClear2D(m_vOriginHistory[i]);
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iCurrentHistory = 0;
|
2023-10-16 00:29:41 +02:00
|
|
|
m_bAnimating = false;
|
2023-10-12 19:42:20 +02:00
|
|
|
m_bIgnoreBadPlace = false;
|
2023-11-14 00:06:26 +01:00
|
|
|
m_iBadPlaceIndex = 0;
|
2023-10-16 00:29:41 +02:00
|
|
|
m_bBecomeRunner = false;
|
|
|
|
m_bEnemySwitch = true;
|
2023-10-17 20:38:58 +02:00
|
|
|
m_iNationality = ACTOR_NATIONALITY_DEFAULT;
|
2023-10-12 19:42:20 +02:00
|
|
|
|
|
|
|
if (g_aistats) {
|
|
|
|
PostEvent(EV_Actor_WriteStats, 1.0);
|
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
mVoiceType = -1;
|
2024-06-22 19:03:04 +02:00
|
|
|
|
|
|
|
//
|
|
|
|
// Added in OPM
|
2024-08-29 23:31:46 +02:00
|
|
|
// The variable isn't set in original
|
2024-06-22 19:03:04 +02:00
|
|
|
//
|
|
|
|
m_bSilent = false;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::~Actor
|
|
|
|
|
|
|
|
Destructor
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
Actor::~Actor()
|
|
|
|
{
|
2023-10-12 21:31:22 +02:00
|
|
|
EndStates();
|
|
|
|
ClearPatrolCurrentNode();
|
|
|
|
ClearAimNode();
|
|
|
|
ClearLookEntity();
|
|
|
|
ClearPointEntity();
|
|
|
|
ClearTurnEntity();
|
|
|
|
|
2023-11-16 23:11:48 +01:00
|
|
|
entflags &= ~ECF_ACTOR;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::setContentsSolid
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::setContentsSolid(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
setContents(CONTENTS_NOBOTCLIP);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EndStates
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EndStates(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
for (int i = 0; i < NUM_THINKLEVELS; i++) {
|
2023-10-12 23:17:09 +02:00
|
|
|
EndState(i);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::ClearStates
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ClearStates(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
for (int i = 0; i < NUM_THINKSTATES; i++) {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThink((eThinkState)i, THINK_VOID);
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::ResolveVoiceType
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ResolveVoiceType(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
char validVoice[128];
|
|
|
|
|
2023-10-14 13:30:20 +02:00
|
|
|
if (mVoiceType != -1) {
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_Team == TEAM_AMERICAN) {
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
if (gAmericanVoices[i][0] == mVoiceType) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
validVoice[0] = '\0';
|
2023-10-12 18:19:22 +02:00
|
|
|
for (int i = 0; i < 3; i++) {
|
2023-10-11 22:49:06 +02:00
|
|
|
strcat(validVoice, gAmericanVoices[i]);
|
|
|
|
strcat(validVoice, " ");
|
|
|
|
}
|
|
|
|
Com_Printf("ERROR: Bad voice type %c. Valid American voicetypes are: %s\n", mVoiceType, validVoice);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
if (gGermanVoices[i][0] == mVoiceType) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
validVoice[0] = '\0';
|
2023-10-12 18:19:22 +02:00
|
|
|
for (int i = 0; i < 3; i++) {
|
2023-10-11 22:49:06 +02:00
|
|
|
strcat(validVoice, gGermanVoices[i]);
|
|
|
|
strcat(validVoice, " ");
|
|
|
|
}
|
|
|
|
Com_Printf("ERROR: Bad voice type %c. Valid German voicetypes are: %s\n", mVoiceType, validVoice);
|
2023-10-14 13:30:20 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
mVoiceType = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mVoiceType == -1) {
|
|
|
|
int d = random() * 3.0 * 0.99;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-14 13:30:20 +02:00
|
|
|
if (m_Team == TEAM_AMERICAN) {
|
|
|
|
mVoiceType = gAmericanVoices[d][0];
|
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
mVoiceType = gGermanVoices[d][0];
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventStart
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Initialize actor.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventStart(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ResolveVoiceType();
|
2023-10-12 18:19:22 +02:00
|
|
|
setSize(MINS, MAXS); //notsure
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
droptofloor(16384);
|
2023-10-12 18:19:22 +02:00
|
|
|
|
|
|
|
SetControllerTag(HEAD_TAG, gi.Tag_NumForName(edict->tiki, "Bip01 Head"));
|
|
|
|
SetControllerTag(TORSO_TAG, gi.Tag_NumForName(edict->tiki, "Bip01"));
|
|
|
|
SetControllerTag(ARMS_TAG, gi.Tag_NumForName(edict->tiki, "Bip01 L UpperArm"));
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-14 14:08:52 +02:00
|
|
|
JoinNearbySquads(1024);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (level.Spawned()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Unregister(STRING_SPAWN);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::ClearEnemies
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ClearEnemies(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_PotentialEnemies.RemoveAll();
|
2023-10-12 18:19:22 +02:00
|
|
|
SetEnemy(NULL, false);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::SetMoveInfo
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Copies current move information to mm.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetMoveInfo(mmove_t *mm)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
memset(mm, 0, sizeof(mmove_t));
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-14 14:08:52 +02:00
|
|
|
velocity.copyTo(mm->velocity);
|
|
|
|
origin.copyTo(mm->origin);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
mm->entityNum = entnum;
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
mm->walking = m_walking;
|
2023-10-14 14:08:52 +02:00
|
|
|
mm->groundPlane = m_groundPlane;
|
|
|
|
VectorCopy(m_groundPlaneNormal, mm->groundPlaneNormal);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
mm->frametime = level.frametime;
|
|
|
|
|
2023-10-14 14:08:52 +02:00
|
|
|
if (m_bNoPlayerCollision) {
|
|
|
|
mm->tracemask = MASK_TARGETPATH;
|
|
|
|
} else {
|
|
|
|
mm->tracemask = MASK_PATHSOLID;
|
|
|
|
}
|
|
|
|
|
2023-10-14 13:31:19 +02:00
|
|
|
VectorCopy(MINS, mm->mins);
|
|
|
|
VectorCopy(MAXS, mm->maxs);
|
2023-10-14 14:08:52 +02:00
|
|
|
mm->maxs[2] = 94;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::DoFailSafeMove
|
2018-09-17 23:50:38 +02:00
|
|
|
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::DoFailSafeMove(vec3_t dest)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
Com_Printf("(entnum %d, radnum %d) blocked, doing failsafe\n", entnum, radnum);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
VectorCopy(dest, m_NoClipDest);
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThinkState(THINKSTATE_NOCLIP, THINKLEVEL_NOCLIP);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::GetMoveInfo
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Fetch current move information from mm.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::GetMoveInfo(mmove_t *mm)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-14 15:02:07 +02:00
|
|
|
trace_t trace;
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_walking = mm->walking;
|
|
|
|
m_groundPlane = mm->groundPlane;
|
2023-10-14 14:08:52 +02:00
|
|
|
VectorCopy(mm->groundPlaneNormal, m_groundPlaneNormal);
|
2023-10-16 00:29:41 +02:00
|
|
|
groundentity = NULL;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
TouchStuff(mm);
|
2023-10-16 00:29:41 +02:00
|
|
|
|
2023-10-14 15:02:07 +02:00
|
|
|
switch (m_eAnimMode) {
|
|
|
|
case ANIM_MODE_DEST:
|
|
|
|
if (!mm->hit_temp_obstacle && mm->hit_obstacle) {
|
|
|
|
trace = G_Trace(
|
|
|
|
m_Dest,
|
|
|
|
PLAYER_BASE_MIN,
|
|
|
|
PLAYER_BASE_MAX,
|
|
|
|
m_Dest - Vector(0, 0, 16384),
|
2023-10-16 00:29:41 +02:00
|
|
|
(Entity *)NULL,
|
2023-10-14 15:02:07 +02:00
|
|
|
MASK_MOVEINFO,
|
|
|
|
qfalse,
|
|
|
|
"Actor::GetMoveInfo"
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-14 15:02:07 +02:00
|
|
|
DoFailSafeMove(trace.endpos);
|
2023-10-23 15:55:58 +02:00
|
|
|
} else if (mm->hit_temp_obstacle && (mm->hit_temp_obstacle & 1)) {
|
2023-10-16 00:29:41 +02:00
|
|
|
Player *p;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
p = static_cast<Player *>(G_GetEntity(0));
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-14 15:02:07 +02:00
|
|
|
if (!IsTeamMate(p)) {
|
|
|
|
if (!m_bEnableEnemy) {
|
|
|
|
m_bDesiredEnableEnemy = true;
|
|
|
|
UpdateEnableEnemy();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-14 15:02:07 +02:00
|
|
|
BecomeTurretGuy();
|
|
|
|
ForceAttackPlayer();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ANIM_MODE_PATH:
|
|
|
|
case ANIM_MODE_PATH_GOAL:
|
|
|
|
if (mm->hit_temp_obstacle) {
|
|
|
|
if (mm->hit_temp_obstacle & 1) {
|
2023-10-16 00:29:41 +02:00
|
|
|
Player *p;
|
2023-10-14 15:02:07 +02:00
|
|
|
|
|
|
|
m_Path.Clear();
|
2023-10-16 00:29:41 +02:00
|
|
|
p = static_cast<Player *>(G_GetEntity(0));
|
2023-10-14 15:02:07 +02:00
|
|
|
|
|
|
|
if (!IsTeamMate(p)) {
|
|
|
|
if (!m_bEnableEnemy) {
|
|
|
|
m_bDesiredEnableEnemy = true;
|
|
|
|
UpdateEnableEnemy();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-14 15:02:07 +02:00
|
|
|
BecomeTurretGuy();
|
|
|
|
ForceAttackPlayer();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-14 15:02:07 +02:00
|
|
|
VectorClear(velocity);
|
|
|
|
} else if (mm->hit_obstacle) {
|
|
|
|
if (level.inttime >= m_Path.Time() + 1000) {
|
|
|
|
m_Path.ReFindPath(origin, this);
|
|
|
|
} else {
|
2023-10-16 00:29:41 +02:00
|
|
|
PathInfo *node = m_Path.NextNode();
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
if (!node
|
|
|
|
|| !m_Path.IsAccurate()
|
|
|
|
&& (node == m_Path.LastNode() && m_Path.CurrentNode() != m_Path.StartNode())) {
|
2023-10-14 15:02:07 +02:00
|
|
|
m_Path.Clear();
|
|
|
|
VectorClear(velocity);
|
|
|
|
return;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-14 15:02:07 +02:00
|
|
|
if (m_Path.CurrentNode() == m_Path.StartNode()) {
|
|
|
|
Com_Printf(
|
|
|
|
"^~^~^ BAD FAILSAFE: %.2f %.2f %.2f, '%s'\n",
|
|
|
|
origin[0],
|
|
|
|
origin[1],
|
|
|
|
origin[2],
|
|
|
|
targetname.c_str()
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-14 15:02:07 +02:00
|
|
|
DoFailSafeMove(node->point);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2024-08-29 23:31:46 +02:00
|
|
|
} else if (DotProduct2D(mm->velocity, velocity) < -0.7f && level.inttime >= m_Path.Time() + 1000) {
|
2023-10-14 15:02:07 +02:00
|
|
|
m_Path.ReFindPath(origin, this);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 15:02:07 +02:00
|
|
|
break;
|
2023-10-23 15:55:58 +02:00
|
|
|
default:
|
|
|
|
break;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
setOrigin(mm->origin);
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (VectorLengthSquared(mm->velocity) < 1) {
|
2023-10-23 15:55:58 +02:00
|
|
|
VectorClear(velocity);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-23 15:55:58 +02:00
|
|
|
VectorCopy(mm->velocity, velocity);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::TouchStuff
|
2018-09-17 23:50:38 +02:00
|
|
|
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::TouchStuff(mmove_t *mm)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
int i, j;
|
|
|
|
gentity_t *other;
|
|
|
|
Event *event;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (getMoveType() != MOVETYPE_NOCLIP) {
|
|
|
|
G_TouchTriggers(this);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
for (i = 0; i < mm->numtouch; i++) {
|
2023-10-11 22:49:06 +02:00
|
|
|
other = &g_entities[mm->touchents[i]];
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
for (j = 0; j < i; j++) {
|
2023-10-14 18:40:53 +02:00
|
|
|
if (&g_entities[j] == other) {
|
2023-10-11 22:49:06 +02:00
|
|
|
break;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (j != i) {
|
2023-10-11 22:49:06 +02:00
|
|
|
// duplicated
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Don't bother touching the world
|
2023-10-14 18:40:53 +02:00
|
|
|
if (!other->entity || other->entity == world) {
|
2023-10-11 22:49:06 +02:00
|
|
|
continue;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
event = new Event(EV_Touch);
|
|
|
|
event->AddEntity(this);
|
|
|
|
other->entity->ProcessEvent(event);
|
|
|
|
|
|
|
|
event = new Event(EV_Touch);
|
|
|
|
event->AddEntity(other->entity);
|
|
|
|
ProcessEvent(event);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ResetBoneControllers
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Reset Bone Controllers.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ResetBoneControllers(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (edict->s.bone_tag[HEAD_TAG] != -1) {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetControllerAngles(HEAD_TAG, vec_zero);
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
if (edict->s.bone_tag[TORSO_TAG] != -1) {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetControllerAngles(TORSO_TAG, vec_zero);
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
if (edict->s.bone_tag[ARMS_TAG] != -1) {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetControllerAngles(ARMS_TAG, vec_zero);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::UpdateBoneControllers
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Update Bone Controllers.
|
|
|
|
Reversed incorrectly, since decompiled output has different behaviour as reversed output.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::UpdateBoneControllers(void)
|
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
float pitchError, yawError, error;
|
|
|
|
float max_change, max_accel_change, min_accel_change;
|
2023-10-14 18:40:53 +02:00
|
|
|
Vector headAngles, torsoAngles;
|
2023-10-16 00:29:41 +02:00
|
|
|
float tolerable_error;
|
2023-10-14 18:40:53 +02:00
|
|
|
vec3_t LocalLookAngles;
|
2023-10-16 00:29:41 +02:00
|
|
|
float torsoYawError;
|
2023-10-14 18:40:53 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_bHasDesiredLookAngles) {
|
2023-10-16 00:29:41 +02:00
|
|
|
vec3_t myAxis[3];
|
|
|
|
vec3_t eyePosition;
|
|
|
|
vec3_t lookAxis[3];
|
|
|
|
vec3_t endPosition;
|
|
|
|
vec3_t worldLookAngles;
|
|
|
|
vec3_t lineVec;
|
|
|
|
int tagnum;
|
2023-10-14 18:40:53 +02:00
|
|
|
orientation_t tag_or;
|
2023-10-16 00:29:41 +02:00
|
|
|
Vector vError;
|
2023-10-14 18:40:53 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
if (g_showlookat->integer == entnum || g_showlookat->integer == -1) {
|
2023-10-14 18:40:53 +02:00
|
|
|
tagnum = gi.Tag_NumForName(edict->tiki, "eyes bone");
|
|
|
|
tag_or = G_TIKI_Orientation(edict, tagnum & TAG_MASK);
|
|
|
|
AnglesToAxis(angles, myAxis);
|
|
|
|
|
|
|
|
VectorCopy(origin, eyePosition);
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
VectorMA(eyePosition, tag_or.origin[i], myAxis[i], eyePosition);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
Vector vEndPoint;
|
|
|
|
|
|
|
|
if (m_bHasDesiredLookDest) {
|
|
|
|
vEndPoint = m_vDesiredLookDest;
|
|
|
|
} else if (m_pLookEntity) {
|
|
|
|
if (m_pLookEntity->IsSubclassOfSentient()) {
|
2023-10-16 00:29:41 +02:00
|
|
|
Sentient *sent = static_cast<Sentient *>(m_pLookEntity.Pointer());
|
|
|
|
vEndPoint = sent->EyePosition();
|
2023-10-14 18:40:53 +02:00
|
|
|
} else {
|
|
|
|
vEndPoint = m_pLookEntity->centroid;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
worldLookAngles[i] = m_DesiredLookAngles[i] + angles[i];
|
|
|
|
}
|
|
|
|
|
|
|
|
AnglesToAxis(worldLookAngles, lookAxis);
|
|
|
|
|
|
|
|
Vector vEndPointDir = vEndPoint - eyePosition;
|
|
|
|
vEndPointDir.normalize();
|
|
|
|
|
|
|
|
// calculate the error
|
|
|
|
Vector vError = vEndPointDir - lookAxis[0];
|
|
|
|
|
|
|
|
if (vError.length() >= 0.1f) {
|
|
|
|
VectorSet(lineVec, 128, 0, 0);
|
|
|
|
VectorCopy(eyePosition, endPosition);
|
|
|
|
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
VectorMA(endPosition, lineVec[i], lookAxis[i], endPosition);
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-14 18:40:53 +02:00
|
|
|
int boxalpha;
|
|
|
|
|
|
|
|
VectorCopy(vEndPoint, endPosition);
|
|
|
|
|
|
|
|
if (vError.length() >= 0.04f) {
|
|
|
|
boxalpha = (vError.length() - 0.1f) / 0.06f;
|
|
|
|
} else {
|
|
|
|
boxalpha = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
G_DebugLine(vEndPoint + Vector(8, 8, 8), vEndPoint + Vector(8, 8, -8), 0, 0, boxalpha, boxalpha);
|
|
|
|
G_DebugLine(vEndPoint + Vector(8, -8, 8), vEndPoint + Vector(8, -8, -8), 0, 0, boxalpha, boxalpha);
|
|
|
|
G_DebugLine(vEndPoint + Vector(-8, 8, 8), vEndPoint + Vector(-8, 8, -8), 0, 0, boxalpha, boxalpha);
|
|
|
|
G_DebugLine(vEndPoint + Vector(-8, -8, 8), vEndPoint + Vector(-8, -8, -8), 0, 0, boxalpha, boxalpha);
|
|
|
|
G_DebugLine(vEndPoint + Vector(8, 8, 8), vEndPoint + Vector(8, -8, 8), 0, 0, boxalpha, boxalpha);
|
|
|
|
G_DebugLine(vEndPoint + Vector(8, 8, -8), vEndPoint + Vector(8, -8, -8), 0, 0, boxalpha, boxalpha);
|
|
|
|
G_DebugLine(vEndPoint + Vector(-8, 8, 8), vEndPoint + Vector(-8, -8, 8), 0, 0, boxalpha, boxalpha);
|
|
|
|
G_DebugLine(vEndPoint + Vector(-8, 8, -8), vEndPoint + Vector(-8, -8, -8), 0, 0, boxalpha, boxalpha);
|
|
|
|
G_DebugLine(vEndPoint + Vector(8, 8, 8), vEndPoint + Vector(-8, 8, 8), 0, 0, boxalpha, boxalpha);
|
|
|
|
G_DebugLine(vEndPoint + Vector(8, 8, -8), vEndPoint + Vector(-8, 8, -8), 0, 0, boxalpha, boxalpha);
|
|
|
|
G_DebugLine(vEndPoint + Vector(8, -8, 8), vEndPoint + Vector(-8, -8, 8), 0, 0, boxalpha, boxalpha);
|
|
|
|
G_DebugLine(vEndPoint + Vector(8, -8, -8), vEndPoint + Vector(-8, -8, -8), 0, 0, boxalpha, boxalpha);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
G_DebugLine(eyePosition, endPosition, 0, 0, 1, 1);
|
|
|
|
|
|
|
|
VectorSet(lineVec, 0, 0, -2);
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
VectorMA(eyePosition, lineVec[i], lookAxis[i], eyePosition);
|
|
|
|
VectorMA(endPosition, lineVec[i], lookAxis[i], endPosition);
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
G_DebugLine(eyePosition, endPosition, 0, 0, 1, 1);
|
|
|
|
|
|
|
|
VectorSet(lineVec, 0, 2, 0);
|
|
|
|
for (int i = 0; i < 3; i++) {
|
|
|
|
VectorMA(eyePosition, lineVec[i], lookAxis[i], eyePosition);
|
|
|
|
VectorMA(endPosition, lineVec[i], lookAxis[i], endPosition);
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
G_DebugLine(eyePosition, endPosition, 0, 0, 1, 1);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
VectorCopy(m_DesiredLookAngles, LocalLookAngles);
|
|
|
|
|
|
|
|
Vector EyeDelta;
|
|
|
|
Vector fwd;
|
|
|
|
|
|
|
|
EyeDelta = LocalLookAngles;
|
|
|
|
EyeDelta.AngleVectorsLeft(&fwd, NULL, NULL);
|
|
|
|
VectorCopy(fwd, edict->s.eyeVector);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-14 18:40:53 +02:00
|
|
|
VectorClear(edict->s.eyeVector);
|
|
|
|
VectorClear(LocalLookAngles);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
torsoAngles = GetControllerAngles(TORSO_TAG);
|
2023-10-16 00:29:41 +02:00
|
|
|
headAngles = GetControllerAngles(HEAD_TAG);
|
2023-10-14 18:40:53 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
yawError = LocalLookAngles[1] - (torsoAngles[1] + headAngles[1]);
|
|
|
|
pitchError = LocalLookAngles[0] - headAngles[0];
|
2023-10-14 18:40:53 +02:00
|
|
|
torsoYawError = LocalLookAngles[1] - torsoAngles[1];
|
|
|
|
|
|
|
|
if (torsoYawError > 180) {
|
|
|
|
torsoYawError -= 360;
|
|
|
|
} else if (torsoYawError < -180) {
|
|
|
|
torsoYawError += 360;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
if (torsoYawError >= 0) {
|
|
|
|
if (yawError < -120) {
|
|
|
|
yawError += 360;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
|
|
|
} else {
|
2023-10-14 18:40:53 +02:00
|
|
|
if (yawError > 120) {
|
|
|
|
yawError -= 360;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
if (!(m_iLookFlags & 1)) {
|
|
|
|
if (yawError > 25) {
|
|
|
|
max_change = (yawError - 25) * 0.2f;
|
|
|
|
} else if (yawError < -25) {
|
|
|
|
max_change = (yawError + 25) * 0.2f;
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-14 18:40:53 +02:00
|
|
|
max_change = 0;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
tolerable_error = yawError + headAngles[1];
|
|
|
|
if (-torsoAngles[1] < tolerable_error) {
|
|
|
|
max_change = Q_clamp_float(max_change, -torsoAngles[1], tolerable_error);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-14 21:21:45 +02:00
|
|
|
max_change = Q_clamp_float(max_change, tolerable_error, -torsoAngles[1]);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
max_accel_change = m_fTorsoCurrentTurnSpeed + level.frametime * 15;
|
|
|
|
min_accel_change = m_fTorsoCurrentTurnSpeed - level.frametime * 15;
|
2023-10-16 00:29:41 +02:00
|
|
|
|
2023-10-14 18:40:53 +02:00
|
|
|
max_change = Q_clamp_float(max_change, min_accel_change, max_accel_change);
|
2023-10-16 00:29:41 +02:00
|
|
|
max_change = Q_clamp_float(
|
|
|
|
max_change, level.frametime * -m_fTorsoCurrentTurnSpeed, level.frametime * m_fTorsoCurrentTurnSpeed
|
|
|
|
);
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
torsoAngles[1] += max_change;
|
|
|
|
|
|
|
|
if (torsoAngles[1] > 30) {
|
|
|
|
max_change -= torsoAngles[1] - 30;
|
|
|
|
torsoAngles[1] = 30;
|
|
|
|
} else if (torsoAngles[1] < -30) {
|
|
|
|
max_change -= torsoAngles[1] + 30;
|
|
|
|
torsoAngles[1] = -30;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
m_fTorsoCurrentTurnSpeed = max_change;
|
|
|
|
|
|
|
|
// clear pitch/roll
|
|
|
|
torsoAngles[0] = 0;
|
|
|
|
torsoAngles[2] = 0;
|
|
|
|
|
|
|
|
SetControllerAngles(TORSO_TAG, torsoAngles);
|
|
|
|
yawError -= max_change;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
if (yawError > 15.f) {
|
|
|
|
max_change = (yawError - 15.f) * level.frametime * 4.f;
|
|
|
|
} else if (yawError < -15.f) {
|
|
|
|
max_change = (yawError + 15.f) * level.frametime * 4.f;
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-14 18:40:53 +02:00
|
|
|
max_change = 0;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
if (-headAngles[1] < yawError) {
|
|
|
|
max_change = Q_clamp_float(max_change, -headAngles[1], yawError);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-14 18:40:53 +02:00
|
|
|
max_change = Q_clamp_float(max_change, yawError, -headAngles[1]);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
max_change =
|
|
|
|
Q_clamp_float(max_change, level.frametime * -m_fHeadMaxTurnSpeed, level.frametime * m_fHeadMaxTurnSpeed);
|
|
|
|
|
2023-10-14 18:40:53 +02:00
|
|
|
headAngles[1] += max_change;
|
|
|
|
// clamp head yaw to 60 degrees
|
|
|
|
headAngles[1] = Q_clamp_float(headAngles[1], -60, 60);
|
|
|
|
|
|
|
|
error = 15.f;
|
|
|
|
|
|
|
|
if (fabs(LocalLookAngles[0]) < 15) {
|
|
|
|
error = fabs(LocalLookAngles[0]);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
if (pitchError > error) {
|
|
|
|
max_change = (pitchError - error) * 0.2f;
|
|
|
|
} else if (pitchError < -error) {
|
|
|
|
max_change = (pitchError + error) * 0.2f;
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-14 18:40:53 +02:00
|
|
|
max_change = 0;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
max_change =
|
|
|
|
Q_clamp_float(max_change, level.frametime * -m_fHeadMaxTurnSpeed, level.frametime * m_fHeadMaxTurnSpeed);
|
2023-10-14 18:40:53 +02:00
|
|
|
headAngles[0] += max_change;
|
|
|
|
// clamp head pitch to 35 degrees
|
|
|
|
headAngles[0] = Q_clamp_float(headAngles[0], -35, 35);
|
|
|
|
headAngles[2] = 0;
|
|
|
|
|
|
|
|
if (m_iLookFlags & 1) {
|
|
|
|
// half view
|
|
|
|
headAngles[0] /= 2.f;
|
|
|
|
headAngles[1] /= 2.f;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:40:53 +02:00
|
|
|
|
|
|
|
SetControllerAngles(HEAD_TAG, headAngles);
|
|
|
|
|
|
|
|
Vector tmp_angles;
|
|
|
|
Vector new_angles;
|
|
|
|
|
|
|
|
// arms
|
|
|
|
tmp_angles = GetControllerAngles(ARMS_TAG);
|
|
|
|
|
|
|
|
max_change = m_vLUpperArmDesiredAngles[1] - tmp_angles[1];
|
|
|
|
if (max_change > 180) {
|
|
|
|
max_change -= 360;
|
|
|
|
} else if (max_change < -180) {
|
|
|
|
max_change += 360;
|
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
max_change =
|
|
|
|
Q_clamp_float(max_change, level.frametime * -m_fLUpperArmTurnSpeed, level.frametime * m_fLUpperArmTurnSpeed);
|
2023-10-14 18:40:53 +02:00
|
|
|
// set the new arms angles
|
|
|
|
new_angles[0] = m_vLUpperArmDesiredAngles[0];
|
|
|
|
new_angles[1] = tmp_angles[1] + max_change;
|
|
|
|
new_angles[2] = 0;
|
|
|
|
SetControllerAngles(ARMS_TAG, new_angles);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::setOriginEvent
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::setOriginEvent(Vector org)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 18:59:35 +02:00
|
|
|
float dist;
|
2023-10-16 00:29:41 +02:00
|
|
|
bool bRejoin = false;
|
2023-10-14 18:59:35 +02:00
|
|
|
|
|
|
|
dist = (org - origin).lengthSquared();
|
|
|
|
|
|
|
|
if (dist > Square(DEFAULT_NEARBY_SQUAD_DIST)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
bRejoin = true;
|
|
|
|
DisbandSquadMate(this);
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iOriginTime = level.inttime;
|
|
|
|
|
|
|
|
VectorCopy2D(org, m_vOriginHistory[0]);
|
|
|
|
VectorCopy2D(org, m_vOriginHistory[1]);
|
|
|
|
VectorCopy2D(org, m_vOriginHistory[2]);
|
2023-10-14 18:59:35 +02:00
|
|
|
VectorCopy2D(org, m_vOriginHistory[3]);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
VectorClear(velocity);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (level.Spawned()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
SafeSetOrigin(org);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
setOrigin(org);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
m_vHome = origin;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (bRejoin) {
|
2023-10-14 18:59:35 +02:00
|
|
|
JoinNearbySquads(DEFAULT_NEARBY_SQUAD_DIST);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (dist > Square(MIN_BADPLACE_UPDATE_DIST)) {
|
|
|
|
UpdateBadPlaces();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::SafeSetOrigin
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Safe set origin.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SafeSetOrigin(vec3_t newOrigin)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 18:59:35 +02:00
|
|
|
// don't update the origin if it's the same
|
2023-10-12 18:19:22 +02:00
|
|
|
if (newOrigin == origin) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
setOrigin(newOrigin);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!m_bNoPlayerCollision) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Player *p = (Player *)G_GetEntity(0);
|
2023-10-14 18:59:35 +02:00
|
|
|
|
2024-08-26 23:55:45 +02:00
|
|
|
// Added in 2.30
|
|
|
|
// Solidity check.
|
2024-04-21 20:33:31 +02:00
|
|
|
// If the Actor is already nonsolid the player won't get stuck
|
|
|
|
if (p && IsTouching(p) && getSolidType() != SOLID_NOT) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Com_Printf("(entnum %d, radnum %d) is going not solid to not get stuck in the player\n", entnum, radnum);
|
|
|
|
m_bNoPlayerCollision = true;
|
|
|
|
setSolidType(SOLID_NOT);
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::DoMove
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Move the actor based on m_eAnimMode.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::DoMove(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
mmove_t mm;
|
2023-10-14 18:59:35 +02:00
|
|
|
trace_t trace;
|
2023-10-14 14:10:16 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
if (m_eAnimMode != ANIM_MODE_ATTACHED
|
|
|
|
&& (!m_bDoPhysics || m_iOriginTime == level.inttime || m_pGlueMaster || bindmaster)) {
|
2023-10-14 18:59:35 +02:00
|
|
|
return;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-14 18:59:35 +02:00
|
|
|
switch (m_eAnimMode) {
|
|
|
|
case ANIM_MODE_NORMAL:
|
|
|
|
SetMoveInfo(&mm);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-14 18:59:35 +02:00
|
|
|
VectorCopy2D(frame_delta, mm.desired_dir);
|
|
|
|
mm.desired_speed = VectorNormalize2D(mm.desired_dir) / level.frametime;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-14 18:59:35 +02:00
|
|
|
if (mm.desired_speed > m_maxspeed) {
|
|
|
|
mm.desired_speed = m_maxspeed;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:59:35 +02:00
|
|
|
|
|
|
|
MmoveSingle(&mm);
|
|
|
|
GetMoveInfo(&mm);
|
|
|
|
break;
|
|
|
|
case ANIM_MODE_PATH:
|
|
|
|
MovePath(frame_delta.length() / level.frametime);
|
|
|
|
break;
|
|
|
|
case ANIM_MODE_PATH_GOAL:
|
|
|
|
MovePathGoal(frame_delta.length() / level.frametime);
|
|
|
|
break;
|
|
|
|
case ANIM_MODE_DEST:
|
|
|
|
MoveDest(frame_delta.length() / level.frametime);
|
|
|
|
break;
|
|
|
|
case ANIM_MODE_SCRIPTED:
|
2024-04-21 20:28:54 +02:00
|
|
|
setAngles(angles + Vector(0, angular_delta, 0));
|
2023-10-14 18:59:35 +02:00
|
|
|
trace = G_Trace(
|
|
|
|
origin, mins, maxs, origin + frame_delta, this, edict->clipmask & ~MASK_SCRIPT_SLAVE, qtrue, "Actor"
|
|
|
|
);
|
|
|
|
SafeSetOrigin(trace.endpos);
|
|
|
|
velocity = frame_delta / level.frametime;
|
|
|
|
break;
|
|
|
|
case ANIM_MODE_NOCLIP:
|
2024-04-21 20:28:54 +02:00
|
|
|
setAngles(angles + Vector(0, angular_delta, 0));
|
2023-10-14 18:59:35 +02:00
|
|
|
SafeSetOrigin(origin + frame_delta);
|
|
|
|
velocity = frame_delta / level.frametime;
|
|
|
|
break;
|
|
|
|
case ANIM_MODE_FALLING_PATH:
|
|
|
|
SafeSetOrigin(m_pFallPath->pos[m_pFallPath->currentPos]);
|
|
|
|
m_pFallPath->currentPos++;
|
|
|
|
velocity = vec_zero;
|
|
|
|
break;
|
|
|
|
case ANIM_MODE_ATTACHED:
|
2023-10-16 00:29:41 +02:00
|
|
|
{
|
|
|
|
Vector frame_offset;
|
|
|
|
Vector attach_angles;
|
2023-10-14 18:59:35 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
frame_offset = edict->s.attach_offset;
|
|
|
|
frame_offset += frame_delta;
|
|
|
|
frame_offset.copyTo(edict->s.attach_offset);
|
|
|
|
setOrigin();
|
2023-10-14 18:59:35 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
attach_angles = angles;
|
|
|
|
attach_angles[1] += angular_delta;
|
|
|
|
setAngles(attach_angles);
|
2023-10-14 18:59:35 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
velocity = frame_delta / level.frametime;
|
|
|
|
break;
|
|
|
|
}
|
2023-10-14 18:59:35 +02:00
|
|
|
default:
|
|
|
|
break;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 18:59:35 +02:00
|
|
|
|
|
|
|
m_maxspeed = 1000000.0f;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::UpdateAngles
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Update current angles.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::UpdateAngles(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
float max_change, error, dist;
|
|
|
|
|
2023-10-14 20:33:50 +02:00
|
|
|
if (m_YawAchieved) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-14 20:33:50 +02:00
|
|
|
error = m_DesiredYaw - angles[1];
|
|
|
|
if (error > 180) {
|
|
|
|
error -= 360;
|
|
|
|
} else if (error < -180) {
|
|
|
|
error += 360;
|
|
|
|
}
|
|
|
|
|
|
|
|
dist = m_fAngleYawSpeed * level.frametime;
|
|
|
|
if (error < -dist) {
|
|
|
|
max_change = -dist;
|
|
|
|
} else if (error > dist) {
|
|
|
|
max_change = dist;
|
|
|
|
} else {
|
|
|
|
max_change = error;
|
|
|
|
StopTurning();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 20:33:50 +02:00
|
|
|
|
|
|
|
setAngles(Vector(0, angles[1] + max_change, 0));
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::SetLeashHome
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set leash home.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetLeashHome(Vector vHome)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!m_bFixedLeash) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_vHome = vHome;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::GunPosition
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns current gun position.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
Vector Actor::GunPosition(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_iGunPositionCheckTime < level.inttime) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iGunPositionCheckTime = level.inttime;
|
2023-10-12 18:19:22 +02:00
|
|
|
Weapon *weap = GetActiveWeapon(WEAPON_MAIN);
|
|
|
|
if (weap) {
|
2023-10-11 22:49:06 +02:00
|
|
|
weap->GetMuzzlePosition(m_vGunPosition);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_vGunPosition = vec_zero;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return m_vGunPosition;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::CanSee
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if actor cansee entity through fov and vision_distance.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::CanSee(Entity *e1, float fov, float vision_distance, bool bNoEnts)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-14 20:33:50 +02:00
|
|
|
bool bCanSee = Sentient::CanSee(e1, fov, vision_distance, false);
|
2023-10-12 18:19:22 +02:00
|
|
|
if (e1 == m_Enemy) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iEnemyVisibleCheckTime = level.inttime;
|
2023-10-14 20:33:50 +02:00
|
|
|
// Added in 2.0.
|
|
|
|
// Check for obfuscation like smoke sprite
|
|
|
|
m_fVisibilityAlpha = 0;
|
|
|
|
if (bCanSee) {
|
|
|
|
m_fVisibilityAlpha = 1.0f - G_VisualObfuscation(VirtualEyePosition(), m_Enemy->EyePosition());
|
|
|
|
if (m_fVisibilityAlpha < m_fVisibilityThreshold) {
|
|
|
|
// enemy is obfuscated behind something
|
|
|
|
bCanSee = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bCanSee) {
|
|
|
|
SetEnemyPos(m_Enemy->origin);
|
2023-10-12 18:19:22 +02:00
|
|
|
m_bEnemyIsDisguised = m_Enemy->m_bIsDisguised;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iLastEnemyVisibleTime = level.inttime;
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-14 20:33:50 +02:00
|
|
|
if (bCanSee != m_bEnemyVisible) {
|
|
|
|
m_bEnemyVisible = !m_bEnemyVisible;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iEnemyVisibleChangeTime = level.inttime;
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (fov != 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iEnemyFovCheckTime = level.inttime;
|
2023-10-14 20:33:50 +02:00
|
|
|
if (bCanSee != m_bEnemyInFOV) {
|
|
|
|
m_bEnemyInFOV = !m_bEnemyInFOV;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iEnemyFovChangeTime = level.inttime;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-14 20:33:50 +02:00
|
|
|
|
|
|
|
return bCanSee;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::WithinVisionDistance
|
|
|
|
|
|
|
|
Returns true if entity is witthin vision distance.
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
bool Actor::WithinVisionDistance(Entity *ent) const
|
|
|
|
{
|
|
|
|
float distance = world->farplane_distance;
|
|
|
|
|
|
|
|
if (!distance || distance < m_fSight) {
|
|
|
|
return WithinDistance(ent, m_fSight);
|
|
|
|
}
|
|
|
|
|
|
|
|
return WithinDistance(ent, distance);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 19:21:41 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::InFOV
|
|
|
|
|
|
|
|
Returns true if positin is within fov.
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
bool Actor::InFOV(Vector pos, float check_fov, float check_fovdot)
|
|
|
|
{
|
2023-10-14 20:33:50 +02:00
|
|
|
if (check_fov == 360) {
|
|
|
|
return true;
|
|
|
|
}
|
2023-10-12 19:21:41 +02:00
|
|
|
|
2023-10-14 20:33:50 +02:00
|
|
|
Vector delta = pos - VirtualEyePosition();
|
|
|
|
if (!delta.x && !delta.y) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
float fDot = DotProduct2D(delta, orientation[0]);
|
|
|
|
if (fDot < 0) {
|
|
|
|
return false;
|
2023-10-12 19:21:41 +02:00
|
|
|
}
|
2023-10-14 20:33:50 +02:00
|
|
|
|
|
|
|
return Square(fDot) > (delta.lengthXYSquared() * Square(check_fovdot));
|
2023-10-12 19:21:41 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::CanShoot
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if actor can shoot entity.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::CanShoot(Entity *ent)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
bool bCanShoot = false;
|
2023-10-14 20:33:50 +02:00
|
|
|
Vector vGunPos;
|
|
|
|
|
|
|
|
if (FriendlyInLineOfFire(ent)) {
|
2024-08-26 23:55:45 +02:00
|
|
|
// Added in 2.0
|
|
|
|
// Check if a friend is in sight
|
2023-10-14 20:33:50 +02:00
|
|
|
bCanShoot = false;
|
|
|
|
} else if (ent->IsSubclassOfSentient()) {
|
2023-10-16 00:29:41 +02:00
|
|
|
Sentient *sen = static_cast<Sentient *>(ent);
|
2023-10-14 20:33:50 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
vGunPos = GunPosition();
|
2023-10-14 20:33:50 +02:00
|
|
|
bCanShoot = false;
|
|
|
|
|
|
|
|
if (WithinFarplaneDistance(origin - ent->origin) && AreasConnected(ent)) {
|
|
|
|
if (G_SightTrace(
|
2023-10-16 00:29:41 +02:00
|
|
|
vGunPos,
|
|
|
|
vec_zero,
|
|
|
|
vec_zero,
|
|
|
|
sen->centroid,
|
|
|
|
this,
|
|
|
|
sen,
|
|
|
|
MASK_CANSEE,
|
|
|
|
qfalse,
|
|
|
|
"Actor::CanShoot centroid"
|
|
|
|
)) {
|
2023-10-14 20:33:50 +02:00
|
|
|
bCanShoot = true;
|
|
|
|
} else if (G_SightTrace(
|
2023-10-16 00:29:41 +02:00
|
|
|
vGunPos,
|
|
|
|
vec_zero,
|
|
|
|
vec_zero,
|
|
|
|
sen->EyePosition(),
|
|
|
|
this,
|
|
|
|
sen,
|
|
|
|
MASK_CANSEE,
|
|
|
|
qfalse,
|
|
|
|
"Actor::CanShoot eyes"
|
|
|
|
)) {
|
2023-10-14 20:33:50 +02:00
|
|
|
bCanShoot = true;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-14 20:33:50 +02:00
|
|
|
bCanShoot = false;
|
|
|
|
if (AreasConnected(ent)) {
|
2023-10-16 00:29:41 +02:00
|
|
|
vGunPos = GunPosition();
|
2023-10-14 20:33:50 +02:00
|
|
|
bCanShoot = CanSeeFrom(vGunPos, ent);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-14 20:33:50 +02:00
|
|
|
if (ent == m_Enemy) {
|
|
|
|
m_iCanShootCheckTime = level.inttime;
|
|
|
|
m_bCanShootEnemy = bCanShoot;
|
|
|
|
}
|
|
|
|
|
|
|
|
return bCanShoot;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::CanSeeFrom
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if actor can see entity from pos.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::CanSeeFrom(vec3_t pos, Entity *ent)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 20:33:50 +02:00
|
|
|
if (!WithinFarplaneDistance(pos)) {
|
|
|
|
// outside the farplane
|
|
|
|
return false;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 20:33:50 +02:00
|
|
|
|
|
|
|
if (ent->flags & FL_NOTARGET) {
|
|
|
|
// ent must be ignored by AI
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return G_SightTrace(pos, vec_zero, vec_zero, ent->centroid, this, ent, MASK_CANSEE, qfalse, "Actor::CanSeeFrom");
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EnemyInFOV
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if enemy is within fov.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::EnemyInFOV(int iMaxDirtyTime)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (level.inttime > iMaxDirtyTime + m_iEnemyFovCheckTime) {
|
2023-10-14 20:33:50 +02:00
|
|
|
if (m_bEnemyInFOV != InFOV(m_Enemy->centroid)) {
|
2023-10-16 00:29:41 +02:00
|
|
|
m_bEnemyInFOV = !m_bEnemyInFOV;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iEnemyFovChangeTime = level.inttime;
|
|
|
|
}
|
|
|
|
m_iEnemyFovCheckTime = level.inttime;
|
|
|
|
}
|
2023-10-14 20:33:50 +02:00
|
|
|
|
|
|
|
return m_bEnemyInFOV;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::CanSeeEnemy
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if actor can see enemy.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::CanSeeEnemy(int iMaxDirtyTime)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (level.inttime > iMaxDirtyTime + m_iEnemyVisibleCheckTime) {
|
2023-10-14 20:33:50 +02:00
|
|
|
CanSee(m_Enemy, 0, world->farplane_distance * 0.828f, false);
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
return m_bEnemyVisible;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::CanShootEnemy
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if actor can shoot enemy.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::CanShootEnemy(int iMaxDirtyTime)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (level.inttime > iMaxDirtyTime + m_iCanShootCheckTime) {
|
|
|
|
CanShoot(m_Enemy);
|
|
|
|
}
|
2018-08-02 15:12:07 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
return m_bCanShootEnemy;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::FriendlyInLineOfFire
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
bool Actor::FriendlyInLineOfFire(Entity *other)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 23:17:09 +02:00
|
|
|
Vector delta;
|
2023-10-16 00:29:41 +02:00
|
|
|
float inverseDot;
|
2023-10-12 23:17:09 +02:00
|
|
|
|
2024-02-14 20:47:54 +01:00
|
|
|
if (g_target_game <= target_game_e::TG_MOH) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
delta = other->origin - origin;
|
2023-10-12 23:17:09 +02:00
|
|
|
inverseDot = 1.0 / (delta * delta);
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
for (Sentient *pSquad = m_pNextSquadMate; pSquad != this; pSquad = pSquad->m_pNextSquadMate) {
|
2023-10-12 23:17:09 +02:00
|
|
|
Vector squadDelta;
|
2023-10-16 00:29:41 +02:00
|
|
|
float squadDot;
|
2023-10-12 23:17:09 +02:00
|
|
|
|
|
|
|
squadDelta = pSquad->origin - origin;
|
2023-10-16 00:29:41 +02:00
|
|
|
squadDot = squadDelta * delta;
|
2023-10-12 23:17:09 +02:00
|
|
|
if (squadDot >= 0) {
|
|
|
|
Vector org;
|
|
|
|
|
|
|
|
org = squadDot * inverseDot * delta - squadDelta;
|
2024-02-14 20:47:54 +01:00
|
|
|
if (org * org >= Square(64)) {
|
2023-10-12 23:17:09 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-12 19:21:41 +02:00
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::VirtualEyePosition
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
Vector Actor::VirtualEyePosition()
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 23:17:09 +02:00
|
|
|
if (m_pTurret && CurrentThink() == THINK_MACHINEGUNNER) {
|
|
|
|
// return the turret eye position
|
|
|
|
return m_pTurret->EyePosition();
|
|
|
|
} else {
|
|
|
|
return EyePosition();
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::CanTarget
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor can target.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::CanTarget(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
return true;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::IsImmortal
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor is immortal ?
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::IsImmortal(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::ShowInfo
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Prints basic actor information.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ShowInfo(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
Com_Printf("-------------------------------------------------------------------------------\n");
|
|
|
|
Com_Printf("Info for Actor:\n");
|
2024-02-17 20:10:00 +01:00
|
|
|
Com_Printf("Current think type: %s %s\n", ThinkStateName().c_str(), ThinkName().c_str());
|
2023-10-12 18:19:22 +02:00
|
|
|
Com_Printf("leash: %f\n", m_fLeash);
|
|
|
|
Com_Printf("mindist: %f\n", m_fMinDistance);
|
|
|
|
Com_Printf("maxdist: %f\n", m_fMaxDistance);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
GlobalFuncs_t *func = &GlobalFuncs[CurrentThink()];
|
2023-10-12 18:19:22 +02:00
|
|
|
if (func->ShowInfo) {
|
|
|
|
(this->*func->ShowInfo)();
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
Com_Printf("-------------------------------------------------------------------------------\n");
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ShowInfo
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Display actor info.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ShowInfo(float fDot, float fDist)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
float fMaxDist, fMinDot;
|
2023-10-11 22:49:06 +02:00
|
|
|
static cvar_t *g_entinfo_max;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!bEntinfoInit) {
|
2023-10-11 22:49:06 +02:00
|
|
|
g_entinfo_max = gi.Cvar_Get("g_entinfo_max", "2048", 0);
|
2023-10-12 18:19:22 +02:00
|
|
|
bEntinfoInit = true;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
fMinDot = 0.9f;
|
2023-10-11 22:49:06 +02:00
|
|
|
fMaxDist = g_entinfo_max->value;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (IsKilledState(m_ThinkState)) {
|
|
|
|
fMinDot = 0.99f;
|
2023-10-11 22:49:06 +02:00
|
|
|
fMaxDist = 512;
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (g_entinfo->integer != 4) {
|
|
|
|
if (fDot <= fMinDot) {
|
|
|
|
if (fDot <= 0 || fDist >= 256) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (fMaxDist <= fDist || fDist <= 64) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!m_bEnableEnemy) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Vector a = origin;
|
|
|
|
a.z += maxs.z + 74;
|
|
|
|
|
|
|
|
G_DebugString(a, 1.0, 1.0, 1.0, 1.0, "DISABLED");
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
Vector a = origin;
|
|
|
|
a.z += maxs.z + 56;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
G_DebugString(a, 1.0, 1.0, 1.0, 1.0, "%i:%i:%s:%.1f", entnum, radnum, targetname.c_str(), health);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_Enemy) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Vector a = origin;
|
|
|
|
a.z += maxs.z + 38;
|
|
|
|
|
|
|
|
G_DebugString(
|
|
|
|
a,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
"%i:%s:%.1f:%i",
|
|
|
|
m_Enemy->entnum,
|
|
|
|
m_Enemy->targetname.c_str(),
|
|
|
|
m_Enemy->health,
|
2023-10-12 18:19:22 +02:00
|
|
|
m_PotentialEnemies.GetCurrentThreat()
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (IsCuriousState(m_ThinkState)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Vector a = origin;
|
|
|
|
a.z += maxs.z + 20;
|
|
|
|
|
|
|
|
G_DebugString(
|
|
|
|
a,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
"%s:%%%.1f",
|
|
|
|
Director.GetString(m_csThinkStateNames[THINKSTATE_CURIOUS]).c_str(),
|
2023-10-12 18:19:22 +02:00
|
|
|
m_PotentialEnemies.GetCurrentVisibility() * 100
|
|
|
|
);
|
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
Vector a = origin;
|
|
|
|
a.z += maxs.z + 20;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
G_DebugString(a, 1.0, 1.0, 1.0, 1.0, "%s", ThinkStateName().c_str());
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
Vector a = origin;
|
|
|
|
a.z += maxs.z + 2;
|
|
|
|
|
|
|
|
str sAnimThreadFile = m_pAnimThread ? m_pAnimThread->FileName() : "(null)";
|
|
|
|
|
|
|
|
G_DebugString(
|
|
|
|
a,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
1.0,
|
|
|
|
"%s:%s:%i - %s",
|
|
|
|
ThinkName().c_str(),
|
|
|
|
m_pszDebugState,
|
|
|
|
m_State,
|
2023-10-12 18:19:22 +02:00
|
|
|
sAnimThreadFile.c_str()
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (g_entinfo->integer == 1) {
|
|
|
|
if (m_pGrenade) {
|
2023-10-11 22:49:06 +02:00
|
|
|
G_DebugLine(m_pGrenade->origin, m_vGrenadePos, 1.0, 0.0, 0.0, 1.0);
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
Vector a = m_vHome;
|
|
|
|
a.z += maxs.z + 18;
|
|
|
|
|
|
|
|
G_DebugLine(centroid, a, 0.0, 1.0, 0.0, 1.0);
|
|
|
|
|
|
|
|
G_DebugCircle(a, m_fLeash, 0.0, 1.0, 0.0, 1.0, qtrue);
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
G_DebugCircle(centroid, m_fMinDistance, 1.0, 0.0, 0.0, 1.0, qtrue);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
G_DebugCircle(centroid, m_fMaxDistance, 0.0, 0.0, 1.0, 1.0, qtrue);
|
|
|
|
} else if (g_entinfo->integer == 2) {
|
|
|
|
G_DebugCircle(centroid, m_fHearing, 1.0, 0.0, 0.0, 1.0, qtrue);
|
|
|
|
G_DebugCircle(centroid, m_fSight, 0.0, 0.0, 1.0, 1.0, qtrue);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::ThinkName
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
str Actor::ThinkName(void) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
return Director.GetString(m_csThinkNames[CurrentThink()]);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::ThinkStateName
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
str Actor::ThinkStateName(void) const
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
return Director.GetString(m_csThinkStateNames[m_ThinkState]);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::MoveTo
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Move actor to specific location/listener with specific animation.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::MoveTo(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
m_csPatrolCurrentAnim = ev->GetConstString(1);
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ev->IsVectorAt(2)) {
|
|
|
|
Vector vec = ev->GetVector(2);
|
|
|
|
SetPatrolCurrentNode(vec);
|
|
|
|
} else {
|
|
|
|
SetPatrolCurrentNode(ev->GetListener(2));
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_patrolCurrentNode) {
|
|
|
|
m_vScriptGoal = origin;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bScriptGoalValid = true;
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThinkIdle(THINK_RUNNER);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::WalkTo
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Walk to specific location.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::WalkTo(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
Event event = Event(EV_Listener_ExecuteScript, 2);
|
2023-10-12 18:19:22 +02:00
|
|
|
event.AddConstString(STRING_GLOBAL_WALKTO_SCR);
|
|
|
|
event.AddValue(ev->GetValue(1));
|
|
|
|
ExecuteScript(&event);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::RunTo
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Run to specific location.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::RunTo(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
Event event = Event(EV_Listener_ExecuteScript, 2);
|
2023-10-12 18:19:22 +02:00
|
|
|
event.AddConstString(STRING_GLOBAL_RUNTO_SCR);
|
|
|
|
event.AddValue(ev->GetValue(1));
|
|
|
|
ExecuteScript(&event);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
2019-08-18 22:06:49 +02:00
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::CrouchTo
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Crouch to specific location.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::CrouchTo(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
Event event = Event(EV_Listener_ExecuteScript, 2);
|
2023-10-12 18:19:22 +02:00
|
|
|
event.AddConstString(STRING_GLOBAL_CROUCHTO_SCR);
|
|
|
|
event.AddValue(ev->GetValue(1));
|
|
|
|
ExecuteScript(&event);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::CrawlTo
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Crawl to specific location.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::CrawlTo(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
Event event = Event(EV_Listener_ExecuteScript, 2);
|
2023-10-12 18:19:22 +02:00
|
|
|
event.AddConstString(STRING_GLOBAL_CRAWLTO_SCR);
|
|
|
|
event.AddValue(ev->GetValue(1));
|
|
|
|
ExecuteScript(&event);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ClearAimNode
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Clear aim node.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ClearAimNode(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_aimNode) {
|
|
|
|
if (m_aimNode->IsSubclassOfTempWaypoint()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
delete m_aimNode;
|
|
|
|
}
|
|
|
|
m_aimNode = NULL;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::SetAimNode
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Change aim node.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-14 21:53:17 +02:00
|
|
|
void Actor::SetAimNode(const Vector& vec)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearAimNode();
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
m_aimNode = new TempWaypoint();
|
2023-10-11 22:49:06 +02:00
|
|
|
m_aimNode->setOrigin(vec);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::SetAimNode
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Change aim node.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetAimNode(Listener *l)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearAimNode();
|
2023-10-12 18:19:22 +02:00
|
|
|
if (l) {
|
|
|
|
if (!l->inheritsFrom(&SimpleEntity::ClassInfo)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError(
|
|
|
|
"Bad aim node with classname '%s' specified for '%s' at (%f %f %f)\n",
|
|
|
|
l->getClassname(),
|
|
|
|
targetname.c_str(),
|
|
|
|
origin.x,
|
|
|
|
origin.y,
|
2023-10-12 18:19:22 +02:00
|
|
|
origin.z
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
m_aimNode = (SimpleEntity *)l;
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::AimAt
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Aim at specified target.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::AimAt(Event *ev)
|
2018-08-19 08:26:59 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ev->IsVectorAt(1)) {
|
2023-10-14 21:21:45 +02:00
|
|
|
SetAimNode(ev->GetVector(1));
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetAimNode(ev->GetListener(1));
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
SetThinkIdle(m_aimNode ? THINK_AIM : THINK_IDLE);
|
2018-08-19 08:26:59 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::LookAtLookEntity
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Change current look entity.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::LookAtLookEntity(void)
|
2018-08-19 08:26:59 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
Vector dir;
|
2023-10-14 21:21:45 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_pLookEntity->IsSubclassOfSentient()) {
|
2023-10-16 00:29:41 +02:00
|
|
|
Sentient *sen = static_cast<Sentient *>(m_pLookEntity.Pointer());
|
|
|
|
dir = sen->EyePosition() - EyePosition();
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
dir = m_pLookEntity->centroid - EyePosition();
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetDesiredLookDir(dir);
|
2018-08-19 08:26:59 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::IdleLook
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Idle look behaviour.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::IdleLook(void)
|
2018-08-19 08:26:59 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_pLookEntity) {
|
2023-10-11 22:49:06 +02:00
|
|
|
LookAtLookEntity();
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-14 21:21:45 +02:00
|
|
|
ForwardLook();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::IdleLook
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Idle look behaviour.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::IdleLook(vec3_t dir)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_pLookEntity) {
|
2023-10-11 22:49:06 +02:00
|
|
|
LookAtLookEntity();
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetDesiredLookDir(dir);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ClearLookEntity
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Clear look entity.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ClearLookEntity(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_pLookEntity) {
|
|
|
|
if (m_pLookEntity->IsSubclassOfTempWaypoint()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
delete m_pLookEntity;
|
|
|
|
}
|
|
|
|
m_pLookEntity = NULL;
|
|
|
|
}
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::LookAt
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Change current look entity.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::LookAt(const Vector& vec)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (g_showlookat->integer == entnum || g_showlookat->integer == -1) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Com_Printf(
|
|
|
|
"Script lookat: %i %i %s looking at point %.0f %.0f %.0f\n",
|
|
|
|
entnum,
|
|
|
|
radnum,
|
|
|
|
targetname.c_str(),
|
|
|
|
vec.x,
|
|
|
|
vec.y,
|
2023-10-12 18:19:22 +02:00
|
|
|
vec.z
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearLookEntity();
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
m_pLookEntity = new TempWaypoint();
|
2023-10-11 22:49:06 +02:00
|
|
|
m_pLookEntity->setOrigin(vec);
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::LookAt
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Change current look entity.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::LookAt(Listener *l)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ClearLookEntity();
|
2023-10-18 19:59:23 +02:00
|
|
|
if (!l) {
|
|
|
|
if (g_showlookat->integer == entnum || g_showlookat->integer == -1) {
|
|
|
|
Com_Printf("Script lookat: %i %i %s cleared lookat\n", entnum, radnum, TargetName().c_str());
|
|
|
|
}
|
2023-10-14 21:21:45 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!l->isSubclassOf(SimpleEntity)) {
|
|
|
|
ScriptError(
|
|
|
|
"Bad look entity with classname '%s' specified for '%s' at (%f %f %f)\n",
|
|
|
|
l->getClassname(),
|
|
|
|
targetname.c_str(),
|
|
|
|
origin.x,
|
|
|
|
origin.y,
|
|
|
|
origin.z
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (l != this) {
|
2023-10-16 00:29:41 +02:00
|
|
|
l = (SimpleEntity *)l;
|
2023-10-14 21:21:45 +02:00
|
|
|
if (g_showlookat->integer == entnum || g_showlookat->integer == -1) {
|
|
|
|
Com_Printf(
|
|
|
|
"Script lookat: %i %i %s looking at point %.0f %.0f %.0f\n",
|
|
|
|
entnum,
|
|
|
|
radnum,
|
2023-10-11 22:49:06 +02:00
|
|
|
targetname.c_str(),
|
2023-10-16 00:29:41 +02:00
|
|
|
((SimpleEntity *)l)->origin.x,
|
|
|
|
((SimpleEntity *)l)->origin.y,
|
|
|
|
((SimpleEntity *)l)->origin.z
|
2023-10-12 18:19:22 +02:00
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
m_pLookEntity = (SimpleEntity *)l;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventLookAt
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Look at event.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventLookAt(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ev->IsVectorAt(1)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
LookAt(ev->GetVector(1));
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
LookAt(ev->GetListener(1));
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
m_iLookFlags = 0;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventEyesLookAt
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Eyes look at event.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventEyesLookAt(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
EventLookAt(ev);
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
m_iLookFlags = LOOK_FLAG_EYE;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::NoPoint
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Don't point at anything.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::NoPoint(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
VectorClear(m_vLUpperArmDesiredAngles);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::IdlePoint
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Idle point behaviour.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::IdlePoint(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
if (!m_pPointEntity) {
|
2023-10-11 22:49:06 +02:00
|
|
|
NoPoint();
|
2023-10-14 21:21:45 +02:00
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 21:21:45 +02:00
|
|
|
|
|
|
|
Vector delta = m_pPointEntity->centroid - origin;
|
|
|
|
delta.normalize();
|
|
|
|
|
|
|
|
Vector pointAngles = delta.toAngles();
|
|
|
|
pointAngles.y -= angles.y;
|
|
|
|
|
|
|
|
pointAngles += Vector(0, 30, 0);
|
|
|
|
pointAngles.y = AngleNormalize180(delta.y);
|
|
|
|
pointAngles.y = Q_clamp_float(pointAngles.y, -80, 100);
|
|
|
|
|
|
|
|
m_vLUpperArmDesiredAngles[0] = pointAngles[0];
|
|
|
|
m_vLUpperArmDesiredAngles[1] = pointAngles[1];
|
|
|
|
m_vLUpperArmDesiredAngles[2] = pointAngles[2];
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ClearPointEntity
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Clear point entity.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ClearPointEntity(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_pPointEntity) {
|
|
|
|
if (m_pPointEntity->IsSubclassOfTempWaypoint()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
delete m_pPointEntity;
|
|
|
|
}
|
|
|
|
m_pPointEntity = NULL;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PointAt
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Change point entity.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::PointAt(const Vector& vec)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearPointEntity();
|
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
m_pPointEntity = new TempWaypoint();
|
2023-10-11 22:49:06 +02:00
|
|
|
m_pPointEntity->setOrigin(vec);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PointAt
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Change point entity.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::PointAt(Listener *l)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ClearPointEntity();
|
2023-10-14 21:21:45 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (l) {
|
2023-10-14 21:21:45 +02:00
|
|
|
if (l->isSubclassOf(SimpleEntity)) {
|
2023-10-12 18:19:22 +02:00
|
|
|
ScriptError(
|
|
|
|
"Bad point entity with classname '%s' specified for '%s' at (%f %f %f)\n",
|
2023-10-11 22:49:06 +02:00
|
|
|
l->getClassname(),
|
|
|
|
targetname.c_str(),
|
|
|
|
origin.x,
|
|
|
|
origin.y,
|
2023-10-12 18:19:22 +02:00
|
|
|
origin.z
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 21:21:45 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (l != this) {
|
2023-10-16 00:29:41 +02:00
|
|
|
m_pPointEntity = static_cast<SimpleEntity *>(l);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventPointAt
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Point at event.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventPointAt(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ev->IsVectorAt(1)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
PointAt(ev->GetVector(1));
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
PointAt(ev->GetListener(1));
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::IdleTurn
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Idle turn behaviour.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::IdleTurn(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
if (!m_pTurnEntity) {
|
|
|
|
return;
|
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
for (int i = 0; i < 2; i++) {
|
|
|
|
if (m_pTurnEntity == this) {
|
|
|
|
StopTurning();
|
|
|
|
m_pTurnEntity = NULL;
|
|
|
|
return;
|
|
|
|
}
|
2018-08-02 15:12:07 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
SetDesiredYawDest(m_pTurnEntity->centroid);
|
|
|
|
|
|
|
|
float error = m_DesiredYaw - angles[1];
|
|
|
|
if (error > 180) {
|
|
|
|
error -= 360;
|
|
|
|
} else if (error < -180) {
|
|
|
|
error += 360;
|
|
|
|
}
|
2018-08-02 15:12:07 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
if (error >= m_fTurnDoneError + 0.001f || error <= -m_fTurnDoneError - 0.001f) {
|
|
|
|
return;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
SafePtr<SimpleEntity> prevTurnEntity = m_pTurnEntity;
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
Director.Unpause();
|
|
|
|
Unregister(STRING_TURNDONE);
|
|
|
|
Director.Pause();
|
|
|
|
|
|
|
|
if (m_pTurnEntity == prevTurnEntity) {
|
|
|
|
break;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ClearTurnEntity
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Clear turn entity.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ClearTurnEntity(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_pTurnEntity) {
|
|
|
|
if (m_pTurnEntity->IsSubclassOfTempWaypoint()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
delete m_pTurnEntity;
|
|
|
|
}
|
|
|
|
m_pTurnEntity = NULL;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::TurnTo
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Change turn entity.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::TurnTo(const Vector& vec)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearTurnEntity();
|
2018-08-02 15:12:07 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
m_pTurnEntity = new TempWaypoint();
|
2023-10-11 22:49:06 +02:00
|
|
|
m_pTurnEntity->setOrigin(vec);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::TurnTo
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Change turn entity.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::TurnTo(Listener *l)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearTurnEntity();
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
if (!l) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_pTurnEntity = this;
|
2023-10-14 21:21:45 +02:00
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 21:21:45 +02:00
|
|
|
|
|
|
|
if (!l->isSubclassOf(SimpleEntity)) {
|
|
|
|
ScriptError(
|
|
|
|
"Bad turn entity with classname '%s' specified for '%s' at (%f %f %f)\n",
|
|
|
|
l->getClassname(),
|
|
|
|
targetname.c_str(),
|
|
|
|
origin.x,
|
|
|
|
origin.y,
|
|
|
|
origin.z
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_pTurnEntity = (SimpleEntity *)l;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventTurnTo
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Turn to event.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventTurnTo(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ev->IsVectorAt(1)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
TurnTo(ev->GetVector(1));
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
TurnTo(ev->GetListener(1));
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetTurnDoneError
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set the error amount that turndone will occur for the turnto command.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetTurnDoneError(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fTurnDoneError = ev->GetFloat(1);
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_fTurnDoneError < 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fTurnDoneError = 0;
|
|
|
|
ScriptError("turndoneerror was set to a negative value - capped to 0");
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventGetTurnDoneError
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Get the error amount that turndone will occur for the turnto command.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetTurnDoneError(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddFloat(m_fTurnDoneError);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGiveWeaponInternal
|
|
|
|
|
|
|
|
Give weapon to actor.
|
|
|
|
|
|
|
|
Called from STRING_GLOBAL_WEAPON_SCR.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGiveWeaponInternal(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
Holster();
|
|
|
|
RemoveWeapons();
|
2023-10-14 21:21:45 +02:00
|
|
|
|
|
|
|
const str weapName = ev->GetString(1);
|
|
|
|
if (weapName.length() > 0 && giveItem(weapName)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Unholster();
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGiveWeapon
|
|
|
|
|
|
|
|
Give weapon to actor.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGiveWeapon(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-18 19:59:23 +02:00
|
|
|
Event event(EV_Listener_ExecuteScript);
|
2023-10-14 21:21:45 +02:00
|
|
|
|
|
|
|
str weapName = ev->GetString(1);
|
2023-10-11 22:49:06 +02:00
|
|
|
weapName.tolower();
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
m_csLoadOut = Director.AddString(weapName);
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
if (m_csLoadOut == STRING_MG42) {
|
|
|
|
m_csWeapon = STRING_MP40;
|
|
|
|
} else {
|
|
|
|
m_csWeapon = m_csLoadOut;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
setModel();
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-18 19:59:23 +02:00
|
|
|
event.AddConstString(STRING_GLOBAL_WEAPON_SCR);
|
|
|
|
event.AddString(weapName);
|
|
|
|
|
|
|
|
ExecuteScript(&event);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetWeapon
|
|
|
|
|
|
|
|
Returns weapon path to script.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetWeapon(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddConstString(m_csWeapon);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::DefaultPain
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Default pain handler.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::DefaultPain(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThink(THINKSTATE_PAIN, THINK_PAIN);
|
|
|
|
HandlePain(ev);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::HandlePain
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Hangled pain event.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::HandlePain(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
int i;
|
|
|
|
Event event(EV_Listener_ExecuteScript);
|
|
|
|
int num;
|
|
|
|
Entity *attacker;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
if (!m_bEnablePain) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
attacker = ev->GetEntity(1);
|
2023-10-16 00:29:41 +02:00
|
|
|
if (attacker && attacker->IsSubclassOfSentient() && IsTeamMate(static_cast<Sentient *>(attacker))) {
|
2023-10-14 21:21:45 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_bNoLongPain) {
|
|
|
|
event.AddConstString(STRING_GLOBAL_PAIN_SCR);
|
|
|
|
|
|
|
|
num = ev->NumArgs();
|
|
|
|
for (i = 1; i <= num; i++) {
|
|
|
|
event.AddValue(ev->GetValue(i));
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
ExecuteScript(&event);
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThinkState(THINKSTATE_PAIN, THINKLEVEL_PAIN);
|
2023-10-14 21:21:45 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
RaiseAlertness(0.5f);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
m_PainTime = level.inttime;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
if (attacker && attacker->IsSubclassOfSentient() && !IsTeamMate(static_cast<Sentient *>(attacker))) {
|
2023-10-14 21:21:45 +02:00
|
|
|
m_pLastAttacker = attacker;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
m_iCuriousLevel = 9;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
//FIXME: macro
|
|
|
|
SetCuriousAnimHint(7);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2024-08-26 23:55:45 +02:00
|
|
|
// Added in 2.30 the m_bIsCurous check
|
2023-10-23 11:59:06 +02:00
|
|
|
if (m_bEnableEnemy && m_ThinkStates[THINKLEVEL_IDLE] == THINKSTATE_IDLE && m_bIsCurious) {
|
2023-10-14 21:21:45 +02:00
|
|
|
SetEnemyPos(attacker->origin);
|
|
|
|
m_pszDebugState = "from_pain";
|
2023-10-15 20:52:06 +02:00
|
|
|
SetThinkState(THINKSTATE_CURIOUS, THINKLEVEL_IDLE);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2023-10-14 21:21:45 +02:00
|
|
|
|
|
|
|
Unregister(STRING_PAIN);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventPain
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Pain event.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventPain(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
if (g_showinfo->integer) {
|
|
|
|
ShowInfo();
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
GlobalFuncs_t *func = &GlobalFuncs[CurrentThink()];
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (func->Pain) {
|
2023-10-11 22:49:06 +02:00
|
|
|
(this->*func->Pain)(ev);
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::DefaultKilled
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Default killed handler.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::DefaultKilled(Event *ev, bool bPlayDeathAnim)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearStates();
|
|
|
|
SetThink(THINKSTATE_KILLED, THINK_KILLED);
|
|
|
|
HandleKilled(ev, bPlayDeathAnim);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::HandleKilled
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Hangled killed event.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::HandleKilled(Event *ev, bool bPlayDeathAnim)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
deadflag = DEAD_DEAD;
|
2023-10-12 18:19:22 +02:00
|
|
|
health = 0.0;
|
2023-10-14 21:21:45 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (bPlayDeathAnim) {
|
2023-10-29 20:20:56 +01:00
|
|
|
Event event(EV_Listener_ExecuteScript, ev->NumArgs() + 1);
|
2023-10-14 21:21:45 +02:00
|
|
|
event.AddConstString(STRING_GLOBAL_KILLED_SCR);
|
2023-10-22 20:16:36 +02:00
|
|
|
for (int i = 1; i <= ev->NumArgs(); i++) {
|
2023-10-14 21:21:45 +02:00
|
|
|
event.AddValue(ev->GetValue(i));
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 21:21:45 +02:00
|
|
|
ExecuteScript(&event);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThink(THINKSTATE_KILLED, THINK_DEAD);
|
|
|
|
}
|
|
|
|
|
|
|
|
ClearThinkStates();
|
|
|
|
|
|
|
|
SetThinkState(THINKSTATE_KILLED, THINKLEVEL_KILLED);
|
|
|
|
|
|
|
|
Unregister(STRING_DEATH);
|
|
|
|
Unregister(STRING_PAIN);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::DispatchEventKilled
|
|
|
|
|
|
|
|
Dispatch killed event.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::DispatchEventKilled(Event *ev, bool bPlayDeathAnim)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
GlobalFuncs_t *func = &GlobalFuncs[CurrentThink()];
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-31 23:23:29 +01:00
|
|
|
assert(func->Killed);
|
|
|
|
(this->*func->Killed)(ev, bPlayDeathAnim);
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetEnemy(NULL, false);
|
|
|
|
|
|
|
|
DisbandSquadMate(this);
|
2023-10-12 18:19:22 +02:00
|
|
|
if (bPlayDeathAnim) {
|
2023-10-11 22:49:06 +02:00
|
|
|
DropInventoryItems();
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventKilled
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Killed event.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventKilled(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
Entity *attacker;
|
|
|
|
Sentient *pBuddy;
|
|
|
|
Sentient *sent;
|
|
|
|
Player *player;
|
2023-10-14 21:21:45 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
DispatchEventKilled(ev, true);
|
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
attacker = ev->GetEntity(1);
|
|
|
|
if (attacker && attacker->IsSubclassOfPlayer()) {
|
2023-10-16 00:29:41 +02:00
|
|
|
player = static_cast<Player *>(attacker);
|
2023-10-14 21:21:45 +02:00
|
|
|
if (player->m_Team != m_Team) {
|
|
|
|
player->m_iNumEnemiesKilled++;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 21:21:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (attacker && attacker->IsSubclassOfSentient()) {
|
2023-10-16 00:29:41 +02:00
|
|
|
sent = static_cast<Sentient *>(attacker);
|
2023-10-14 21:21:45 +02:00
|
|
|
|
|
|
|
for (pBuddy = level.m_HeadSentient[m_Team]; pBuddy; pBuddy = pBuddy->m_NextSentient) {
|
|
|
|
if (pBuddy != this && pBuddy->IsSubclassOfActor()) {
|
2023-10-16 00:29:41 +02:00
|
|
|
Actor *actor = static_cast<Actor *>(pBuddy);
|
2023-10-14 21:21:45 +02:00
|
|
|
actor->NotifySquadmateKilled(this, sent);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventBeDead
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Become dead.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventBeDead(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
health = 0;
|
2023-10-11 22:49:06 +02:00
|
|
|
DispatchEventKilled(ev, false);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::DeathEmbalm
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
preps the dead actor for turning nonsolid gradually over time
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::DeathEmbalm(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
if (maxs.z > 8) {
|
|
|
|
maxs.z -= 4;
|
|
|
|
|
|
|
|
if (maxs.z > 8) {
|
|
|
|
PostEvent(EV_Actor_DeathEmbalm, 0.5f);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-14 21:21:45 +02:00
|
|
|
maxs.z = 8.0;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
setSize(mins, maxs);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::DeathSinkStart
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Makes the actor sink into the ground and then get removed(this starts it).
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::DeathSinkStart(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
setMoveType(MOVETYPE_NONE);
|
2023-10-14 21:21:45 +02:00
|
|
|
flags &= ~FL_THINK;
|
2023-10-11 22:49:06 +02:00
|
|
|
Entity::DeathSinkStart(ev);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-14 21:21:45 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::FireWeapon
|
|
|
|
|
|
|
|
Fire weapon from script.
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void Actor::FireWeapon(Event *ev)
|
|
|
|
{
|
|
|
|
if (ev->NumArgs() > 0 && ev->GetInteger(1) == WEAPON_OFFHAND) {
|
|
|
|
// shoot using off hand
|
|
|
|
Sentient::FireWeapon(WEAPON_OFFHAND, FIRE_PRIMARY);
|
|
|
|
} else {
|
|
|
|
Sentient::FireWeapon(WEAPON_MAIN, FIRE_PRIMARY);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PlayAnimation
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Play animation
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::PlayAnimation(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
Event event(EV_Listener_ExecuteScript, 2);
|
|
|
|
event.AddConstString(STRING_GLOBAL_ANIM_SCR);
|
|
|
|
event.AddValue(ev->GetValue(1));
|
|
|
|
ExecuteScript(&event);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PlayScriptedAnimation
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Play scripted animation
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::PlayScriptedAnimation(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
Event event(EV_Listener_ExecuteScript, 2);
|
|
|
|
event.AddConstString(STRING_GLOBAL_ANIM_SCRIPTED_SCR);
|
|
|
|
event.AddValue(ev->GetValue(1));
|
|
|
|
ExecuteScript(&event);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PlayNoclipAnimation
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Play noclip animation
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::PlayNoclipAnimation(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
Event event(EV_Listener_ExecuteScript, 2);
|
|
|
|
event.AddConstString(STRING_GLOBAL_ANIM_NOCLIP_SCR);
|
|
|
|
event.AddValue(ev->GetValue(1));
|
|
|
|
ExecuteScript(&event);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 19:21:41 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::PlayAttachedAnimation
|
|
|
|
|
|
|
|
Play attached animation
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void Actor::PlayAttachedAnimation(Event *ev)
|
|
|
|
{
|
2023-10-14 21:21:45 +02:00
|
|
|
Event event(EV_Listener_ExecuteScript, 2);
|
|
|
|
event.AddConstString(STRING_GLOBAL_ANIM_ATTACHED_SCR);
|
|
|
|
event.AddValue(ev->GetValue(1));
|
|
|
|
ExecuteScript(&event);
|
2023-10-12 19:21:41 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::MoveDest
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Play noclip animation
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::MoveDest(float fMoveSpeed)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
mmove_t mm;
|
2023-10-12 18:19:22 +02:00
|
|
|
vec2_t offset;
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetMoveInfo(&mm);
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
mm.desired_speed = fMoveSpeed;
|
2023-10-14 21:21:45 +02:00
|
|
|
if (mm.desired_speed > m_maxspeed) {
|
|
|
|
mm.desired_speed = m_maxspeed;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
VectorSub2D(m_Dest, origin, offset);
|
2023-10-14 21:21:45 +02:00
|
|
|
VectorNormalize2D(offset);
|
|
|
|
VectorCopy2D(offset, mm.desired_dir);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
MmoveSingle(&mm);
|
|
|
|
|
|
|
|
GetMoveInfo(&mm);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::MovePath
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Move on path.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::MovePath(float fMoveSpeed)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
mmove_t mm;
|
|
|
|
const float *dir;
|
|
|
|
vec2_t delta;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
SetMoveInfo(&mm);
|
|
|
|
|
|
|
|
mm.desired_speed = fMoveSpeed;
|
2023-10-12 18:19:22 +02:00
|
|
|
if (mm.desired_speed > m_maxspeed) {
|
2023-10-11 22:49:06 +02:00
|
|
|
mm.desired_speed = m_maxspeed;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_Path.UpdatePos(origin);
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ai_debugpath->integer) {
|
2023-10-16 00:29:41 +02:00
|
|
|
Vector pos, dest;
|
|
|
|
PathInfo *current_path;
|
2023-10-15 14:01:13 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
pos = origin;
|
|
|
|
pos.z += 32;
|
2023-10-15 14:01:13 +02:00
|
|
|
|
2023-10-23 18:58:16 +02:00
|
|
|
VectorAdd2D(origin, m_Path.CurrentDelta(), dest);
|
|
|
|
dest[2] = origin[2] + 32;
|
2023-10-15 14:01:13 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
G_DebugLine(pos, dest, 1, 0, 0, 1);
|
2023-10-15 14:01:13 +02:00
|
|
|
|
2023-10-22 21:15:58 +02:00
|
|
|
for (current_path = m_Path.CurrentNode(); current_path != m_Path.LastNode(); current_path--) {
|
2023-10-23 11:59:06 +02:00
|
|
|
pos = current_path->point;
|
2023-10-22 21:15:58 +02:00
|
|
|
dest = (current_path - 1)->point;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 14:01:13 +02:00
|
|
|
G_DebugLine(pos + Vector(0, 0, 32), dest + Vector(0, 0, 32), 0, 1, 0, 1);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorCopy2D(m_Path.CurrentDelta(), mm.desired_dir);
|
|
|
|
MmoveSingle(&mm);
|
2023-10-15 14:01:13 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!mm.hit_obstacle) {
|
|
|
|
if (m_WallDir) {
|
|
|
|
if (level.inttime >= m_iWallDodgeTimeout) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_WallDir = 0;
|
2023-10-15 14:01:13 +02:00
|
|
|
} else if (DotProduct2D(mm.desired_dir, m_PrevObstacleNormal) > 0 && CrossProduct2D(mm.desired_dir, m_PrevObstacleNormal) < 0) {
|
|
|
|
m_iWallDodgeTimeout = level.inttime + 1000;
|
2023-10-16 00:29:41 +02:00
|
|
|
m_WallDir = -m_WallDir;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
GetMoveInfo(&mm);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
velocity.copyTo(mm.velocity);
|
|
|
|
origin.copyTo(mm.origin);
|
|
|
|
mm.groundPlane = m_groundPlane;
|
2023-10-12 18:19:22 +02:00
|
|
|
mm.walking = m_walking;
|
2023-10-14 14:08:52 +02:00
|
|
|
VectorCopy(m_groundPlaneNormal, mm.groundPlaneNormal);
|
2023-10-11 22:49:06 +02:00
|
|
|
VectorCopy2D(mm.obstacle_normal, m_PrevObstacleNormal);
|
|
|
|
|
|
|
|
m_Path.UpdatePos(mm.hit_origin);
|
|
|
|
|
2023-10-15 14:01:13 +02:00
|
|
|
if (m_Path.NextNode() && m_Path.IsAccurate()) {
|
|
|
|
dir = m_Path.CurrentPathDir();
|
|
|
|
|
|
|
|
m_iWallDodgeTimeout = level.inttime + 1000;
|
|
|
|
VectorSub2D(m_Path.NextNode()->point, mm.hit_origin, delta);
|
|
|
|
|
|
|
|
if (delta[0] * dir[1] > delta[1] * dir[0]) {
|
2023-10-16 00:29:41 +02:00
|
|
|
m_WallDir = -1;
|
2023-10-15 14:01:13 +02:00
|
|
|
mm.desired_dir[0] = -mm.obstacle_normal[1];
|
|
|
|
mm.desired_dir[1] = mm.obstacle_normal[0];
|
2023-10-16 00:29:41 +02:00
|
|
|
} else {
|
2023-10-15 14:01:13 +02:00
|
|
|
mm.desired_dir[0] = mm.obstacle_normal[1];
|
|
|
|
mm.desired_dir[1] = -mm.obstacle_normal[0];
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-15 14:01:13 +02:00
|
|
|
MmoveSingle(&mm);
|
|
|
|
|
|
|
|
if (!mm.hit_obstacle) {
|
2023-10-11 22:49:06 +02:00
|
|
|
GetMoveInfo(&mm);
|
|
|
|
return;
|
2023-10-15 14:01:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
velocity.copyTo(mm.velocity);
|
|
|
|
origin.copyTo(mm.origin);
|
|
|
|
|
|
|
|
mm.groundPlane = m_groundPlane;
|
2023-10-16 00:29:41 +02:00
|
|
|
mm.walking = m_walking;
|
2023-10-15 14:01:13 +02:00
|
|
|
VectorCopy(m_groundPlaneNormal, mm.groundPlaneNormal);
|
|
|
|
VectorCopy2D(mm.obstacle_normal, m_PrevObstacleNormal);
|
|
|
|
|
2024-06-07 20:34:13 +02:00
|
|
|
if (m_WallDir == (char)-1) {
|
2023-10-15 14:01:13 +02:00
|
|
|
mm.desired_dir[0] = -mm.obstacle_normal[1];
|
|
|
|
mm.desired_dir[1] = mm.obstacle_normal[0];
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-15 14:01:13 +02:00
|
|
|
mm.desired_dir[0] = mm.obstacle_normal[1];
|
|
|
|
mm.desired_dir[1] = -mm.obstacle_normal[0];
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 14:01:13 +02:00
|
|
|
MmoveSingle(&mm);
|
|
|
|
GetMoveInfo(&mm);
|
|
|
|
} else {
|
|
|
|
if (m_Path.NextNode() && !m_Path.IsAccurate() && m_WallDir == 0) {
|
|
|
|
dir = m_Path.CurrentPathDir();
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 14:01:13 +02:00
|
|
|
VectorSub2D(m_Path.NextNode()->point, mm.hit_origin, delta);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 14:01:13 +02:00
|
|
|
if (DotProduct2D(dir, delta) >= 0) {
|
|
|
|
float cross = CrossProduct2D(dir, delta);
|
|
|
|
if (cross <= -16) {
|
2023-10-11 22:49:06 +02:00
|
|
|
mm.desired_dir[0] = -mm.obstacle_normal[1];
|
2023-10-15 14:01:13 +02:00
|
|
|
mm.desired_dir[1] = mm.obstacle_normal[0];
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
MmoveSingle(&mm);
|
|
|
|
GetMoveInfo(&mm);
|
|
|
|
return;
|
2023-10-15 14:01:13 +02:00
|
|
|
|
|
|
|
} else if (cross >= 16) {
|
2023-10-11 22:49:06 +02:00
|
|
|
mm.desired_dir[0] = mm.obstacle_normal[1];
|
|
|
|
mm.desired_dir[1] = -mm.obstacle_normal[0];
|
2023-10-15 14:01:13 +02:00
|
|
|
|
|
|
|
MmoveSingle(&mm);
|
|
|
|
GetMoveInfo(&mm);
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-15 14:01:13 +02:00
|
|
|
if (m_WallDir == 0) {
|
|
|
|
dir = m_Path.CurrentPathDir();
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 14:01:13 +02:00
|
|
|
if (m_Path.NextNode()) {
|
|
|
|
dir = m_Path.NextNode()->dir;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 14:01:13 +02:00
|
|
|
if (dir[0] * mm.obstacle_normal[1] > dir[1] * mm.obstacle_normal[0]) {
|
2023-10-16 00:29:41 +02:00
|
|
|
m_WallDir = 1;
|
2023-10-15 14:01:13 +02:00
|
|
|
mm.desired_dir[0] = mm.obstacle_normal[1];
|
|
|
|
mm.desired_dir[1] = -mm.obstacle_normal[0];
|
2023-10-16 00:29:41 +02:00
|
|
|
} else {
|
|
|
|
m_WallDir = -1;
|
2023-10-11 22:49:06 +02:00
|
|
|
mm.desired_dir[0] = -mm.obstacle_normal[1];
|
|
|
|
mm.desired_dir[1] = mm.obstacle_normal[0];
|
2023-10-15 14:01:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
MmoveSingle(&mm);
|
|
|
|
if (mm.hit_obstacle) {
|
2023-10-16 00:29:41 +02:00
|
|
|
m_WallDir = 0;
|
2023-10-15 14:01:13 +02:00
|
|
|
m_iWallDodgeTimeout = 0;
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-15 14:01:13 +02:00
|
|
|
m_iWallDodgeTimeout = level.inttime + 1000;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (m_WallDir >= 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
mm.desired_dir[0] = mm.obstacle_normal[1];
|
|
|
|
mm.desired_dir[1] = -mm.obstacle_normal[0];
|
2023-10-15 14:01:13 +02:00
|
|
|
} else {
|
|
|
|
mm.desired_dir[0] = -mm.obstacle_normal[1];
|
|
|
|
mm.desired_dir[1] = mm.obstacle_normal[0];
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-15 14:01:13 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
MmoveSingle(&mm);
|
2023-10-15 14:01:13 +02:00
|
|
|
|
|
|
|
if (mm.hit_obstacle) {
|
2023-10-16 00:29:41 +02:00
|
|
|
m_WallDir = 0;
|
2023-10-15 14:01:13 +02:00
|
|
|
m_iWallDodgeTimeout = 0;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2024-02-13 17:37:28 +01:00
|
|
|
|
|
|
|
GetMoveInfo(&mm);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::MovePathGoal
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Move on path end(goal).
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::MovePathGoal(float fMoveSpeed)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
vec2_t vDelta;
|
2023-10-16 00:29:41 +02:00
|
|
|
float fSlowdownSpeed;
|
|
|
|
float fTimeToGo;
|
|
|
|
float fDeltaSquareLen;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!m_Path.HasCompleteLookahead()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
MovePath(fMoveSpeed);
|
|
|
|
m_fPathGoalTime = 0;
|
|
|
|
return;
|
|
|
|
}
|
2023-10-15 14:01:13 +02:00
|
|
|
|
|
|
|
VectorSub2D(origin, m_Path.CurrentPathGoal(), vDelta);
|
|
|
|
fDeltaSquareLen = VectorLength2DSquared(vDelta);
|
2023-10-16 00:29:41 +02:00
|
|
|
fTimeToGo = m_fPathGoalTime - level.time;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 14:01:13 +02:00
|
|
|
if (fTimeToGo > -0.001f) {
|
|
|
|
fSlowdownSpeed = sqrt(fDeltaSquareLen) * (2.f / (fTimeToGo + level.frametime));
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 14:01:13 +02:00
|
|
|
if (fSlowdownSpeed > (fMoveSpeed + 0.001f) && fSlowdownSpeed > sv_runspeed->value * 0.4f) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fPathGoalTime = 0;
|
2023-10-15 14:01:48 +02:00
|
|
|
StartAnimation(ANIM_MODE_PATH_GOAL, m_Anim);
|
2023-10-15 14:01:13 +02:00
|
|
|
MovePath(fMoveSpeed);
|
|
|
|
} else {
|
|
|
|
MovePath(fSlowdownSpeed);
|
|
|
|
if (level.time >= m_fPathGoalTime) {
|
|
|
|
m_eAnimMode = ANIM_MODE_NORMAL;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2024-08-30 00:39:45 +02:00
|
|
|
} else if (fDeltaSquareLen < Square(fMoveSpeed * 0.5 * 0.5)) {
|
2023-10-16 00:29:41 +02:00
|
|
|
fTimeToGo = 0.5f;
|
2023-10-15 14:01:13 +02:00
|
|
|
m_fPathGoalTime = level.time + fTimeToGo;
|
|
|
|
if (m_csPathGoalEndAnimScript == STRING_EMPTY) {
|
|
|
|
m_csPathGoalEndAnimScript = STRING_ANIM_IDLE_SCR;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-15 14:01:13 +02:00
|
|
|
m_bStartPathGoalEndAnim = true;
|
|
|
|
} else {
|
|
|
|
MovePath(fMoveSpeed);
|
|
|
|
m_fPathGoalTime = 0;
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::Dumb
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Make actor dumb.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::Dumb(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-15 14:03:44 +02:00
|
|
|
Event event(EV_Listener_ExecuteScript);
|
|
|
|
event.AddConstString(STRING_GLOBAL_DISABLE_AI_SCR);
|
|
|
|
ExecuteScript(&event);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PhysicsOn
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-15 14:03:44 +02:00
|
|
|
Disable PhysicsOff.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-15 14:03:44 +02:00
|
|
|
void Actor::PhysicsOff(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-15 14:03:44 +02:00
|
|
|
m_bDoPhysics = false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PhysicsOn
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-15 14:03:44 +02:00
|
|
|
Enable physics.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-15 14:03:44 +02:00
|
|
|
void Actor::PhysicsOn(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-15 14:03:44 +02:00
|
|
|
m_bDoPhysics = true;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventGetMood
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Get current mood.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetMood(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddConstString(m_csMood);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetMood
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set current mood.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetMood(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_csMood = ev->GetConstString(1);
|
2023-10-16 00:29:41 +02:00
|
|
|
if (m_csMood != STRING_BORED && m_csMood != STRING_NERVOUS && m_csMood != STRING_CURIOUS
|
|
|
|
&& m_csMood != STRING_ALERT) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_csMood = STRING_BORED;
|
|
|
|
ScriptError("invalid mood - setting to bored");
|
|
|
|
}
|
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventDamagePuff
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-19 10:52:47 +02:00
|
|
|
Spawns a puff of 'blood' smoke at the specified location in the specified direction.
|
2023-10-11 22:49:06 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventDamagePuff(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 23:17:09 +02:00
|
|
|
Vector pos = ev->GetVector(1);
|
|
|
|
Vector dir = ev->GetVector(2);
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
gi.SetBroadcastVisible(pos, NULL);
|
2023-10-12 23:17:09 +02:00
|
|
|
|
|
|
|
gi.MSG_StartCGM(BG_MapCGMToProtocol(g_protocol, CGM_BULLET_8));
|
2023-10-11 22:49:06 +02:00
|
|
|
gi.MSG_WriteCoord(pos.x);
|
|
|
|
gi.MSG_WriteCoord(pos.y);
|
|
|
|
gi.MSG_WriteCoord(pos.z);
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
gi.MSG_WriteDir(dir);
|
|
|
|
gi.MSG_WriteBits(0, 1);
|
|
|
|
gi.MSG_EndCGM();
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventGetAngleYawSpeed
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Get current AngleYawSpeed.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetAngleYawSpeed(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddFloat(m_fAngleYawSpeed);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetAngleYawSpeed
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set current AngleYawSpeed.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetAngleYawSpeed(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
float speed = ev->GetFloat(1);
|
2023-10-12 18:19:22 +02:00
|
|
|
if (speed <= 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("Attempting to set illegal turnspeed %f", speed);
|
|
|
|
}
|
|
|
|
m_fAngleYawSpeed = speed;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetAimTarget
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set current weapon's aim tagret.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetAimTarget(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
Entity *ent;
|
|
|
|
Weapon *weap;
|
2023-10-15 15:08:01 +02:00
|
|
|
|
|
|
|
ent = ev->GetEntity(1);
|
|
|
|
if (!ent) {
|
|
|
|
// Added in 2.0
|
|
|
|
// Check for NULL
|
|
|
|
ScriptError("EventSetAimTarget::NULL entity given as first argument.");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
weap = GetActiveWeapon(WEAPON_MAIN);
|
|
|
|
weap->SetAimTarget(ent);
|
|
|
|
|
|
|
|
// Added in 2.0
|
|
|
|
// Make the ent an enemy
|
|
|
|
if (ev->NumArgs() > 1 && ev->GetInteger(2) == 1 && ent->IsSubclassOfSentient()) {
|
2023-10-16 00:29:41 +02:00
|
|
|
SetEnemy(static_cast<Sentient *>(ent), false);
|
2023-10-15 15:08:01 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ReadyToFire
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if weapon is ready to fire.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ReadyToFire(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
Weapon *weap = GetActiveWeapon(WEAPON_MAIN);
|
2023-10-15 15:08:01 +02:00
|
|
|
if (weap) {
|
|
|
|
ev->AddInteger(weap->ReadyToFire(FIRE_PRIMARY, true));
|
|
|
|
} else {
|
|
|
|
ev->AddInteger(0);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventGetSight
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Return current sight (vision distance).
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetSight(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddFloat(m_fSight);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetSight
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set current sight (vision distance).
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetSight(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fSight = ev->GetFloat(1);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventGetHearing
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Get current hearing distance.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetHearing(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddFloat(m_fHearing);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetHearing
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set current hearing distance.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetHearing(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fHearing = ev->GetFloat(1);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventGetFov
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Get current fov.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetFov(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddFloat(m_fFov);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetFov
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set current fov.
|
|
|
|
============
|
2018-09-17 23:50:38 +02:00
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetFov(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
float fov = ev->GetFloat(1);
|
2023-10-12 18:19:22 +02:00
|
|
|
if (fov < 0 || fov > 360) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("fov must be in the range [0,360]");
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
m_fFov = fov;
|
2023-10-15 15:08:01 +02:00
|
|
|
m_fFovDot = cos(fov * 0.5f * M_PI / 180.0);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ClearPatrolCurrentNode
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Clear current patrol node.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ClearPatrolCurrentNode(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_patrolCurrentNode) {
|
|
|
|
if (m_patrolCurrentNode->IsSubclassOfTempWaypoint()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
delete m_patrolCurrentNode;
|
|
|
|
}
|
|
|
|
m_patrolCurrentNode = NULL;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::NextPatrolCurrentNode
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Switch to next patrol node.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::NextPatrolCurrentNode(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_bScriptGoalValid) {
|
|
|
|
if (m_patrolCurrentNode->origin == m_vScriptGoal) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bScriptGoalValid = false;
|
|
|
|
}
|
|
|
|
}
|
2023-10-15 15:08:01 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_patrolCurrentNode->IsSubclassOfTempWaypoint()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearPatrolCurrentNode();
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_patrolCurrentNode = m_patrolCurrentNode->Next();
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::SetPatrolCurrentNode
|
|
|
|
|
|
|
|
Set current patrol node.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetPatrolCurrentNode(Vector& vec)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearPatrolCurrentNode();
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
m_patrolCurrentNode = new TempWaypoint();
|
2023-10-11 22:49:06 +02:00
|
|
|
m_patrolCurrentNode->setOrigin(vec);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::SetPatrolCurrentNode
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set current patrol node.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetPatrolCurrentNode(Listener *l)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearPatrolCurrentNode();
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
if (l && !l->isSubclassOf(SimpleEntity)) {
|
2023-10-12 18:19:22 +02:00
|
|
|
ScriptError(
|
|
|
|
"Bad patrol path with classname '%s' specified for '%s' at (%f %f %f)\n",
|
2023-10-11 22:49:06 +02:00
|
|
|
l->getClassname(),
|
|
|
|
targetname.c_str(),
|
|
|
|
origin.x,
|
|
|
|
origin.y,
|
|
|
|
origin.z
|
2023-10-12 18:19:22 +02:00
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_patrolCurrentNode = static_cast<SimpleEntity *>(l);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetPatrolPath
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set current patrol path.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetPatrolPath(Event *ev)
|
2018-08-19 08:26:59 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
SetPatrolCurrentNode(ev->GetListener(1));
|
2018-08-19 08:26:59 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventGetPatrolPath
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Get current patrol path.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetPatrolPath(Event *ev)
|
2018-08-19 08:26:59 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddListener(m_patrolCurrentNode);
|
2018-08-19 08:26:59 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetPatrolWaitTrigger
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set m_bPatrolWaitTrigger.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetPatrolWaitTrigger(Event *ev)
|
2018-08-19 08:26:59 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bPatrolWaitTrigger = ev->GetBoolean(1);
|
2018-08-19 08:26:59 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventGetPatrolWaitTrigger
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Get m_bPatrolWaitTrigger.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetPatrolWaitTrigger(Event *ev)
|
2018-08-19 08:26:59 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddInteger(m_bPatrolWaitTrigger);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ShowInfo_PatrolCurrentNode
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Show current patrol node info.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ShowInfo_PatrolCurrentNode(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_patrolCurrentNode) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Com_Printf("current patrol node: %s\n", m_patrolCurrentNode->targetname.c_str());
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
Com_Printf("no current patrol node\n");
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ShowInfo_AimNode
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Show current aim node info.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ShowInfo_AimNode(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_aimNode) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Com_Printf("aim node: %s\n", m_aimNode->targetname.c_str());
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
Com_Printf("no current aim node\n");
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::MoveOnPathWithSquad
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Move on path with squad.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::MoveOnPathWithSquad(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
const float *pvMyDir, *pvHisDir;
|
|
|
|
vec2_t vDelta;
|
|
|
|
Sentient *pSquadMate;
|
|
|
|
float fIntervalSquared;
|
|
|
|
vec2_t vMyNormalDir;
|
|
|
|
float fDistSquared;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
if (level.inttime < m_iSquadStandTime + 500) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
|
|
|
}
|
2023-10-15 15:08:01 +02:00
|
|
|
|
|
|
|
if (!PathExists() || PathComplete()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
pvMyDir = PathDelta();
|
2023-10-11 22:49:06 +02:00
|
|
|
fIntervalSquared = Square(m_fInterval);
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_iSquadStandTime) {
|
2023-10-11 22:49:06 +02:00
|
|
|
fIntervalSquared *= 2;
|
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
pSquadMate = static_cast<Sentient *>(G_GetEntity(0));
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
if (IsTeamMate(pSquadMate)) {
|
|
|
|
VectorSub2D(pSquadMate->origin, origin, vDelta);
|
2023-10-11 22:49:06 +02:00
|
|
|
fDistSquared = VectorLength2DSquared(vDelta);
|
2023-10-15 15:08:01 +02:00
|
|
|
|
|
|
|
if (fIntervalSquared > fDistSquared && DotProduct2D(vDelta, pvMyDir) > 0) {
|
|
|
|
VectorSub2D(velocity, pSquadMate->velocity, vMyNormalDir);
|
2023-10-11 22:49:06 +02:00
|
|
|
VectorNormalize2D(vMyNormalDir);
|
2023-10-15 15:08:01 +02:00
|
|
|
|
|
|
|
if (fDistSquared - DotProduct2D(vDelta, vMyNormalDir) < Square(48)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iSquadStandTime = level.inttime;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
for (pSquadMate = m_pNextSquadMate; pSquadMate != this; pSquadMate = pSquadMate->m_pNextSquadMate) {
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!pSquadMate->IsSubclassOfActor()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
continue;
|
|
|
|
}
|
2023-10-15 15:08:01 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
Actor *pActorSquadMate = static_cast<Actor *>(pSquadMate);
|
2023-10-15 15:08:01 +02:00
|
|
|
|
|
|
|
VectorSub2D(pActorSquadMate->origin, origin, vDelta);
|
2023-10-11 22:49:06 +02:00
|
|
|
fDistSquared = VectorLength2DSquared(vDelta);
|
2023-10-15 15:08:01 +02:00
|
|
|
|
|
|
|
if (fDistSquared >= fIntervalSquared || DotProduct2D(vDelta, pvMyDir) <= 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
continue;
|
|
|
|
}
|
2023-10-15 15:08:01 +02:00
|
|
|
|
|
|
|
if (!pActorSquadMate->PathExists() || pActorSquadMate->PathComplete()) {
|
|
|
|
pvHisDir = pActorSquadMate->velocity;
|
|
|
|
|
|
|
|
if (VectorLength2DSquared(pvHisDir) <= 8) {
|
2023-10-11 22:49:06 +02:00
|
|
|
continue;
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-15 15:08:01 +02:00
|
|
|
pvHisDir = pActorSquadMate->PathDelta();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
if (DotProduct2D(pvMyDir, pvHisDir) >= 0
|
2024-08-26 23:55:45 +02:00
|
|
|
&& (entnum >= pActorSquadMate->entnum || DotProduct2D(pvHisDir, vDelta) >= 0)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iSquadStandTime = level.inttime;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
2023-10-15 15:08:01 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iSquadStandTime = 0;
|
|
|
|
return true;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::MoveToWaypointWithPlayer
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Move to waypoint with player.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::MoveToWaypointWithPlayer(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
vec2_t pvMyDir;
|
|
|
|
vec2_t vDelta;
|
|
|
|
float fIntervalSquared;
|
|
|
|
vec2_t vMyNormalDir;
|
|
|
|
float fDistSquared;
|
|
|
|
Sentient *pSquadMate;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (level.inttime < m_iSquadStandTime + 500) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
fIntervalSquared = Square(m_fInterval);
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_iSquadStandTime) {
|
2023-10-11 22:49:06 +02:00
|
|
|
fIntervalSquared += fIntervalSquared;
|
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
pSquadMate = static_cast<Sentient *>(G_GetEntity(0));
|
2023-10-15 15:08:01 +02:00
|
|
|
if (!IsTeamMate(pSquadMate)) {
|
|
|
|
return true;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
VectorSub2D(pSquadMate->origin, origin, vDelta);
|
2023-10-15 15:08:01 +02:00
|
|
|
fDistSquared = VectorLength2DSquared(vDelta);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
if (fDistSquared >= fIntervalSquared) {
|
|
|
|
m_iSquadStandTime = 0;
|
|
|
|
return true;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
VectorSub2D(m_patrolCurrentNode->origin, origin, pvMyDir);
|
|
|
|
if (DotProduct2D(vDelta, pvMyDir) <= 0) {
|
|
|
|
m_iSquadStandTime = 0;
|
|
|
|
return true;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
VectorSub2D(velocity, pSquadMate->velocity, vMyNormalDir);
|
|
|
|
VectorNormalize2D(vMyNormalDir);
|
|
|
|
|
|
|
|
if (fDistSquared - DotProduct2D(vDelta, vMyNormalDir) >= Square(48)) {
|
|
|
|
m_iSquadStandTime = 0;
|
|
|
|
return true;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-15 15:08:01 +02:00
|
|
|
|
|
|
|
m_iSquadStandTime = level.inttime;
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PatrolNextNodeExists
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if next patrol node exits.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::PatrolNextNodeExists(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-15 15:08:01 +02:00
|
|
|
if (!m_patrolCurrentNode) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_patrolCurrentNode->IsSubclassOfTempWaypoint()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_patrolCurrentNode->Next()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::UpdatePatrolCurrentNode
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Update current patrol node.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::UpdatePatrolCurrentNode(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-15 15:08:01 +02:00
|
|
|
if (!m_patrolCurrentNode) {
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-15 15:08:01 +02:00
|
|
|
|
|
|
|
if (m_patrolCurrentNode->IsSubclassOfWaypoint()) {
|
|
|
|
vec2_t delta;
|
|
|
|
VectorSub2D(origin, m_patrolCurrentNode->origin, delta);
|
|
|
|
|
|
|
|
if (fabs(delta[0]) < 16.0 && fabs(delta[1]) < 16.0) {
|
|
|
|
NextPatrolCurrentNode();
|
|
|
|
}
|
|
|
|
} else if (PathExists() && PathComplete()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
NextPatrolCurrentNode();
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::MoveToPatrolCurrentNode
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::MoveToPatrolCurrentNode(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
UpdatePatrolCurrentNode();
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-23 15:55:58 +02:00
|
|
|
if (!m_patrolCurrentNode || m_bPatrolWaitTrigger) {
|
2023-10-15 15:08:01 +02:00
|
|
|
IdleLook();
|
|
|
|
Anim_Idle();
|
|
|
|
return false;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
if (m_patrolCurrentNode->IsSubclassOfWaypoint()) {
|
|
|
|
if (MoveToWaypointWithPlayer()) {
|
|
|
|
DesiredAnimation(ANIM_MODE_DEST, m_csPatrolCurrentAnim);
|
|
|
|
FaceMotion();
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-15 15:08:01 +02:00
|
|
|
Anim_Stand();
|
|
|
|
IdleLook();
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
SetDest(m_patrolCurrentNode->origin);
|
|
|
|
|
|
|
|
if (!m_fMoveDoneRadiusSquared || m_patrolCurrentNode->Next()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
vec2_t delta;
|
|
|
|
VectorSub2D(m_patrolCurrentNode->origin, origin, delta);
|
|
|
|
return VectorLength2DSquared(delta) <= m_fMoveDoneRadiusSquared;
|
2023-10-16 00:29:41 +02:00
|
|
|
} else {
|
2023-10-15 15:08:01 +02:00
|
|
|
SetPath(m_patrolCurrentNode->origin, "Actor::MoveToPatrolCurrentNode", 0, NULL, 0);
|
2023-10-16 00:29:41 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
if (!PathExists()) {
|
|
|
|
IdleLook();
|
|
|
|
Anim_Idle();
|
|
|
|
// tell scripts the move has failed
|
|
|
|
parm.movefail = qtrue;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (MoveOnPathWithSquad()) {
|
|
|
|
if (PatrolNextNodeExists()) {
|
|
|
|
DesiredAnimation(ANIM_MODE_PATH, m_csPatrolCurrentAnim);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-15 15:08:01 +02:00
|
|
|
DesiredAnimation(ANIM_MODE_PATH_GOAL, m_csPatrolCurrentAnim);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
FaceMotion();
|
|
|
|
} else {
|
|
|
|
Anim_Stand();
|
|
|
|
IdleLook();
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
if (!m_fMoveDoneRadiusSquared) {
|
|
|
|
return false;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
if (PathComplete()) {
|
|
|
|
return true;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
if (!m_Path.HasCompleteLookahead()) {
|
|
|
|
return false;
|
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
if (m_patrolCurrentNode->Next()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-10-15 17:50:28 +02:00
|
|
|
const float *delta = PathDelta();
|
2023-10-15 15:08:01 +02:00
|
|
|
return VectorLength2DSquared(delta) <= m_fMoveDoneRadiusSquared;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetAccuracy
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set current accuracy.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetAccuracy(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-15 15:08:01 +02:00
|
|
|
mAccuracy = ev->GetFloat(1) / 100.f;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventGetAccuracy
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Get current accuracy.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetAccuracy(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-15 15:08:01 +02:00
|
|
|
ev->AddFloat(mAccuracy * 100.f);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetMinDistance
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetMinDistance(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fMinDistance = ev->GetFloat(1);
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_fMinDistance < 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fMinDistance = 0;
|
|
|
|
Com_Printf(
|
|
|
|
"^~^~^ Warning: mindist negative, forcing to %g for entity %i, targetname '%s'\n",
|
|
|
|
m_fMinDistance,
|
|
|
|
entnum,
|
2023-10-15 15:08:01 +02:00
|
|
|
TargetName().c_str()
|
2023-10-12 18:19:22 +02:00
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-15 15:08:01 +02:00
|
|
|
|
|
|
|
m_fMinDistanceSquared = Square(m_fMinDistance);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetMinDistance
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetMinDistance(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddFloat(m_fMinDistance);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetMaxDistance
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetMaxDistance(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
m_fMaxDistance = ev->GetFloat(1);
|
2023-10-15 15:08:01 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_fMaxDistance < 256) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fMaxDistance = 256;
|
2023-10-15 15:08:01 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Com_Printf(
|
|
|
|
"^~^~^ Warning: maxdist too small, forcing to %g for entity %i, targetname '%s'\n",
|
|
|
|
m_fMaxDistance,
|
|
|
|
entnum,
|
2023-10-12 18:19:22 +02:00
|
|
|
targetname.c_str()
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-15 15:08:01 +02:00
|
|
|
|
|
|
|
m_fMaxDistanceSquared = Square(m_fMaxDistance);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetMaxDistance
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetMaxDistance(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddFloat(m_fMaxDistance);
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetLeash
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetLeash(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddFloat(m_fLeash);
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetLeash
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetLeash(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
m_fLeash = ev->GetFloat(1);
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fLeashSquared = Square(m_fLeash);
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetInterval
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetInterval(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddFloat(m_fInterval);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetInterval
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetInterval(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
m_fInterval = ev->GetFloat(1);
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventDistToEnemy
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventDistToEnemy(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-15 15:08:01 +02:00
|
|
|
if (!m_Enemy) {
|
|
|
|
ev->AddFloat(0);
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-15 15:08:01 +02:00
|
|
|
|
|
|
|
ev->AddFloat((origin - m_Enemy->origin).length());
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::Init
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Initialize global actor variables.
|
|
|
|
Called from G_InitGame()
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::Init(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
g_showinfo = gi.Cvar_Get("g_showinfo", "0", 0);
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
for (int i = 0; i < NUM_THINKS; i++) {
|
|
|
|
GlobalFuncs[i].ThinkState = NULL;
|
|
|
|
GlobalFuncs[i].BeginState = NULL;
|
|
|
|
GlobalFuncs[i].ResumeState = NULL;
|
|
|
|
GlobalFuncs[i].EndState = NULL;
|
|
|
|
GlobalFuncs[i].SuspendState = NULL;
|
|
|
|
GlobalFuncs[i].RestartState = &Actor::DefaultRestart;
|
|
|
|
GlobalFuncs[i].FinishedAnimation = NULL;
|
|
|
|
GlobalFuncs[i].PostShoot = NULL;
|
|
|
|
GlobalFuncs[i].Pain = &Actor::DefaultPain;
|
|
|
|
GlobalFuncs[i].Killed = &Actor::DefaultKilled;
|
2023-10-11 22:49:06 +02:00
|
|
|
GlobalFuncs[i].PassesTransitionConditions = NULL;
|
2023-10-12 18:19:22 +02:00
|
|
|
GlobalFuncs[i].ShowInfo = NULL;
|
|
|
|
GlobalFuncs[i].ReceiveAIEvent = &Actor::DefaultReceiveAIEvent;
|
|
|
|
GlobalFuncs[i].IsState = NULL;
|
|
|
|
GlobalFuncs[i].PathnodeClaimRevoked = NULL;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
InitVoid(&GlobalFuncs[THINK_VOID]);
|
|
|
|
InitTurret(&GlobalFuncs[THINK_TURRET]);
|
|
|
|
InitCover(&GlobalFuncs[THINK_COVER]);
|
|
|
|
InitPatrol(&GlobalFuncs[THINK_PATROL]);
|
|
|
|
InitRunner(&GlobalFuncs[THINK_RUNNER]);
|
2023-10-14 01:06:47 +02:00
|
|
|
InitIdle(&GlobalFuncs[THINK_IDLE]);
|
2023-10-11 22:49:06 +02:00
|
|
|
InitPain(&GlobalFuncs[THINK_PAIN]);
|
|
|
|
InitKilled(&GlobalFuncs[THINK_KILLED]);
|
|
|
|
InitCurious(&GlobalFuncs[THINK_CURIOUS]);
|
2023-10-14 01:06:47 +02:00
|
|
|
InitAlarm(&GlobalFuncs[THINK_ALARM]);
|
2023-10-11 22:49:06 +02:00
|
|
|
InitDisguiseSalute(&GlobalFuncs[THINK_DISGUISE_SALUTE]);
|
|
|
|
InitDisguiseSentry(&GlobalFuncs[THINK_DISGUISE_SENTRY]);
|
|
|
|
InitDisguiseOfficer(&GlobalFuncs[THINK_DISGUISE_OFFICER]);
|
|
|
|
InitDisguiseRover(&GlobalFuncs[THINK_DISGUISE_ROVER]);
|
|
|
|
InitDisguiseNone(&GlobalFuncs[THINK_DISGUISE_NONE]);
|
|
|
|
InitGrenade(&GlobalFuncs[THINK_GRENADE]);
|
|
|
|
InitMachineGunner(&GlobalFuncs[THINK_MACHINEGUNNER]);
|
|
|
|
InitDogIdle(&GlobalFuncs[THINK_DOG_IDLE]);
|
|
|
|
InitDogAttack(&GlobalFuncs[THINK_DOG_ATTACK]);
|
|
|
|
InitDogCurious(&GlobalFuncs[THINK_DOG_CURIOUS]);
|
|
|
|
InitAnim(&GlobalFuncs[THINK_ANIM]);
|
|
|
|
InitAnimCurious(&GlobalFuncs[THINK_ANIM_CURIOUS]);
|
|
|
|
InitAim(&GlobalFuncs[THINK_AIM]);
|
|
|
|
InitBalconyIdle(&GlobalFuncs[THINK_BALCONY_IDLE]);
|
|
|
|
InitBalconyCurious(&GlobalFuncs[THINK_BALCONY_CURIOUS]);
|
|
|
|
InitBalconyAttack(&GlobalFuncs[THINK_BALCONY_ATTACK]);
|
|
|
|
InitBalconyDisguise(&GlobalFuncs[THINK_BALCONY_DISGUISE]);
|
|
|
|
InitBalconyGrenade(&GlobalFuncs[THINK_BALCONY_GRENADE]);
|
|
|
|
InitBalconyPain(&GlobalFuncs[THINK_BALCONY_PAIN]);
|
|
|
|
InitBalconyKilled(&GlobalFuncs[THINK_BALCONY_KILLED]);
|
|
|
|
InitWeaponless(&GlobalFuncs[THINK_WEAPONLESS]);
|
|
|
|
InitNoClip(&GlobalFuncs[THINK_NOCLIP]);
|
|
|
|
InitDead(&GlobalFuncs[THINK_DEAD]);
|
2024-08-26 23:55:45 +02:00
|
|
|
// Added in 2.0
|
2023-10-14 01:06:47 +02:00
|
|
|
InitBadPlace(&GlobalFuncs[THINK_BADPLACE]);
|
2024-08-26 23:55:45 +02:00
|
|
|
// Added in 2.30
|
2023-10-14 01:06:47 +02:00
|
|
|
InitRunAndShoot(&GlobalFuncs[THINK_RUN_AND_SHOOT]);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
AddWaitTill(STRING_VISIBLE);
|
|
|
|
AddWaitTill(STRING_PAIN);
|
2023-10-14 01:06:47 +02:00
|
|
|
AddWaitTill(STRING_DEATH);
|
2023-10-11 22:49:06 +02:00
|
|
|
AddWaitTill(STRING_HASENEMY);
|
2023-10-14 01:06:47 +02:00
|
|
|
AddWaitTill(STRING_FLAGGEDANIMDONE);
|
|
|
|
AddWaitTill(STRING_UPPERANIMDONE);
|
|
|
|
AddWaitTill(STRING_SAYDONE);
|
2023-10-11 22:49:06 +02:00
|
|
|
AddWaitTill(STRING_SOUNDDONE);
|
2023-10-14 01:06:47 +02:00
|
|
|
AddWaitTill(STRING_ANIMDONE);
|
|
|
|
AddWaitTill(STRING_MOVEDONE);
|
|
|
|
AddWaitTill(STRING_TRIGGER);
|
|
|
|
AddWaitTill(STRING_MOVE);
|
2023-10-11 22:49:06 +02:00
|
|
|
AddWaitTill(STRING_TURNDONE);
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (developer->integer) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Com_Printf("sizeof(Actor) == %zi\n", sizeof(Actor));
|
|
|
|
//FIXME: magic ??
|
2023-10-14 01:06:47 +02:00
|
|
|
Com_Printf("Magic sizeof actor number: %zd\n", sizeof(Actor) - 64);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::UpdateEyeOrigin
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Update eye position.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::UpdateEyeOrigin(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
Vector eyeTag = vec_zero;
|
|
|
|
|
|
|
|
int currLvlTime = level.inttime;
|
2023-10-12 18:19:22 +02:00
|
|
|
int currTime = m_iEyeUpdateTime;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (currLvlTime > currTime) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iEyeUpdateTime = NextUpdateTime(currTime, 100);
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
GetTag("eyes bone", &eyeTag, &m_vEyeDir);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
eyeposition = eyeTag - origin;
|
|
|
|
|
|
|
|
m_vEyeDir[2] = 0.0;
|
2023-10-15 15:08:01 +02:00
|
|
|
m_vEyeDir.normalizefast();
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
eyeposition[0] = Q_clamp_float(eyeposition[0], -10.5f, 10.5f);
|
|
|
|
eyeposition[1] = Q_clamp_float(eyeposition[1], -10.5f, 10.5f);
|
|
|
|
eyeposition[2] = Q_clamp_float(eyeposition[2], 4.5f, 89.5f);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::RequireThink
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Do I need to think ?
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::RequireThink(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (G_GetEntity(0)) {
|
|
|
|
return (level.inttime < edict->r.lastNetTime + 60000);
|
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::UpdateEnemyInternal
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Real update enemy.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::UpdateEnemyInternal(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-15 15:08:01 +02:00
|
|
|
// Added in 2.0
|
|
|
|
DetectSmokeGrenades();
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
for (Sentient *pSent = level.m_HeadSentient[1 - m_Team]; pSent; pSent = pSent->m_NextSentient) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_PotentialEnemies.AddPotentialEnemy(pSent);
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
m_PotentialEnemies.CheckEnemies(this);
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2024-08-31 16:17:37 +02:00
|
|
|
if (m_Enemy != m_PotentialEnemies.GetCurrentEnemy() && (m_bEnemySwitch || !m_Enemy)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetEnemy(m_PotentialEnemies.GetCurrentEnemy(), false);
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
m_fNoticeTimeScale += (level.inttime - m_iEnemyCheckTime) / 10000.f;
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_fNoticeTimeScale > m_fMaxNoticeTimeScale) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fNoticeTimeScale = m_fMaxNoticeTimeScale;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iEnemyCheckTime = level.inttime;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::UpdateEnemy
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Update enemy w.r.t m_iEnemyCheckTime.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::UpdateEnemy(int iMaxDirtyTime)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (level.inttime > iMaxDirtyTime + m_iEnemyCheckTime) {
|
2023-10-11 22:49:06 +02:00
|
|
|
UpdateEnemyInternal();
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 19:21:41 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::DetectSmokeGrenades
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void Actor::DetectSmokeGrenades(void)
|
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
SmokeSprite *sprite;
|
2023-10-15 15:08:01 +02:00
|
|
|
|
|
|
|
if (m_Enemy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
sprite = G_GetRandomSmokeSprite();
|
2023-10-18 19:59:23 +02:00
|
|
|
if (!sprite || !sprite->owner) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-15 15:08:01 +02:00
|
|
|
|
2023-10-18 19:59:23 +02:00
|
|
|
if (sprite->owner->m_Team != m_Team) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-10-23 11:59:06 +02:00
|
|
|
const Vector eyePos = VirtualEyePosition();
|
|
|
|
const float fDistSquared = (sprite->origin - eyePos).lengthSquared();
|
2023-10-18 19:59:23 +02:00
|
|
|
|
|
|
|
if (fDistSquared > Square(256) || InFOV(sprite->origin)) {
|
|
|
|
if (G_SightTrace(
|
2023-10-23 11:59:06 +02:00
|
|
|
eyePos,
|
|
|
|
vec_zero,
|
|
|
|
vec_zero,
|
|
|
|
sprite->origin,
|
|
|
|
this,
|
|
|
|
NULL,
|
|
|
|
MASK_CANSEE,
|
|
|
|
qfalse,
|
|
|
|
"Actor::DetectSmokeGrenades"
|
|
|
|
)) {
|
2023-10-18 19:59:23 +02:00
|
|
|
m_PotentialEnemies.ConfirmEnemy(this, sprite->owner);
|
2023-10-15 15:08:01 +02:00
|
|
|
}
|
|
|
|
}
|
2023-10-12 19:21:41 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::SetEnemy
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set current enemy.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetEnemy(Sentient *pEnemy, bool bForceConfirmed)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (pEnemy == m_Enemy) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_Enemy) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_Enemy->m_iAttackerCount--;
|
|
|
|
}
|
|
|
|
m_bNewEnemy = m_Enemy == NULL;
|
2023-10-16 00:29:41 +02:00
|
|
|
m_Enemy = pEnemy;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
m_iEnemyChangeTime = level.inttime;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_Enemy) {
|
2023-10-15 15:08:01 +02:00
|
|
|
PostEvent(EV_Actor_ShareEnemy, 0.75f);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
m_bEnemyIsDisguised = m_Enemy->m_bHasDisguise && (m_Enemy->m_bIsDisguised || !CanSeeEnemy(0));
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
SetEnemyPos(m_Enemy->origin);
|
|
|
|
m_Enemy->m_iAttackerCount++;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (bForceConfirmed) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_PotentialEnemies.ConfirmEnemy(this, m_Enemy);
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::SetEnemyPos
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Update stored enemy position information.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetEnemyPos(Vector vPos)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-15 15:08:01 +02:00
|
|
|
if (m_vLastEnemyPos == vPos) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
m_iLastEnemyPosChangeTime = level.inttime;
|
|
|
|
m_vLastEnemyPos = vPos;
|
|
|
|
mTargetPos = m_vLastEnemyPos;
|
|
|
|
|
|
|
|
if (!m_Enemy) {
|
|
|
|
mTargetPos.z += 88;
|
|
|
|
} else if (m_Enemy->m_bIsAnimal) {
|
|
|
|
mTargetPos.z += 10;
|
|
|
|
} else {
|
|
|
|
mTargetPos += m_Enemy->eyeposition;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 15:08:01 +02:00
|
|
|
if (mTargetPos.z - EyePosition().z < 128) {
|
|
|
|
mTargetPos.z -= 16;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
static bool UnknownAnim(const char *name, dtiki_t *tiki)
|
|
|
|
{
|
|
|
|
ScriptException::next_bIsForAnim = true;
|
|
|
|
ScriptError("unknown animation '%s' in '%s'", name, tiki->a->name);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set animation event.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetAnim(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
const_str name = 0;
|
2023-10-12 18:19:22 +02:00
|
|
|
float weight = 1;
|
2023-10-16 00:29:41 +02:00
|
|
|
int slot = 0;
|
|
|
|
int anim;
|
|
|
|
const_str flagVal;
|
2023-10-22 20:16:36 +02:00
|
|
|
qboolean flagged = qfalse;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
switch (ev->NumArgs()) {
|
|
|
|
case 4:
|
2023-10-11 22:49:06 +02:00
|
|
|
flagVal = ev->GetConstString(4);
|
|
|
|
flagged = qtrue;
|
2023-10-12 18:19:22 +02:00
|
|
|
if (flagVal != STRING_FLAGGED) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("unknown keyword '%s', expected 'flagged'", Director.GetString(flagVal).c_str());
|
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
case 3:
|
2023-10-11 22:49:06 +02:00
|
|
|
weight = ev->GetFloat(3);
|
2023-10-12 18:19:22 +02:00
|
|
|
if (weight < 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("Negative anim weight not allowed");
|
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
if (!weight) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
case 2:
|
|
|
|
slot = ev->GetInteger(2);
|
|
|
|
if (slot > 2) {
|
|
|
|
ScriptError("Bad animation slot, only 0 and 1 supported");
|
|
|
|
}
|
|
|
|
case 1:
|
|
|
|
name = ev->GetConstString(1);
|
|
|
|
anim = gi.Anim_NumForName(edict->tiki, Director.GetString(name).c_str());
|
|
|
|
if (anim == -1) {
|
|
|
|
UnknownAnim(Director.GetString(name).c_str(), edict->tiki);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ScriptError("bad number of arguments");
|
|
|
|
break;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
|
|
|
if (!slot) {
|
2023-10-11 22:49:06 +02:00
|
|
|
flagged = qtrue;
|
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (flagged) {
|
2023-10-11 22:49:06 +02:00
|
|
|
parm.motionfail = qtrue;
|
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!m_bLevelMotionAnim) {
|
|
|
|
if (slot) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_weightType[GetMotionSlot(slot)] = 0;
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
ChangeMotionAnim();
|
|
|
|
m_bMotionAnimSet = true;
|
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
|
|
|
|
StartMotionAnimSlot(slot, anim, weight);
|
2023-10-12 18:19:22 +02:00
|
|
|
if (flagged) {
|
|
|
|
m_iMotionSlot = GetMotionSlot(slot);
|
2023-10-11 22:49:06 +02:00
|
|
|
parm.motionfail = qfalse;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventEndActionAnim
|
|
|
|
|
|
|
|
End action animation.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventEndActionAnim(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
parm.upperfail = qtrue;
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!m_bLevelActionAnim) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ChangeActionAnim();
|
|
|
|
parm.upperfail = qfalse;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetMotionAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set motion animation.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetMotionAnim(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
int anim;
|
|
|
|
const_str name;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ev->NumArgs() != 1) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("bad number of arguments");
|
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
|
|
|
|
name = ev->GetConstString(1);
|
|
|
|
anim = gi.Anim_NumForName(edict->tiki, Director.GetString(name));
|
|
|
|
|
|
|
|
if (anim == -1) {
|
|
|
|
UnknownAnim(Director.GetString(name), edict->tiki);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
parm.motionfail = qtrue;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!m_bLevelMotionAnim) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ChangeMotionAnim();
|
2023-10-16 00:29:41 +02:00
|
|
|
|
|
|
|
// start the animation
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bMotionAnimSet = true;
|
2023-10-24 23:16:45 +02:00
|
|
|
StartMotionAnimSlot(0, anim, 2.0);
|
2023-10-16 00:29:41 +02:00
|
|
|
// set the slot
|
|
|
|
m_iMotionSlot = GetMotionSlot(0);
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
parm.motionfail = qfalse;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetAimMotionAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set aim motion animation.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetAimMotionAnim(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
const_str name;
|
2023-10-16 00:29:41 +02:00
|
|
|
int anim_crouch, anim_stand, anim_high;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ev->NumArgs() != 3) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("bad number of arguments");
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
name = ev->GetConstString(1);
|
2023-10-16 00:29:41 +02:00
|
|
|
anim_crouch = gi.Anim_NumForName(edict->tiki, Director.GetString(name));
|
2023-10-12 18:19:22 +02:00
|
|
|
if (anim_crouch == -1) {
|
2023-10-16 00:29:41 +02:00
|
|
|
UnknownAnim(Director.GetString(name), edict->tiki);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
name = ev->GetConstString(2);
|
2023-10-16 00:29:41 +02:00
|
|
|
anim_stand = gi.Anim_NumForName(edict->tiki, Director.GetString(name));
|
2023-10-12 18:19:22 +02:00
|
|
|
if (anim_stand == -1) {
|
2023-10-16 00:29:41 +02:00
|
|
|
UnknownAnim(Director.GetString(name), edict->tiki);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
name = ev->GetConstString(3);
|
2023-10-16 00:29:41 +02:00
|
|
|
anim_high = gi.Anim_NumForName(edict->tiki, Director.GetString(name));
|
2023-10-12 18:19:22 +02:00
|
|
|
if (anim_high == -1) {
|
2023-10-16 00:29:41 +02:00
|
|
|
UnknownAnim(Director.GetString(name), edict->tiki);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
parm.motionfail = qtrue;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!m_bLevelMotionAnim) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ChangeMotionAnim();
|
2023-10-16 00:29:41 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bMotionAnimSet = true;
|
|
|
|
UpdateAimMotion();
|
2023-10-16 00:29:41 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
StartAimMotionAnimSlot(0, anim_crouch);
|
|
|
|
StartAimMotionAnimSlot(1, anim_stand);
|
|
|
|
StartAimMotionAnimSlot(2, anim_high);
|
2023-10-16 00:29:41 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
m_iMotionSlot = GetMotionSlot(1);
|
2023-10-11 22:49:06 +02:00
|
|
|
parm.motionfail = qfalse;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetActionAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set action animation.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetActionAnim(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
const_str name;
|
|
|
|
int anim_forward, anim_up, anim_down;
|
|
|
|
str derivedName;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ev->NumArgs() != 3) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("bad number of arguments");
|
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
name = ev->GetConstString(1);
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fAimLimit_down = ev->GetFloat(2);
|
2023-10-16 00:29:41 +02:00
|
|
|
if (m_fAimLimit_down >= 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fAimLimit_down = -0.001f;
|
|
|
|
ScriptError("Positive lower_limit not allowed");
|
|
|
|
}
|
|
|
|
|
|
|
|
m_fAimLimit_up = ev->GetFloat(3);
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_fAimLimit_up <= 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fAimLimit_up = 0.001f;
|
|
|
|
ScriptError("Negative upper_limit not allowed");
|
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
anim_forward = gi.Anim_NumForName(edict->tiki, Director.GetString(name));
|
|
|
|
if (anim_forward == -1) {
|
|
|
|
UnknownAnim(Director.GetString(name), edict->tiki);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
derivedName = Director.GetString(name) + "_up";
|
|
|
|
anim_up = gi.Anim_NumForName(edict->tiki, derivedName);
|
|
|
|
if (anim_up == -1) {
|
|
|
|
UnknownAnim(derivedName, edict->tiki);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
derivedName = Director.GetString(name) + "_down";
|
|
|
|
anim_down = gi.Anim_NumForName(edict->tiki, derivedName);
|
|
|
|
if (anim_down == -1) {
|
|
|
|
UnknownAnim(derivedName, edict->tiki);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
parm.upperfail = qtrue;
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!m_bLevelActionAnim) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ChangeActionAnim();
|
2023-10-12 18:19:22 +02:00
|
|
|
m_bAimAnimSet = true;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bActionAnimSet = true;
|
|
|
|
UpdateAim();
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
StartAimAnimSlot(0, anim_up);
|
|
|
|
StartAimAnimSlot(1, anim_forward);
|
|
|
|
StartAimAnimSlot(2, anim_down);
|
2023-10-12 18:19:22 +02:00
|
|
|
m_iActionSlot = GetActionSlot(0);
|
2023-10-11 22:49:06 +02:00
|
|
|
parm.upperfail = qfalse;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventUpperAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set upper body.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventUpperAnim(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
int anim;
|
|
|
|
const_str name;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ev->NumArgs()) {
|
|
|
|
if (ev->NumArgs() != 1) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("bad number of arguments");
|
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
|
|
|
|
name = ev->GetConstString(1);
|
|
|
|
anim = gi.Anim_NumForName(edict->tiki, Director.GetString(name));
|
|
|
|
if (anim == -1) {
|
|
|
|
UnknownAnim(Director.GetString(name), edict->tiki);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
m_csUpperAnim = name;
|
2023-10-12 18:19:22 +02:00
|
|
|
} else if (m_bLevelActionAnim) {
|
2023-10-11 22:49:06 +02:00
|
|
|
AnimFinished(m_iActionSlot, true);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetUpperAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set upper body animation.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetUpperAnim(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
int anim;
|
|
|
|
const_str name;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ev->NumArgs() != 1) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("bad number of arguments");
|
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
name = ev->GetConstString(1);
|
|
|
|
anim = gi.Anim_NumForName(edict->tiki, Director.GetString(name));
|
|
|
|
if (anim == -1) {
|
|
|
|
UnknownAnim(Director.GetString(name), edict->tiki);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
parm.upperfail = qtrue;
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!m_bLevelActionAnim) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ChangeActionAnim();
|
|
|
|
m_bActionAnimSet = true;
|
2023-10-16 00:29:41 +02:00
|
|
|
StartActionAnimSlot(anim);
|
2023-10-12 18:19:22 +02:00
|
|
|
m_iActionSlot = SimpleActor::GetActionSlot(0);
|
2023-10-11 22:49:06 +02:00
|
|
|
parm.upperfail = qfalse;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::SoundSayAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if animation not found.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::SoundSayAnim(const_str name, byte bLevelSayAnim)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
if (gi.Anim_NumForName(edict->tiki, Director.GetString(name).c_str()) != -1) {
|
|
|
|
return false;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
ChangeSayAnim();
|
|
|
|
m_bSayAnimSet = true;
|
|
|
|
m_bLevelSayAnim = bLevelSayAnim;
|
|
|
|
m_iSaySlot = -2;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
Com_Printf(
|
|
|
|
"Couldn't find animation '%s' in '%s' - trying sound alias instead.\n",
|
|
|
|
Director.GetString(name).c_str(),
|
|
|
|
edict->tiki->a->name
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2024-09-08 23:54:47 +02:00
|
|
|
Sound(Director.GetString(name), CHAN_AUTO, 0, 0, NULL, 0, 0, 1, 1, -1);
|
2023-10-16 00:29:41 +02:00
|
|
|
|
|
|
|
return true;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventIdleSayAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Play idle say dialogue.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventIdleSayAnim(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
const_str name;
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
if (!ev->NumArgs() && m_bLevelSayAnim == 1) {
|
2023-10-11 22:49:06 +02:00
|
|
|
AnimFinished(m_iSaySlot, true);
|
2023-10-16 00:29:41 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ev->NumArgs() != 1) {
|
|
|
|
ScriptError("bad number of arguments");
|
|
|
|
}
|
|
|
|
|
|
|
|
name = ev->GetConstString(1);
|
|
|
|
|
|
|
|
if (m_ThinkState == THINKSTATE_KILLED || m_ThinkState == THINKSTATE_PAIN || m_ThinkState == THINKSTATE_ATTACK
|
2023-10-16 23:42:30 +02:00
|
|
|
|| m_ThinkState == THINKSTATE_GRENADE || !SoundSayAnim(name, 1)) {
|
2023-10-16 00:29:41 +02:00
|
|
|
m_csSayAnim = name;
|
|
|
|
m_bNextLevelSayAnim = 1;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSayAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Play idle dialogue.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSayAnim(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
const_str name;
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
if (!ev->NumArgs() && m_bLevelSayAnim) {
|
2023-10-11 22:49:06 +02:00
|
|
|
AnimFinished(m_iSaySlot, true);
|
2023-10-16 00:29:41 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ev->NumArgs() != 1) {
|
|
|
|
ScriptError("bad number of arguments");
|
|
|
|
}
|
|
|
|
|
|
|
|
name = ev->GetConstString(1);
|
|
|
|
|
|
|
|
if (m_ThinkState == THINKSTATE_KILLED || m_ThinkState == THINKSTATE_PAIN || !SoundSayAnim(name, 2)) {
|
|
|
|
m_csSayAnim = name;
|
|
|
|
m_bNextLevelSayAnim = 2;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventSetSayAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set say animation.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetSayAnim(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 00:29:41 +02:00
|
|
|
int anim;
|
|
|
|
int animflags;
|
2023-10-11 22:49:06 +02:00
|
|
|
const_str name;
|
2023-10-16 00:29:41 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ev->NumArgs() != 1) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("bad number of arguments");
|
|
|
|
}
|
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
if (m_bLevelSayAnim) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
name = ev->GetConstString(1);
|
|
|
|
parm.sayfail = qtrue;
|
|
|
|
anim = gi.Anim_NumForName(edict->tiki, Director.GetString(name));
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
if (anim == -1) {
|
|
|
|
ChangeSayAnim();
|
|
|
|
m_bSayAnimSet = true;
|
|
|
|
m_iSaySlot = -2;
|
|
|
|
|
|
|
|
Com_Printf(
|
|
|
|
"Couldn't find animation '%s' in '%s' - trying sound alias instead.\n",
|
2023-10-16 00:31:50 +02:00
|
|
|
Director.GetString(name).c_str(),
|
2023-10-16 00:29:41 +02:00
|
|
|
edict->tiki->a->name
|
|
|
|
);
|
|
|
|
Sound(Director.GetString(name), CHAN_AUTO, 0, 0, NULL, 0, 0, true, true);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
animflags = gi.Anim_FlagsSkel(edict->tiki, anim);
|
|
|
|
if (animflags & TAF_HASUPPER) {
|
|
|
|
if (m_bLevelActionAnim) {
|
|
|
|
if (!m_bSayAnimSet) {
|
|
|
|
m_iSaySlot = m_iActionSlot;
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (flags & TAF_HASDELTA) {
|
|
|
|
if (m_bLevelMotionAnim) {
|
|
|
|
if (!m_bSayAnimSet) {
|
|
|
|
m_iSaySlot = m_iMotionSlot;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
|
|
|
|
ChangeActionAnim();
|
|
|
|
ChangeMotionAnim();
|
|
|
|
StartMotionAnimSlot(0, anim, 1.0);
|
|
|
|
|
|
|
|
m_iMotionSlot = m_iActionSlot = GetMotionSlot(0);
|
|
|
|
} else {
|
|
|
|
ChangeActionAnim();
|
|
|
|
m_bActionAnimSet = true;
|
|
|
|
StartActionAnimSlot(anim);
|
|
|
|
m_iActionSlot = GetActionSlot(0);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
|
|
|
|
ChangeSayAnim();
|
|
|
|
m_bSayAnimSet = true;
|
|
|
|
m_iSaySlot = m_iActionSlot;
|
|
|
|
} else {
|
|
|
|
ChangeSayAnim();
|
|
|
|
m_bSayAnimSet = true;
|
|
|
|
StartSayAnimSlot(anim);
|
|
|
|
m_iSaySlot = GetSaySlot();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 00:29:41 +02:00
|
|
|
|
|
|
|
parm.sayfail = qfalse;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ChangeAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Change current animation.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ChangeAnim(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_pAnimThread) {
|
2023-10-16 23:42:30 +02:00
|
|
|
if (g_scripttrace->integer && m_pAnimThread->CanScriptTracePrint()) {
|
|
|
|
Com_Printf("--- Change Anim\n");
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
m_pAnimThread->AbortRegistration(STRING_EMPTY, this);
|
2023-10-16 23:42:30 +02:00
|
|
|
delete m_pAnimThread->GetScriptClass();
|
2023-10-23 22:55:09 +02:00
|
|
|
// The animation thread must be deleted afterwards
|
|
|
|
assert(!m_pAnimThread);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
switch (m_ThinkState) {
|
|
|
|
case THINKSTATE_PAIN:
|
|
|
|
case THINKSTATE_KILLED:
|
|
|
|
if (m_bMotionAnimSet) {
|
|
|
|
AnimFinished(m_iMotionSlot, true);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_bActionAnimSet) {
|
|
|
|
AnimFinished(m_iActionSlot, true);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_bSayAnimSet) {
|
|
|
|
AnimFinished(m_iSaySlot, true);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
break;
|
2023-10-24 23:16:45 +02:00
|
|
|
case THINKSTATE_ATTACK:
|
2023-10-16 23:42:30 +02:00
|
|
|
case THINKSTATE_GRENADE:
|
|
|
|
if (m_bMotionAnimSet) {
|
|
|
|
AnimFinished(m_iMotionSlot, true);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_bActionAnimSet) {
|
|
|
|
AnimFinished(m_iActionSlot, true);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_bSayAnimSet && m_bLevelSayAnim != 2) {
|
|
|
|
AnimFinished(m_iSaySlot, true);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
if (m_bMotionAnimSet && m_bLevelMotionAnim == 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
AnimFinished(m_iMotionSlot, true);
|
2023-10-16 23:42:30 +02:00
|
|
|
}
|
|
|
|
if (m_bActionAnimSet && m_bLevelActionAnim == 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
AnimFinished(m_iActionSlot, true);
|
2023-10-16 23:42:30 +02:00
|
|
|
}
|
|
|
|
if (m_bSayAnimSet && m_bLevelSayAnim == 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
AnimFinished(m_iSaySlot, true);
|
2023-10-16 23:42:30 +02:00
|
|
|
}
|
|
|
|
break;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
m_fCrossblendTime = 0.5f;
|
|
|
|
m_pAnimThread = m_Anim.Create(this);
|
2023-11-02 19:11:44 +01:00
|
|
|
if (m_pAnimThread) {
|
|
|
|
if (g_scripttrace->integer && m_pAnimThread->CanScriptTracePrint()) {
|
|
|
|
Com_Printf("+++ Change Anim\n");
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-11-02 19:11:44 +01:00
|
|
|
m_pAnimThread->Register(STRING_EMPTY, this);
|
|
|
|
m_pAnimThread->StartTiming();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::UpdateSayAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Update say animation.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::UpdateSayAnim(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
int anim;
|
|
|
|
int animflags;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_ThinkState == THINKSTATE_KILLED || m_ThinkState == THINKSTATE_PAIN) {
|
|
|
|
if (!m_bSayAnimSet) {
|
|
|
|
Unregister(STRING_SAYDONE);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
return;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
anim = gi.Anim_NumForName(edict->tiki, Director.GetString(m_csSayAnim));
|
|
|
|
if (anim == -1) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
animflags = gi.Anim_FlagsSkel(edict->tiki, anim);
|
|
|
|
if (animflags & TAF_HASUPPER) {
|
|
|
|
if (m_ThinkState == THINKSTATE_ATTACK || m_ThinkState == THINKSTATE_GRENADE) {
|
|
|
|
if (!m_bSayAnimSet) {
|
|
|
|
Unregister(STRING_SAYDONE);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
ChangeActionAnim();
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (animflags & TAF_HASDELTA) {
|
|
|
|
ChangeMotionAnim();
|
|
|
|
StartMotionAnimSlot(0, anim, 1.0);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
m_bLevelActionAnim = true;
|
|
|
|
m_bLevelMotionAnim = true;
|
|
|
|
m_iMotionSlot = m_iActionSlot = GetMotionSlot(0);
|
|
|
|
} else {
|
|
|
|
m_bActionAnimSet = true;
|
|
|
|
StartActionAnimSlot(anim);
|
|
|
|
m_bLevelActionAnim = true;
|
|
|
|
m_iActionSlot = GetActionSlot(0);
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
ChangeSayAnim();
|
|
|
|
m_bSayAnimSet = true;
|
|
|
|
m_bLevelSayAnim = m_bNextLevelSayAnim;
|
|
|
|
m_bNextLevelSayAnim = false;
|
|
|
|
m_iSaySlot = m_iActionSlot;
|
|
|
|
} else if (m_bNextLevelSayAnim != 2 && (m_ThinkState == THINKSTATE_ATTACK || m_ThinkState == THINKSTATE_GRENADE)) {
|
|
|
|
if (!m_bSayAnimSet) {
|
|
|
|
Unregister(STRING_SAYDONE);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
} else {
|
|
|
|
ChangeSayAnim();
|
|
|
|
|
|
|
|
m_bSayAnimSet = true;
|
|
|
|
StartSayAnimSlot(anim);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
m_bLevelSayAnim = m_bNextLevelSayAnim;
|
|
|
|
m_bNextLevelSayAnim = 0;
|
|
|
|
m_iSaySlot = GetSaySlot();
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::UpdateUpperAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Update upper animation.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::UpdateUpperAnim(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
int anim;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
anim = gi.Anim_NumForName(edict->tiki, Director.GetString(m_csUpperAnim).c_str());
|
|
|
|
if (anim == -1) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_ThinkState == THINKSTATE_ATTACK || m_ThinkState == THINKSTATE_GRENADE || m_ThinkState == THINKSTATE_KILLED
|
|
|
|
|| m_ThinkState == THINKSTATE_PAIN) {
|
|
|
|
if (!m_bActionAnimSet) {
|
|
|
|
Unregister(STRING_UPPERANIMDONE);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
gi.Anim_FlagsSkel(edict->tiki, anim);
|
|
|
|
|
|
|
|
ChangeActionAnim();
|
|
|
|
|
|
|
|
m_bActionAnimSet = true;
|
|
|
|
StartActionAnimSlot(anim);
|
|
|
|
m_bLevelActionAnim = true;
|
|
|
|
m_iActionSlot = GetActionSlot(0);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::UpdateAnim
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Update animation.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::UpdateAnim(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
float time;
|
|
|
|
float total_weight;
|
|
|
|
float fAnimTime;
|
|
|
|
float fAnimWeight;
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bAnimating = true;
|
2023-10-16 23:42:30 +02:00
|
|
|
UpdateAim();
|
|
|
|
|
|
|
|
if (UpdateSelectedAnimation()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ChangeAnim();
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Director.Unpause();
|
|
|
|
Director.Pause();
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_csSayAnim != STRING_EMPTY) {
|
2023-10-11 22:49:06 +02:00
|
|
|
UpdateSayAnim();
|
|
|
|
m_csSayAnim = STRING_EMPTY;
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_csUpperAnim != STRING_EMPTY) {
|
2023-10-11 22:49:06 +02:00
|
|
|
UpdateUpperAnim();
|
|
|
|
m_csUpperAnim = STRING_EMPTY;
|
|
|
|
}
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!m_bSayAnimSet && !m_bIsAnimal) {
|
|
|
|
UpdateEmotion();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
for (int slot = 0; slot < MAX_FRAMEINFOS - 2; slot++) {
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!((m_bUpdateAnimDoneFlags >> slot) & 1)) {
|
2023-10-16 23:42:30 +02:00
|
|
|
UpdateAnimSlot(slot);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
time = 0;
|
|
|
|
total_weight = 0;
|
|
|
|
|
|
|
|
for (int slot = 0; slot < MAX_FRAMEINFOS - 2; slot++) {
|
|
|
|
if (m_weightType[slot] != ANIM_WEIGHT_MOTION && m_weightType[slot] != ANIM_WEIGHT_CROSSBLEND_2) {
|
|
|
|
UseSyncTime(slot, 0);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IsRepeatType(slot)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
UseSyncTime(slot, 0);
|
2023-10-16 23:42:30 +02:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
UseSyncTime(slot, 1);
|
|
|
|
fAnimTime = AnimTime(slot);
|
2023-10-23 15:55:58 +02:00
|
|
|
fAnimWeight = GetWeight(slot);
|
2023-10-16 23:42:30 +02:00
|
|
|
time += fAnimTime * fAnimWeight;
|
|
|
|
|
|
|
|
if (!isfinite(time)) {
|
|
|
|
Com_Printf(
|
|
|
|
"ent %i, targetname '%s', anim '%s', slot %i, fAnimTime %f, fAnimWeight %f\n",
|
|
|
|
entnum,
|
|
|
|
targetname.c_str(),
|
|
|
|
AnimName(slot),
|
|
|
|
slot,
|
|
|
|
fAnimTime,
|
|
|
|
fAnimWeight
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
total_weight += fAnimWeight;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (total_weight != 0) {
|
2023-10-16 23:42:30 +02:00
|
|
|
float rate;
|
|
|
|
|
|
|
|
rate = time / total_weight;
|
2023-10-23 15:55:58 +02:00
|
|
|
if (m_Team != TEAM_GERMAN) {
|
2023-10-16 23:42:30 +02:00
|
|
|
rate /= 1.45f;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetSyncRate(rate / m_fRunAnimRate);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
PostAnimate();
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::Think
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Think function for actor.
|
|
|
|
Calls think function related to the current thinkstate.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::Think(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
int iNewCurrentHistory;
|
|
|
|
|
|
|
|
if (!g_ai->integer) {
|
|
|
|
// AI is disabled
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_bDoAI) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!edict->tiki) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
m_bAnimating = false;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
Director.Pause();
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
iNewCurrentHistory = level.inttime / 125 % 4;
|
|
|
|
if (m_iCurrentHistory != iNewCurrentHistory) {
|
|
|
|
m_iCurrentHistory = iNewCurrentHistory;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (iNewCurrentHistory >= 1) {
|
|
|
|
VectorCopy2D(origin, m_vOriginHistory[iNewCurrentHistory - 1]);
|
|
|
|
} else {
|
|
|
|
VectorCopy2D(origin, m_vOriginHistory[3]);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (m_bNoPlayerCollision) {
|
|
|
|
Entity *player = G_GetEntity(0);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!IsTouching(player)) {
|
|
|
|
Com_Printf("(entnum %d, radnum %d) is going solid after not getting stuck in the player\n", entnum, radnum);
|
|
|
|
setSolidType(SOLID_BBOX);
|
|
|
|
m_bNoPlayerCollision = false;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
m_eNextAnimMode = -1;
|
|
|
|
FixAIParameters();
|
|
|
|
UpdateEnableEnemy();
|
|
|
|
|
|
|
|
if (m_pTetherEnt) {
|
|
|
|
m_vHome = m_pTetherEnt->origin;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
parm.movefail = false;
|
2023-11-01 20:16:44 +01:00
|
|
|
if (m_bBecomeRunner && m_ThinkMap[THINKSTATE_IDLE] != THINK_RUNNER && m_ThinkMap[THINKSTATE_IDLE] != THINK_PATROL) {
|
|
|
|
parm.movefail = true;
|
2023-10-16 23:42:30 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_bDirtyThinkState) {
|
|
|
|
m_bDirtyThinkState = false;
|
|
|
|
ThinkStateTransitions();
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
GlobalFuncs_t *Think = &GlobalFuncs[m_Think[m_ThinkLevel]];
|
|
|
|
|
|
|
|
if (Think->ThinkState) {
|
|
|
|
(this->*Think->ThinkState)();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
m_bNeedReload = false;
|
|
|
|
mbBreakSpecialAttack = false;
|
|
|
|
|
|
|
|
Director.Unpause();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::CheckUnregister
|
|
|
|
|
|
|
|
Notify scripts when the actor has:
|
|
|
|
- Finished moving
|
|
|
|
- Has a new enemy
|
|
|
|
- And/or if the enemy is visible
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::CheckUnregister(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bBecomeRunner = false;
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (parm.movefail) {
|
2023-10-11 22:49:06 +02:00
|
|
|
parm.movedone = false;
|
|
|
|
Unregister(STRING_MOVEDONE);
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_Enemy) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Unregister(STRING_HASENEMY);
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_bEnemyVisible) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Unregister(STRING_VISIBLE);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PostThink
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Called after think is finished.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::PostThink(bool bDontFaceWall)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
CheckUnregister();
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
if (bDontFaceWall && (!m_pTurnEntity || m_ThinkState != THINKSTATE_IDLE)) {
|
|
|
|
DontFaceWall();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (is_paused) {
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
UpdateAngles();
|
|
|
|
UpdateAnim();
|
|
|
|
DoMove();
|
|
|
|
UpdateBoneControllers();
|
|
|
|
UpdateFootsteps();
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::AnimFinished
|
2018-09-17 23:50:38 +02:00
|
|
|
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::AnimFinished(int slot, bool stop)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (stop && slot >= 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
animFlags[slot] |= ANIM_NOACTION;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (slot == m_iMotionSlot) {
|
|
|
|
if (stop) {
|
|
|
|
m_iMotionSlot = -1;
|
2023-10-16 23:42:30 +02:00
|
|
|
m_bLevelMotionAnim = false;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
MPrintf("flagged anim finished slot %d\n", slot);
|
|
|
|
Unregister(STRING_FLAGGEDANIMDONE);
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (slot == m_iActionSlot) {
|
|
|
|
if (stop) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ChangeActionAnim();
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_csUpperAnim == STRING_EMPTY) {
|
2023-10-11 22:49:06 +02:00
|
|
|
MPrintf("upper anim finished slot %d\n", slot);
|
|
|
|
Unregister(STRING_UPPERANIMDONE);
|
|
|
|
}
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (slot == m_iSaySlot) {
|
|
|
|
if (stop) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ChangeSayAnim();
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_csSayAnim == STRING_EMPTY) {
|
2023-10-11 22:49:06 +02:00
|
|
|
MPrintf("say anim finished slot %d\n", slot);
|
|
|
|
Unregister(STRING_SAYDONE);
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
} else if (slot == GetSaySlot() && stop) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ChangeSayAnim();
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::AnimFinished
|
2018-09-17 23:50:38 +02:00
|
|
|
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::AnimFinished(int slot)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
animFlags[slot] &= ~ANIM_FINISHED;
|
2023-10-16 23:42:30 +02:00
|
|
|
AnimFinished(slot, !IsRepeatType(slot));
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::SetThink
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Modifies think num of current thinkstate inside m_ThinkMap.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetThink(eThinkState state, eThinkNum think)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_ThinkMap[state] = think;
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_ThinkState == state) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bDirtyThinkState = true;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::SetThink
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set think to idle.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetThinkIdle(eThinkNum think_idle)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
eThinkNum think_curious;
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
switch (think_idle) {
|
2023-10-11 22:49:06 +02:00
|
|
|
case THINK_PATROL:
|
|
|
|
case THINK_RUNNER:
|
2023-10-12 18:19:22 +02:00
|
|
|
think_curious = THINK_CURIOUS;
|
2023-10-16 23:42:30 +02:00
|
|
|
m_bBecomeRunner = true;
|
2023-10-11 22:49:06 +02:00
|
|
|
break;
|
|
|
|
case THINK_MACHINEGUNNER:
|
|
|
|
think_curious = THINK_MACHINEGUNNER;
|
|
|
|
break;
|
|
|
|
case THINK_DOG_IDLE:
|
|
|
|
think_curious = THINK_DOG_CURIOUS;
|
2023-10-29 20:20:56 +01:00
|
|
|
SetThink(THINKSTATE_GRENADE, THINK_DOG_CURIOUS);
|
2023-10-11 22:49:06 +02:00
|
|
|
break;
|
|
|
|
case THINK_ANIM:
|
|
|
|
think_curious = THINK_ANIM_CURIOUS;
|
|
|
|
break;
|
|
|
|
case THINK_BALCONY_IDLE:
|
|
|
|
think_curious = THINK_BALCONY_CURIOUS;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
think_curious = THINK_CURIOUS;
|
|
|
|
break;
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThink(THINKSTATE_IDLE, think_idle);
|
|
|
|
SetThink(THINKSTATE_CURIOUS, think_curious);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::GetThinkType
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Get think for csName.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
int Actor::GetThinkType(const_str csName)
|
2019-06-29 23:43:30 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (i = 0; i < NUM_THINKS; i++) {
|
|
|
|
if (m_csThinkNames[i] == csName) {
|
|
|
|
return i;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
ScriptError("unknown think type '%s'", Director.GetString(csName).c_str());
|
2019-06-29 23:43:30 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::SetThinkState
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set thinkstate.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetThinkState(eThinkState state, eThinkLevel level)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-29 20:20:56 +01:00
|
|
|
eThinkNum map;
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-29 20:20:56 +01:00
|
|
|
if (state == THINKSTATE_ATTACK) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_csIdleMood = STRING_NERVOUS;
|
2023-10-16 23:42:30 +02:00
|
|
|
map = m_ThinkMap[THINKSTATE_ATTACK];
|
|
|
|
|
2023-10-29 20:20:56 +01:00
|
|
|
if (map != THINK_ALARM
|
|
|
|
&& map != THINK_WEAPONLESS
|
|
|
|
&& map != THINK_DOG_ATTACK
|
|
|
|
&& !GetWeapon(WEAPON_MAIN)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Com_Printf(
|
|
|
|
"^~^~^ LD ERROR: (entnum %i, radnum %i, targetname '%s'): forcing weaponless attack state.\n"
|
|
|
|
"^~^~^ Level designers should specify 'type_attack weaponless' for this guy.\n",
|
|
|
|
entnum,
|
|
|
|
radnum,
|
2023-10-16 23:42:30 +02:00
|
|
|
TargetName().c_str()
|
2023-10-12 18:19:22 +02:00
|
|
|
);
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThink(THINKSTATE_ATTACK, THINK_WEAPONLESS);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_ThinkStates[level] = state;
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_ThinkLevel <= level) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bDirtyThinkState = true;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EndCurrentThinkState
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
End current think state.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EndCurrentThinkState(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThinkState(THINKSTATE_VOID, m_ThinkLevel);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ClearThinkStates
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Clear all thinkstates.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ClearThinkStates(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-29 20:20:56 +01:00
|
|
|
for (int i = 0; i < NUM_THINKLEVELS; i++) {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThinkState(THINKSTATE_VOID, (eThinkLevel)i);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetAlarmNode
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetAlarmNode(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
Listener *l = ev->GetListener(1);
|
2023-10-16 23:42:30 +02:00
|
|
|
if (l && !l->isSubclassOf(SimpleEntity)) {
|
|
|
|
ScriptError("Alarm node must be an entity");
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
m_AlarmNode = static_cast<SimpleEntity *>(l);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetAlarmNode
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetAlarmNode(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddListener(m_AlarmNode);
|
|
|
|
}
|
2019-07-01 20:17:46 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetPreAlarmThread
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventSetPreAlarmThread(Event *ev)
|
|
|
|
{
|
|
|
|
if (ev->IsFromScript()) {
|
|
|
|
m_PreAlarmThread.SetThread(ev->GetValue());
|
|
|
|
} else {
|
|
|
|
m_PreAlarmThread.Set(ev->GetString(1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetAlarmThread
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetAlarmThread(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ev->IsFromScript()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_AlarmThread.SetThread(ev->GetValue());
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_AlarmThread.Set(ev->GetString(1));
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetAlarmThread
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetAlarmThread(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
m_AlarmThread.GetScriptValue(&ev->GetValue());
|
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetSoundAwareness
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetSoundAwareness(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fSoundAwareness = ev->GetFloat(1);
|
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetSoundAwareness
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetSoundAwareness(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddFloat(m_fSoundAwareness);
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetGrenadeAwareness
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetGrenadeAwareness(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
m_fGrenadeAwareness = ev->GetFloat(1);
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetGrenadeAwareness
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetGrenadeAwareness(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddFloat(m_fGrenadeAwareness);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetTypeIdle
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetTypeIdle(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
bool (*AllowedState)(int state);
|
|
|
|
eThinkNum think;
|
|
|
|
|
|
|
|
think = (eThinkNum)GetThinkType(ev->GetConstString(1));
|
|
|
|
AllowedState = Actor::GlobalFuncs[think].IsState;
|
|
|
|
|
|
|
|
if (!AllowedState(THINKSTATE_IDLE)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThinkIdle(THINK_IDLE);
|
|
|
|
ScriptError("Invalid idle think '%s'", Director.GetString(m_csThinkNames[think]).c_str());
|
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThinkIdle(think);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetTypeIdle
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetTypeIdle(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddConstString(m_csThinkNames[m_ThinkMap[THINKSTATE_IDLE]]);
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetTypeAttack
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetTypeAttack(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
bool (*AllowedState)(int state);
|
|
|
|
eThinkNum think;
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
think = (eThinkNum)GetThinkType(ev->GetConstString(1));
|
|
|
|
AllowedState = Actor::GlobalFuncs[think].IsState;
|
|
|
|
|
|
|
|
if (!AllowedState(THINKSTATE_ATTACK)) {
|
|
|
|
SetThink(THINKSTATE_ATTACK, THINK_TURRET);
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("Invalid attack think '%s'", Director.GetString(m_csThinkNames[think]).c_str());
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThink(THINKSTATE_ATTACK, think);
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetTypeAttack
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetTypeAttack(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddConstString(m_csThinkNames[m_ThinkMap[THINKSTATE_ATTACK]]);
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetTypeDisguise
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetTypeDisguise(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
bool (*AllowedState)(int state);
|
|
|
|
eThinkNum think;
|
|
|
|
|
|
|
|
think = (eThinkNum)GetThinkType(ev->GetConstString(1));
|
|
|
|
AllowedState = Actor::GlobalFuncs[think].IsState;
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!AllowedState(THINKSTATE_DISGUISE)) {
|
|
|
|
SetThink(THINKSTATE_DISGUISE, THINK_DISGUISE_SALUTE);
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("Invalid disguise think '%s'", Director.GetString(m_csThinkNames[think]).c_str());
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThink(THINKSTATE_DISGUISE, think);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetDisguiseAcceptThread
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetDisguiseAcceptThread(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ev->IsFromScript()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_DisguiseAcceptThread.SetThread(ev->GetValue());
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_DisguiseAcceptThread.Set(ev->GetString(1));
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetDisguiseAcceptThread
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetDisguiseAcceptThread(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
m_DisguiseAcceptThread.GetScriptValue(&ev->GetValue());
|
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetTypeDisguise
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetTypeDisguise(Event *ev)
|
2018-08-19 08:26:59 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddConstString(m_csThinkNames[m_ThinkMap[THINKSTATE_DISGUISE]]);
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetDisguiseLevel
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetDisguiseLevel(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
m_iDisguiseLevel = ev->GetInteger(1);
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
if (m_iDisguiseLevel != 1 && m_iDisguiseLevel != 2) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iDisguiseLevel = 1;
|
2023-10-16 23:42:30 +02:00
|
|
|
ScriptError("bad disguise level %d for %s, setting to 1\n", m_iDisguiseLevel, TargetName().c_str());
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetDisguiseLevel
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetDisguiseLevel(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddInteger(m_iDisguiseLevel);
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetTypeGrenade
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetTypeGrenade(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
bool (*AllowedState)(int state);
|
|
|
|
eThinkNum think;
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
think = (eThinkNum)GetThinkType(ev->GetConstString(1));
|
|
|
|
AllowedState = Actor::GlobalFuncs[think].IsState;
|
|
|
|
|
|
|
|
if (!AllowedState(THINKSTATE_GRENADE)) {
|
|
|
|
SetThink(THINKSTATE_GRENADE, THINK_GRENADE);
|
|
|
|
ScriptError("Invalid grenade think '%s'", Director.GetString(m_csThinkNames[think]).c_str());
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThink(THINKSTATE_GRENADE, think);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetTypeGrenade
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetTypeGrenade(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddConstString(m_csThinkNames[m_ThinkMap[THINKSTATE_GRENADE]]);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::InitThinkStates
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Initialize think related stuff.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::InitThinkStates(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
for (size_t i = 0; i < NUM_THINKSTATES; i++) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_ThinkMap[i] = THINK_VOID;
|
|
|
|
}
|
2023-10-28 00:01:57 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
for (size_t i = 0; i < NUM_THINKLEVELS; i++) {
|
|
|
|
m_Think[i] = THINK_VOID;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_ThinkStates[i] = THINKSTATE_VOID;
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
m_ThinkMap[THINKSTATE_VOID] = THINK_VOID;
|
|
|
|
m_ThinkMap[THINKSTATE_IDLE] = THINK_IDLE;
|
|
|
|
m_ThinkMap[THINKSTATE_PAIN] = THINK_PAIN;
|
|
|
|
m_ThinkMap[THINKSTATE_KILLED] = THINK_KILLED;
|
|
|
|
m_ThinkMap[THINKSTATE_ATTACK] = THINK_TURRET;
|
|
|
|
m_ThinkMap[THINKSTATE_CURIOUS] = THINK_CURIOUS;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_ThinkMap[THINKSTATE_DISGUISE] = THINK_DISGUISE_SALUTE;
|
2023-10-12 18:19:22 +02:00
|
|
|
m_ThinkMap[THINKSTATE_GRENADE] = THINK_GRENADE;
|
2023-10-16 23:42:30 +02:00
|
|
|
m_ThinkMap[THINKSTATE_BADPLACE] = THINK_BADPLACE;
|
2023-10-12 18:19:22 +02:00
|
|
|
m_ThinkMap[THINKSTATE_NOCLIP] = THINK_NOCLIP;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-15 20:52:06 +02:00
|
|
|
m_ThinkLevel = THINKLEVEL_IDLE;
|
2023-10-12 18:19:22 +02:00
|
|
|
m_ThinkState = THINKSTATE_VOID;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bDirtyThinkState = false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::DefaultRestart
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Default restart of current think state.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::DefaultRestart(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
EndState(m_ThinkLevel);
|
2023-10-11 22:49:06 +02:00
|
|
|
BeginState();
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::SuspendState
|
2019-06-30 02:42:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Suspend current think state.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SuspendState(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-28 00:01:57 +02:00
|
|
|
GlobalFuncs_t *think = &GlobalFuncs[CurrentThink()];
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (think->SuspendState) {
|
|
|
|
(this->*think->SuspendState)();
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ResumeState
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Resume current think state.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ResumeState(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-28 00:01:57 +02:00
|
|
|
GlobalFuncs_t *think = &GlobalFuncs[CurrentThink()];
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (think->ResumeState) {
|
|
|
|
(this->*think->ResumeState)();
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::BeginState
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Begin current think state.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::BeginState(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
GlobalFuncs_t *think;
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
m_Think[m_ThinkLevel] = m_ThinkMap[m_ThinkState];
|
2023-10-28 00:01:57 +02:00
|
|
|
think = &GlobalFuncs[CurrentThink()];
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (think->BeginState) {
|
|
|
|
(this->*think->BeginState)();
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
m_Think[m_ThinkLevel] = m_ThinkMap[m_ThinkState];
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EndState
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
End current think state.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EndState(int level)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
GlobalFuncs_t *think;
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-24 21:35:49 +02:00
|
|
|
think = &GlobalFuncs[m_Think[level]];
|
2023-10-16 23:42:30 +02:00
|
|
|
m_Think[level] = THINK_VOID;
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (think->EndState) {
|
|
|
|
(this->*think->EndState)();
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_pAnimThread) {
|
|
|
|
m_pAnimThread->AbortRegistration(STRING_EMPTY, this);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::RestartState
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Restart current think state.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::RestartState(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-28 00:01:57 +02:00
|
|
|
GlobalFuncs_t *think = &GlobalFuncs[CurrentThink()];
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (think->RestartState) {
|
|
|
|
(this->*think->RestartState)();
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::UpdateEnableEnemy
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Enable/disable enemy based on desired value.
|
|
|
|
Can be changed from script.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::UpdateEnableEnemy(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_bEnableEnemy == m_bDesiredEnableEnemy) {
|
|
|
|
// no change
|
|
|
|
return;
|
|
|
|
}
|
2023-10-14 15:02:07 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
m_bEnableEnemy = m_bDesiredEnableEnemy;
|
2023-10-14 15:02:07 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_bEnableEnemy) {
|
|
|
|
SetLeashHome(origin);
|
|
|
|
} else {
|
|
|
|
if (m_ThinkStates[THINKLEVEL_IDLE] == THINKSTATE_ATTACK || m_ThinkStates[THINKLEVEL_IDLE] == THINKSTATE_CURIOUS
|
|
|
|
|| m_ThinkStates[THINKLEVEL_IDLE] == THINKSTATE_DISGUISE) {
|
|
|
|
SetThinkState(THINKSTATE_IDLE, THINKLEVEL_IDLE);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
SetEnemy(NULL, false);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ThinkStateTransitions
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Transition think state and level.
|
|
|
|
Called when thinkstate/level are change.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ThinkStateTransitions(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
int i;
|
|
|
|
eThinkLevel newThinkLevel;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
for (newThinkLevel = THINKLEVEL_NOCLIP; newThinkLevel; newThinkLevel = (eThinkLevel)(newThinkLevel - 1)) {
|
|
|
|
if (m_ThinkStates[newThinkLevel]) {
|
2023-10-11 22:49:06 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_ThinkMap[m_ThinkStates[newThinkLevel]] != CurrentThink()) {
|
|
|
|
for (i = 0; i < newThinkLevel; i++) {
|
|
|
|
if (!m_ThinkStates[i]) {
|
|
|
|
EndState(i);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (newThinkLevel > m_ThinkLevel) {
|
2023-10-11 22:49:06 +02:00
|
|
|
SuspendState();
|
2023-10-16 23:42:30 +02:00
|
|
|
m_ThinkLevel = newThinkLevel;
|
|
|
|
m_ThinkState = m_ThinkStates[m_ThinkLevel];
|
2023-10-11 22:49:06 +02:00
|
|
|
BeginState();
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
EndState(m_ThinkLevel);
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (newThinkLevel == m_ThinkLevel) {
|
2023-10-16 23:42:30 +02:00
|
|
|
m_ThinkState = m_ThinkStates[m_ThinkLevel];
|
2023-10-11 22:49:06 +02:00
|
|
|
BeginState();
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-16 23:42:30 +02:00
|
|
|
m_ThinkLevel = newThinkLevel;
|
|
|
|
m_ThinkState = m_ThinkStates[m_ThinkLevel];
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (CurrentThink() == m_ThinkMap[m_ThinkState]) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ResumeState();
|
2023-10-16 23:42:30 +02:00
|
|
|
} else {
|
|
|
|
EndState(m_ThinkLevel);
|
|
|
|
BeginState();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
} else if (newThinkLevel == m_ThinkLevel && m_ThinkState == m_ThinkStates[m_ThinkLevel]) {
|
|
|
|
RestartState();
|
|
|
|
} else {
|
|
|
|
m_ThinkLevel = newThinkLevel;
|
|
|
|
m_ThinkState = m_ThinkStates[m_ThinkLevel];
|
|
|
|
m_Think[m_ThinkLevel] = m_ThinkMap[m_ThinkState];
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::FixAIParameters
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Fix path related parameters.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::FixAIParameters(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
float fMinLeash;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_pTetherEnt) {
|
2023-10-16 23:42:30 +02:00
|
|
|
fMinLeash = 64;
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_pTetherEnt->IsSubclassOfEntity()) {
|
2024-02-15 20:40:55 +01:00
|
|
|
Entity* pEnt = static_cast<Entity*>(m_pTetherEnt.Pointer());
|
|
|
|
fMinLeash = pEnt->maxs[0] - pEnt->mins[1] + pEnt->maxs[1] - pEnt->mins[1];
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
if (m_fLeash < fMinLeash) {
|
2023-10-12 18:19:22 +02:00
|
|
|
Com_Printf(
|
|
|
|
"^~^~^ LD ERROR: (entnum %i, radnum %i, targetname '%s'): increasing leash from %g to %g.\n"
|
2023-10-11 22:49:06 +02:00
|
|
|
"^~^~^ Leash must be larger than the size of the entity to which an AI is tethered.\n"
|
|
|
|
"\n",
|
|
|
|
entnum,
|
|
|
|
radnum,
|
2023-10-16 23:42:30 +02:00
|
|
|
TargetName().c_str(),
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fLeash,
|
2023-10-16 23:42:30 +02:00
|
|
|
fMinLeash
|
2023-10-12 18:19:22 +02:00
|
|
|
);
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
m_fLeash = fMinLeash;
|
|
|
|
m_fLeashSquared = Square(fMinLeash);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
if (m_fLeash < m_fMinDistance) {
|
2023-10-12 18:19:22 +02:00
|
|
|
Com_Printf(
|
|
|
|
"^~^~^ LD ERROR: (entnum %i, radnum %i, targetname '%s'): reducing mindist from %g to %g to match "
|
|
|
|
"leash.\n"
|
2023-10-11 22:49:06 +02:00
|
|
|
"^~^~^ Leash must be greater than mindist, or the AI will want to both run away and stay put.\n"
|
|
|
|
"\n",
|
|
|
|
entnum,
|
|
|
|
radnum,
|
2023-10-16 23:42:30 +02:00
|
|
|
TargetName().c_str(),
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fMinDistance,
|
2023-10-16 23:42:30 +02:00
|
|
|
m_fLeash
|
2023-10-12 18:19:22 +02:00
|
|
|
);
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
m_fMinDistance = m_fLeash;
|
|
|
|
m_fMinDistanceSquared = Square(m_fMinDistance);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
if (m_fMaxDistance < m_fMinDistance + 128.0 - 1.0) {
|
2023-10-12 18:19:22 +02:00
|
|
|
Com_Printf(
|
|
|
|
"^~^~^ LD ERROR: (entnum %i, radnum %i, targetname '%s'): increasing maxdist from %g to %g to exceed "
|
|
|
|
"mindist.\n"
|
|
|
|
"^~^~^ Maxdist should be %i greater than mindist, or the AI will want to both run away and charge, or just "
|
2023-10-16 23:42:30 +02:00
|
|
|
"do oscillitaroy behavior.\n"
|
2023-10-11 22:49:06 +02:00
|
|
|
"\n",
|
|
|
|
entnum,
|
|
|
|
radnum,
|
2023-10-16 23:42:30 +02:00
|
|
|
TargetName().c_str(),
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fMaxDistance,
|
2023-10-16 23:42:30 +02:00
|
|
|
m_fMinDistance + 128.0,
|
2023-10-12 18:19:22 +02:00
|
|
|
128
|
|
|
|
);
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
m_fMaxDistance = m_fMinDistance + 128;
|
|
|
|
m_fMaxDistanceSquared = Square(m_fMaxDistance);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
if (world->farplane_distance > 0 && m_fMaxDistance > world->farplane_distance * 0.828f) {
|
|
|
|
Com_Printf(
|
|
|
|
"^~^~^ LD ERROR: (entnum %i, radnum %i, targetname '%s'): reducing maxdist from %g to %g to be %g%% "
|
|
|
|
"of farplane.\n"
|
|
|
|
"^~^~^ Maxdist should be this distance within fog, or AI will be able to see and attack through fog.\n"
|
|
|
|
"\n",
|
|
|
|
entnum,
|
|
|
|
radnum,
|
|
|
|
TargetName().c_str(),
|
|
|
|
m_fMaxDistance,
|
|
|
|
world->farplane_distance * 0.828,
|
|
|
|
2.0
|
|
|
|
);
|
|
|
|
|
|
|
|
m_fMaxDistance = world->farplane_distance * 0.828f;
|
|
|
|
m_fMaxDistanceSquared = Square(m_fMaxDistance);
|
|
|
|
|
|
|
|
if (m_fMaxDistance < m_fMinDistance + 128.0 - 1.0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Com_Printf(
|
2023-10-16 23:42:30 +02:00
|
|
|
"^~^~^ LD ERROR: (entnum %i, radnum %i, targetname '%s'): reducing mindist from %g to %g to be less "
|
|
|
|
"than maxdist after fog adjustment.\n"
|
2023-10-11 22:49:06 +02:00
|
|
|
"\n",
|
|
|
|
entnum,
|
|
|
|
radnum,
|
2023-10-16 23:42:30 +02:00
|
|
|
TargetName().c_str(),
|
|
|
|
m_fMinDistance,
|
|
|
|
((m_fMaxDistance > 128) ? (m_fMaxDistance - 128) : 0)
|
2023-10-12 18:19:22 +02:00
|
|
|
);
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
m_fMinDistance = m_fMaxDistance - 128;
|
|
|
|
if (m_fMinDistance < 0) {
|
|
|
|
m_fMinDistance = 0;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
m_fMinDistanceSquared = Square(m_fMinDistance);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::AttackEntryAnimation
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if actor stands/draws his weapon.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::AttackEntryAnimation(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
float fDistSquared;
|
|
|
|
vec2_t vDelta;
|
|
|
|
|
|
|
|
if (!m_Enemy) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (level.inttime >= level.m_iAttackEntryAnimTime + 3000) {
|
|
|
|
VectorSub2D(m_Enemy->origin, origin, vDelta);
|
|
|
|
fDistSquared = VectorLength2DSquared(vDelta);
|
|
|
|
|
|
|
|
if (!m_bNoSurprise && fDistSquared < Square(256)) {
|
|
|
|
if (fDistSquared / 384.f < rand()) {
|
|
|
|
StartAnimation(ANIM_MODE_NORMAL, STRING_ANIM_STANDSHOCK_SCR);
|
|
|
|
m_bNoSurprise = true;
|
|
|
|
m_bNewEnemy = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
} else if (fDistSquared > Square(1024)) {
|
|
|
|
Sentient *pSquadMate;
|
|
|
|
|
|
|
|
for (pSquadMate = m_pNextSquadMate; pSquadMate != this; pSquadMate = pSquadMate->m_pNextSquadMate) {
|
|
|
|
if (Square(m_fInterval) * 4 > (pSquadMate->origin - origin).lengthSquared()) {
|
|
|
|
SetDesiredYawDest(m_Enemy->origin);
|
|
|
|
SetDesiredLookDir(m_Enemy->origin - origin);
|
|
|
|
|
|
|
|
StartAnimation(ANIM_MODE_NORMAL, STRING_ANIM_STANDIDENTIFY_SCR);
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bNoSurprise = true;
|
2023-10-12 18:19:22 +02:00
|
|
|
m_bNewEnemy = false;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_bNewEnemy) {
|
|
|
|
Anim_Say(STRING_ANIM_SAY_SIGHTED_SCR, 200, true);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
m_bNoSurprise = true;
|
|
|
|
m_bNewEnemy = false;
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::CheckForThinkStateTransition
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Check for all thinkstates transitions.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::CheckForThinkStateTransition(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
if (CheckForTransition(THINKSTATE_GRENADE, THINKLEVEL_IDLE)
|
|
|
|
|| CheckForTransition(THINKSTATE_BADPLACE, THINKLEVEL_IDLE)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_bEnableEnemy) {
|
|
|
|
CheckForTransition(THINKSTATE_IDLE, THINKLEVEL_IDLE);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CheckForTransition(THINKSTATE_ATTACK, THINKLEVEL_IDLE)
|
|
|
|
|| CheckForTransition(THINKSTATE_DISGUISE, THINKLEVEL_IDLE)) {
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
if (CheckForTransition(THINKSTATE_CURIOUS, THINKLEVEL_IDLE)) {
|
|
|
|
m_pszDebugState = "from_sight";
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CheckForTransition(THINKSTATE_IDLE, THINKLEVEL_IDLE);
|
2018-08-19 08:26:59 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::CheckForTransition
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Check for thinkstate transition.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::CheckForTransition(eThinkState state, eThinkLevel level)
|
2018-08-19 08:26:59 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
GlobalFuncs_t *func;
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_ThinkStates[level] == state) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
func = &GlobalFuncs[m_ThinkMap[state]];
|
|
|
|
if (!func->PassesTransitionConditions) {
|
|
|
|
return false;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!(this->*(func->PassesTransitionConditions))()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetThinkState(state, THINKLEVEL_IDLE);
|
|
|
|
return true;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::PassesTransitionConditions_Grenade
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Should actor transition think state to grenade ?
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::PassesTransitionConditions_Grenade(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-23 11:59:06 +02:00
|
|
|
if (!m_bIsCurious) {
|
|
|
|
// Added in 2.30
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_bLockThinkState || !m_bEnableEnemy) {
|
|
|
|
return false;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!m_pGrenade) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_fGrenadeAwareness >= random();
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 19:21:41 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::PassesTransitionConditions_BadPlace
|
|
|
|
|
|
|
|
Should actor transition think state to bad place?
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
bool Actor::PassesTransitionConditions_BadPlace(void)
|
|
|
|
{
|
|
|
|
if (m_bLockThinkState) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return m_iBadPlaceIndex != 0;
|
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PassesTransitionConditions_Attack
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Should actor transition think state to attack ?
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::PassesTransitionConditions_Attack(void)
|
2018-08-19 08:26:59 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
UpdateEnemy(0);
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_bLockThinkState) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!m_Enemy || (m_Enemy->flags & FL_NOTARGET)) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (EnemyIsDisguised() || !m_PotentialEnemies.IsEnemyConfirmed()) {
|
|
|
|
return false;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
return true;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::PassesTransitionConditions_Disguise
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Should actor transition think state to disguise ?
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::PassesTransitionConditions_Disguise(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
vec2_t vDelta;
|
|
|
|
float fDistSquared;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_bLockThinkState) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_iNextDisguiseTime > level.inttime) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iNextDisguiseTime = level.inttime + 200;
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
UpdateEnemy(200);
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!m_Enemy) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!EnemyIsDisguised()) {
|
|
|
|
return false;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!m_PotentialEnemies.IsEnemyConfirmed()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fabs(m_Enemy->origin[2] - origin[2]) > 48) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorSub2D(m_Enemy->origin, origin, vDelta);
|
|
|
|
fDistSquared = VectorLength2DSquared(vDelta);
|
|
|
|
if (fDistSquared <= Square(32) || fDistSquared >= m_fMaxDisguiseDistSquared) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
Entity *player = G_GetEntity(0);
|
|
|
|
|
|
|
|
return G_SightTrace(
|
|
|
|
EyePosition(),
|
|
|
|
vec_zero,
|
|
|
|
vec_zero,
|
|
|
|
player->centroid,
|
|
|
|
this,
|
|
|
|
player,
|
|
|
|
MASK_TRANSITION,
|
|
|
|
qfalse,
|
|
|
|
"Actor::PassesTransitionConditions_Disguise"
|
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PassesTransitionConditions_Curious
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Should actor transition think state to curious ?
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::PassesTransitionConditions_Curious(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
UpdateEnemy(200);
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_bLockThinkState) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!m_Enemy && m_iCuriousTime) {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetCuriousAnimHint(6);
|
|
|
|
return true;
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_Enemy && !EnemyIsDisguised() && !m_PotentialEnemies.IsEnemyConfirmed()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetCuriousAnimHint(6);
|
|
|
|
return true;
|
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PassesTransitionConditions_Idle
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Should actor transition think state to idle ?
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::PassesTransitionConditions_Idle(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_bEnableEnemy) {
|
|
|
|
UpdateEnemy(500);
|
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_bLockThinkState) {
|
|
|
|
return false;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!m_Enemy && !m_iCuriousTime) {
|
|
|
|
return true;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetRunAnim
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetRunAnim(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddConstString(GetRunAnim());
|
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetWalkAnim
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetWalkAnim(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddConstString(GetWalkAnim());
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PathDistanceAlongVector
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns projected distance from vDir along path.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
float Actor::PathDistanceAlongVector(vec3_t vDir)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
const float *delta = m_Path.CurrentDelta();
|
2018-08-02 15:12:07 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
return DotProduct2D(delta, vDir);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::FaceEnemyOrMotion
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::FaceEnemyOrMotion(int iTimeIntoMove)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
vec2_t vDelta;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
VectorCopy2D(origin, vDelta);
|
|
|
|
|
|
|
|
if (iTimeIntoMove <= 999) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bFaceEnemy = true;
|
2023-10-16 23:42:30 +02:00
|
|
|
} else if (m_Path.CurrentNodeIndex() != m_sCurrentPathNodeIndex) {
|
|
|
|
float fDist;
|
|
|
|
|
|
|
|
fDist = PathDistanceAlongVector(vDelta);
|
|
|
|
|
|
|
|
if (fDist > 0 || VectorLength2DSquared(vDelta) * 4096 < Square(fDist)) {
|
|
|
|
m_bFaceEnemy = false;
|
|
|
|
} else {
|
|
|
|
m_bFaceEnemy = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_sCurrentPathNodeIndex = m_Path.CurrentNodeIndex();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!m_bFaceEnemy) {
|
2023-10-11 22:49:06 +02:00
|
|
|
FaceMotion();
|
2023-10-16 23:42:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2024-02-14 20:22:44 +01:00
|
|
|
if (vDelta[0] < 15 && vDelta[0] > -15 && vDelta[1] < 15 && vDelta[1] > -15) {
|
|
|
|
FaceMotion();
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2024-02-14 20:22:44 +01:00
|
|
|
|
|
|
|
vDelta[0] = -vDelta[0];
|
|
|
|
vDelta[1] = -vDelta[1];
|
|
|
|
FaceDirectionDuringMotion(vDelta);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::FaceDirectionDuringMotion
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Face direction during motion.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::FaceDirectionDuringMotion(vec3_t vLook)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
float yaw;
|
|
|
|
|
|
|
|
SetDesiredLookDir(vLook);
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!velocity[0] && !velocity[1]) {
|
|
|
|
SetDesiredYawDir(vLook);
|
|
|
|
return;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
float fDot = DotProduct2D(velocity, vLook);
|
|
|
|
float fDotSquared = Square(fDot);
|
|
|
|
float fMagsSquared = VectorLength2DSquared(vLook) * VectorLength2DSquared(velocity);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
yaw = velocity.toYaw();
|
|
|
|
|
|
|
|
if (fDotSquared < fMagsSquared / 2.f) {
|
|
|
|
if (velocity.y * vLook[0] > velocity.x * vLook[1]) {
|
|
|
|
yaw -= 90;
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-16 23:42:30 +02:00
|
|
|
yaw -= 270;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (yaw < 0) {
|
|
|
|
yaw += 360;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
} else if (fDot < 0) {
|
|
|
|
yaw -= 180;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (yaw < 0) {
|
|
|
|
yaw += 360;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
SetDesiredYaw(yaw);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetAnimName
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetAnimName(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddConstString(m_csAnimName);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetAnimName
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetAnimName(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
m_csAnimName = ev->GetConstString(1);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetDisguiseRange
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetDisguiseRange(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
m_fMaxDisguiseDistSquared = ev->GetFloat(1);
|
|
|
|
m_fMaxDisguiseDistSquared = Square(m_fMaxDisguiseDistSquared);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetDisguiseRange
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetDisguiseRange(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddFloat(sqrt(m_fMaxDisguiseDistSquared));
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetDisguisePeriod
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetDisguisePeriod(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
m_iDisguisePeriod = ev->GetFloat(1) * 1000 + 0.5;
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetDisguisePeriod
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetDisguisePeriod(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddFloat(m_iDisguisePeriod / 1000.0);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::FaceMotion
|
2018-09-17 23:50:38 +02:00
|
|
|
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::FaceMotion(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
vec2_t vDelta;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (VectorLength2DSquared(velocity) > 1) {
|
2023-10-11 22:49:06 +02:00
|
|
|
vec3_t dir;
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
VectorCopy2D(velocity, dir);
|
|
|
|
VectorSub2D(origin, m_vOriginHistory[m_iCurrentHistory], vDelta);
|
|
|
|
|
2024-02-14 20:22:44 +01:00
|
|
|
if (VectorLength2DSquared(vDelta) >= 1 && DotProduct2D(vDelta, dir) > 0) {
|
2023-10-16 23:42:30 +02:00
|
|
|
VectorCopy2D(vDelta, dir);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-02-14 20:22:44 +01:00
|
|
|
dir[2] = 0;
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_ThinkState == THINKSTATE_IDLE) {
|
2023-10-11 22:49:06 +02:00
|
|
|
IdleLook(dir);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetDesiredLookDir(dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
SetDesiredYawDir(dir);
|
2023-10-16 23:42:30 +02:00
|
|
|
} else if (m_ThinkState == THINKSTATE_IDLE) {
|
|
|
|
IdleLook();
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-16 23:42:30 +02:00
|
|
|
ForwardLook();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::ForceAttackPlayer
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ForceAttackPlayer(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
m_PotentialEnemies.ConfirmEnemy(this, static_cast<Sentient *>(G_GetEntity(0)));
|
|
|
|
m_bForceAttackPlayer = true;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventAttackPlayer
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventAttackPlayer(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!G_GetEntity(0)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("player doesn't exist");
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
ForceAttackPlayer();
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventShareEnemy
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Share enemy with squad mates.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventShareEnemy(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
Sentient *pSquadMate;
|
|
|
|
|
|
|
|
if (!m_Enemy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (EnemyIsDisguised()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pSquadMate = m_pNextSquadMate; pSquadMate != this; pSquadMate = pSquadMate->m_pNextSquadMate) {
|
|
|
|
if (!pSquadMate->IsSubclassOfActor()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Actor *pActorSquadMate = static_cast<Actor *>(pSquadMate);
|
|
|
|
|
|
|
|
if (!m_fMaxShareDistSquared || m_fMaxShareDistSquared < (pActorSquadMate->origin - origin).lengthSquared()) {
|
|
|
|
pActorSquadMate->m_PotentialEnemies.ConfirmEnemyIfCanSeeSharerOrEnemy(pActorSquadMate, this, m_Enemy);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::EventShareGrenade
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Share grenade with squad mates.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventShareGrenade(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
Sentient *pSquadMate;
|
|
|
|
|
|
|
|
if (!m_pGrenade) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (pSquadMate = m_pNextSquadMate; pSquadMate != this; pSquadMate = pSquadMate->m_pNextSquadMate) {
|
|
|
|
if (!pSquadMate->IsSubclassOfActor()) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
Actor *pActorSquadMate = static_cast<Actor *>(pSquadMate);
|
|
|
|
|
|
|
|
if (pActorSquadMate->m_pGrenade) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((pSquadMate->origin - origin).lengthSquared() < Square(768)
|
|
|
|
&& DoesTheoreticPathExist(pSquadMate->origin, 1536)) {
|
|
|
|
pActorSquadMate->SetGrenade(m_pGrenade);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ReceiveAIEvent
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Calls proper RecieveAIEvent for current ThinkState.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ReceiveAIEvent(
|
|
|
|
vec3_t event_origin, int iType, Entity *originator, float fDistSquared, float fMaxDistSquared
|
|
|
|
)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
if (originator) {
|
|
|
|
if (originator == this || originator == GetActiveWeapon(WEAPON_MAIN)) {
|
|
|
|
return;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
GlobalFuncs_t *func = &GlobalFuncs[CurrentThink()];
|
|
|
|
|
|
|
|
if (func->ReceiveAIEvent) {
|
|
|
|
(this->*func->ReceiveAIEvent)(event_origin, iType, originator, fDistSquared, fMaxDistSquared);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::DefaultReceiveAIEvent
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Default AI event handler.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::DefaultReceiveAIEvent(
|
|
|
|
vec3_t event_origin, int iType, Entity *originator, float fDistSquared, float fMaxDistSquared
|
|
|
|
)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-14 01:16:50 +02:00
|
|
|
if (IsDead()) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 00:29:41 +02:00
|
|
|
if (originator && !originator->IsDead() && originator->IsSubclassOfSentient()
|
|
|
|
&& ((Sentient *)originator)->m_Team == m_Team && !IsSquadMate((Sentient *)originator)) {
|
|
|
|
MergeWithSquad((Sentient *)originator);
|
2023-10-14 01:16:50 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
switch (iType) {
|
|
|
|
case AI_EVENT_WEAPON_FIRE:
|
|
|
|
case AI_EVENT_WEAPON_IMPACT:
|
2023-10-16 23:42:30 +02:00
|
|
|
if (fDistSquared < Square(m_fHearing)) {
|
2023-10-14 01:16:50 +02:00
|
|
|
WeaponSound(iType, event_origin, fDistSquared, fMaxDistSquared, originator);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AI_EVENT_EXPLOSION:
|
|
|
|
case AI_EVENT_MISC:
|
|
|
|
case AI_EVENT_MISC_LOUD:
|
2023-10-16 23:42:30 +02:00
|
|
|
if (fDistSquared < Square(m_fHearing)) {
|
2023-10-14 01:16:50 +02:00
|
|
|
CuriousSound(iType, event_origin, fDistSquared, fMaxDistSquared);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AI_EVENT_AMERICAN_VOICE:
|
|
|
|
case AI_EVENT_GERMAN_VOICE:
|
|
|
|
case AI_EVENT_AMERICAN_URGENT:
|
|
|
|
case AI_EVENT_GERMAN_URGENT:
|
2023-10-16 23:42:30 +02:00
|
|
|
if (fDistSquared < Square(m_fHearing)) {
|
2023-10-14 01:16:50 +02:00
|
|
|
VoiceSound(iType, event_origin, fDistSquared, fMaxDistSquared, originator);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AI_EVENT_FOOTSTEP:
|
2023-10-16 23:42:30 +02:00
|
|
|
if (fDistSquared < Square(m_fHearing)) {
|
2023-10-14 01:16:50 +02:00
|
|
|
FootstepSound(event_origin, fDistSquared, fMaxDistSquared, originator);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-14 01:16:50 +02:00
|
|
|
break;
|
|
|
|
case AI_EVENT_GRENADE:
|
|
|
|
GrenadeNotification(originator);
|
|
|
|
break;
|
|
|
|
case AI_EVENT_BADPLACE:
|
|
|
|
UpdateBadPlaces();
|
|
|
|
break;
|
|
|
|
default:
|
2023-10-16 00:29:41 +02:00
|
|
|
{
|
|
|
|
char assertStr[16317] = {0};
|
|
|
|
strcpy(assertStr, "\"unknown ai_event type\"\n\tMessage: ");
|
|
|
|
Q_strcat(assertStr, sizeof(assertStr), DumpCallTrace("iType = %i", iType));
|
|
|
|
assert(false && assertStr);
|
|
|
|
}
|
|
|
|
break;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::PriorityForEventType
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns priority for event type.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
int Actor::PriorityForEventType(int iType)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
switch (iType) {
|
2023-10-16 23:42:30 +02:00
|
|
|
//FIXME: return macros
|
2023-10-11 22:49:06 +02:00
|
|
|
case AI_EVENT_WEAPON_FIRE:
|
|
|
|
return 7;
|
|
|
|
case AI_EVENT_WEAPON_IMPACT:
|
|
|
|
return 5;
|
|
|
|
case AI_EVENT_EXPLOSION:
|
|
|
|
return 6;
|
|
|
|
case AI_EVENT_AMERICAN_VOICE:
|
|
|
|
case AI_EVENT_GERMAN_VOICE:
|
|
|
|
return 3;
|
|
|
|
case AI_EVENT_AMERICAN_URGENT:
|
|
|
|
case AI_EVENT_GERMAN_URGENT:
|
|
|
|
return 4;
|
|
|
|
case AI_EVENT_MISC:
|
|
|
|
return 1;
|
|
|
|
case AI_EVENT_MISC_LOUD:
|
|
|
|
case AI_EVENT_FOOTSTEP:
|
|
|
|
return 2;
|
|
|
|
case AI_EVENT_GRENADE:
|
|
|
|
return 8;
|
|
|
|
default:
|
2023-10-12 18:19:22 +02:00
|
|
|
assert(!"PriorityForEventType: unknown ai_event type");
|
2023-10-11 22:49:06 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *DebugStringForEvent(int iType)
|
|
|
|
{
|
|
|
|
switch (iType) {
|
|
|
|
case AI_EVENT_WEAPON_FIRE:
|
|
|
|
return "weapon_fire";
|
|
|
|
case AI_EVENT_WEAPON_IMPACT:
|
|
|
|
return "weapon_impact";
|
|
|
|
case AI_EVENT_EXPLOSION:
|
|
|
|
return "explosion";
|
|
|
|
case AI_EVENT_AMERICAN_VOICE:
|
|
|
|
return "american_voice";
|
|
|
|
case AI_EVENT_GERMAN_VOICE:
|
|
|
|
return "german_voice";
|
|
|
|
case AI_EVENT_AMERICAN_URGENT:
|
|
|
|
return "american_urgent";
|
|
|
|
case AI_EVENT_GERMAN_URGENT:
|
|
|
|
return "german_urgent";
|
|
|
|
case AI_EVENT_MISC:
|
|
|
|
return "misc";
|
|
|
|
case AI_EVENT_MISC_LOUD:
|
|
|
|
return "misc_loud";
|
|
|
|
case AI_EVENT_FOOTSTEP:
|
|
|
|
return "footstep";
|
|
|
|
case AI_EVENT_GRENADE:
|
|
|
|
return "grenade";
|
|
|
|
default:
|
|
|
|
return "????";
|
|
|
|
}
|
|
|
|
}
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::CuriousSound
|
|
|
|
|
|
|
|
Handles curious sound.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::CuriousSound(int iType, vec3_t sound_origin, float fDistSquared, float fMaxDistSquared)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
float fRangeFactor;
|
2023-10-12 18:19:22 +02:00
|
|
|
int iPriority;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!m_bEnableEnemy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_ThinkStates[THINKLEVEL_IDLE] != THINKSTATE_IDLE && m_ThinkStates[THINKLEVEL_IDLE] != THINKSTATE_CURIOUS) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!m_bIsCurious) {
|
|
|
|
// Added in 2.30
|
|
|
|
return;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
fRangeFactor = 1.0;
|
|
|
|
if (fMaxDistSquared) {
|
|
|
|
fRangeFactor = (4.0 / 3.0 - ((4.0 / 3.0 * fDistSquared) / fMaxDistSquared));
|
|
|
|
if (fRangeFactor > 1) {
|
|
|
|
fRangeFactor = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-08-28 00:41:53 +02:00
|
|
|
if ((fRangeFactor * m_fSoundAwareness) < (rand() / (0x7fffffff / 100.0))) {
|
2023-10-16 23:42:30 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
RaiseAlertnessForEventType(iType);
|
|
|
|
// get the priority
|
|
|
|
iPriority = PriorityForEventType(iType);
|
|
|
|
|
|
|
|
if (iPriority < m_iCuriousLevel) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_iCuriousLevel = iPriority;
|
|
|
|
switch (iType) {
|
|
|
|
case AI_EVENT_WEAPON_IMPACT:
|
|
|
|
if (fDistSquared <= Square(192)) {
|
|
|
|
SetCuriousAnimHint(1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case AI_EVENT_EXPLOSION:
|
|
|
|
if (fDistSquared <= Square(768)) {
|
|
|
|
SetCuriousAnimHint(3);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
break;
|
|
|
|
case AI_EVENT_WEAPON_FIRE:
|
|
|
|
if (fDistSquared <= Square(512)) {
|
|
|
|
SetCuriousAnimHint(2);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
SetCuriousAnimHint(5);
|
|
|
|
break;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
SetEnemyPos(sound_origin);
|
|
|
|
|
|
|
|
EndCurrentThinkState();
|
|
|
|
SetThinkState(THINKSTATE_CURIOUS, THINKLEVEL_IDLE);
|
|
|
|
|
|
|
|
m_pszDebugState = DebugStringForEvent(iType);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::WeaponSound
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Handles weapon sound.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::WeaponSound(int iType, vec3_t sound_origin, float fDistSquared, float fMaxDistSquared, Entity *originator)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
Sentient *pOwner;
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (originator->IsSubclassOfWeapon()) {
|
2023-10-16 23:42:30 +02:00
|
|
|
pOwner = static_cast<Weapon *>(originator)->GetOwner();
|
|
|
|
} else if (originator->IsSubclassOfProjectile()) {
|
|
|
|
pOwner = static_cast<Projectile *>(originator)->GetOwner();
|
|
|
|
} else if (originator->IsSubclassOfSentient()) {
|
|
|
|
pOwner = static_cast<Sentient *>(originator);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-16 23:42:30 +02:00
|
|
|
char assertStr[16317] = {0};
|
|
|
|
strcpy(assertStr, "\"Actor::WeaponSound: non-weapon made a weapon sound.\\n\"\n\tMessage: ");
|
|
|
|
Q_strcat(assertStr, sizeof(assertStr), DumpCallTrace("class = %s", originator->getClassname()));
|
|
|
|
assert(false && assertStr);
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!pOwner) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return;
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Sentient *pEnemy;
|
|
|
|
|
2023-10-31 23:23:29 +01:00
|
|
|
pEnemy = pOwner;
|
|
|
|
|
|
|
|
if (pOwner->m_Team == m_Team) {
|
|
|
|
pEnemy = pOwner->m_Enemy;
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
2023-10-31 23:23:29 +01:00
|
|
|
if (pOwner->m_Team == m_Team && !pEnemy && pOwner->IsSubclassOfActor()
|
2023-10-16 23:42:30 +02:00
|
|
|
&& originator->IsSubclassOfWeapon()) {
|
|
|
|
Actor *pActor = static_cast<Actor *>(pOwner);
|
|
|
|
Weapon *pWeapon = static_cast<Weapon *>(originator);
|
|
|
|
|
|
|
|
if (pActor->m_Think[THINKLEVEL_IDLE] == THINK_MACHINEGUNNER && pWeapon->aim_target) {
|
|
|
|
if (pWeapon->aim_target->IsSubclassOfSentient()) {
|
|
|
|
Sentient *pTarget = static_cast<Sentient *>(pWeapon->aim_target.Pointer());
|
2024-02-20 22:57:02 +01:00
|
|
|
if (pTarget->m_Team == m_Team) {
|
2023-10-16 23:42:30 +02:00
|
|
|
pEnemy = pTarget;
|
|
|
|
}
|
|
|
|
} else if (!m_Team) {
|
|
|
|
for (pEnemy = level.m_HeadSentient[TEAM_AMERICAN]; pEnemy; pEnemy = pEnemy->m_NextSentient) {
|
|
|
|
if ((pEnemy->origin - pWeapon->aim_target->centroid).lengthSquared() < Square(48)) {
|
|
|
|
break;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (pEnemy && m_PotentialEnemies.CaresAboutPerfectInfo(pEnemy) && NoticeShot(pOwner, pEnemy, sqrt(fDistSquared))) {
|
|
|
|
if (pOwner->m_Team != m_Team) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_PotentialEnemies.ConfirmEnemy(this, pOwner);
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
CuriousSound(iType, sound_origin, fDistSquared, fMaxDistSquared);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::FootstepSound
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Handles footstep sound.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::FootstepSound(vec3_t sound_origin, float fDistSquared, float fMaxDistSquared, Entity *originator)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!originator->IsSubclassOfSentient()) {
|
2023-10-12 18:19:22 +02:00
|
|
|
char assertStr[16317] = {0};
|
2023-10-11 22:49:06 +02:00
|
|
|
strcpy(assertStr, "\"'ai_event footstep' in a tiki used by something besides AI or player.\\n\"\n\tMessage: ");
|
|
|
|
Q_strcat(assertStr, sizeof(assertStr), DumpCallTrace(""));
|
|
|
|
assert(false && assertStr);
|
2023-10-16 23:42:30 +02:00
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
if (m_ThinkStates[THINKLEVEL_IDLE] != THINKSTATE_IDLE && m_ThinkStates[THINKLEVEL_IDLE] != THINKSTATE_CURIOUS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_bEnableEnemy) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!NoticeFootstep(static_cast<Sentient *>(originator))) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
CuriousSound(AI_EVENT_FOOTSTEP, sound_origin, fDistSquared, fMaxDistSquared);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::VoiceSound
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Handles voice sound.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::VoiceSound(int iType, vec3_t sound_origin, float fDistSquared, float fMaxDistSquared, Entity *originator)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
bool bFriendly;
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
if (m_ThinkStates[THINKLEVEL_IDLE] != THINKSTATE_IDLE && m_ThinkStates[THINKLEVEL_IDLE] != THINKSTATE_CURIOUS) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!m_bEnableEnemy) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
switch (iType) {
|
|
|
|
case AI_EVENT_AMERICAN_VOICE:
|
|
|
|
case AI_EVENT_AMERICAN_URGENT:
|
|
|
|
bFriendly = m_Team == TEAM_AMERICAN;
|
|
|
|
break;
|
|
|
|
case AI_EVENT_GERMAN_VOICE:
|
|
|
|
case AI_EVENT_GERMAN_URGENT:
|
|
|
|
bFriendly = m_Team == TEAM_GERMAN;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!bFriendly) {
|
|
|
|
CuriousSound(iType, sound_origin, fDistSquared, fMaxDistSquared);
|
|
|
|
} else if (NoticeVoice(static_cast<Sentient *>(originator))) {
|
|
|
|
CuriousSound(iType, sound_origin, fDistSquared, fMaxDistSquared);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::GrenadeNotification
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Handles grenade notification.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::GrenadeNotification(Entity *originator)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
if (!m_pGrenade && CanSeeFOV(originator) && originator->IsSubclassOfProjectile()) {
|
|
|
|
Projectile *proj = static_cast<Projectile *>(originator);
|
|
|
|
Entity *projOwner = NULL;
|
|
|
|
Sentient *sentientOwner = NULL;
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
SetGrenade(originator);
|
|
|
|
PostEvent(EV_Actor_ShareGrenade, 0.5f);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (proj->owner != ENTITYNUM_NONE) {
|
|
|
|
projOwner = G_GetEntity(proj->owner);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (projOwner && projOwner->IsSubclassOfSentient()) {
|
|
|
|
sentientOwner = static_cast<Sentient *>(projOwner);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!sentientOwner || sentientOwner->m_Team != m_Team) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Anim_Say(STRING_ANIM_SAY_GRENADE_SIGHTED_SCR, 0, true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_pGrenade == originator) {
|
2023-10-16 23:42:30 +02:00
|
|
|
float fTimeLand;
|
|
|
|
float fVelDivGrav;
|
2023-10-11 22:49:06 +02:00
|
|
|
vec2_t vLand;
|
|
|
|
vec2_t vMove;
|
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
fVelDivGrav = originator->velocity[2] / (sv_gravity->value * m_pGrenade->gravity);
|
|
|
|
fTimeLand = fVelDivGrav
|
|
|
|
+ sqrt(
|
|
|
|
Square(fVelDivGrav)
|
|
|
|
+ Square(originator->origin[2] - origin[2]) / (sv_gravity->value * m_pGrenade->gravity)
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
VectorMA2D(originator->origin, fTimeLand, originator->velocity, vLand);
|
|
|
|
VectorSub2D(m_vGrenadePos, vLand, vMove);
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (VectorLength2DSquared(vMove) > Square(4)) {
|
|
|
|
VectorCopy2D(vLand, m_vGrenadePos);
|
|
|
|
m_vGrenadePos[2] = origin[2];
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bGrenadeBounced = true;
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::SetGrenade
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Set current grenade.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetGrenade(Entity *pGrenade)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
m_pGrenade = pGrenade;
|
|
|
|
m_bGrenadeBounced = true;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iFirstGrenadeTime = level.inttime;
|
2023-10-16 23:42:30 +02:00
|
|
|
m_vGrenadePos = pGrenade->origin;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-12 19:21:41 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::UpdateBadPlaces
|
|
|
|
|
|
|
|
Update bad places, with a new path
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void Actor::UpdateBadPlaces(void)
|
|
|
|
{
|
|
|
|
m_iBadPlaceIndex = 0;
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_bIgnoreBadPlace) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-12 19:21:41 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
if (PathExists()) {
|
|
|
|
m_Path.ReFindPath(origin, this);
|
2023-10-12 19:21:41 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
m_iBadPlaceIndex = level.GetNearestBadPlace(origin, 64, 1 << m_Team);
|
2023-10-12 19:21:41 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::NotifySquadmateKilled
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Handle squadmate killed notification.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::NotifySquadmateKilled(Sentient *pSquadMate, Sentient *pAttacker)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
Vector vDelta;
|
|
|
|
float fSquareDist;
|
|
|
|
bool bCanSee;
|
|
|
|
|
|
|
|
if (!m_PotentialEnemies.CaresAboutPerfectInfo(pAttacker)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vDelta = pSquadMate->origin - origin;
|
|
|
|
fSquareDist = vDelta.lengthSquared();
|
|
|
|
if (fSquareDist > Square(m_fSight)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
bCanSee = false;
|
|
|
|
if (AreasConnected(pSquadMate)) {
|
|
|
|
bCanSee = G_SightTrace(
|
|
|
|
VirtualEyePosition(),
|
|
|
|
vec_zero,
|
|
|
|
vec_zero,
|
|
|
|
pSquadMate->EyePosition(),
|
|
|
|
this,
|
|
|
|
pSquadMate,
|
|
|
|
MASK_AI_CANSEE,
|
|
|
|
qfalse,
|
|
|
|
"Actor::NotifySquadmateKilled"
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bCanSee) {
|
|
|
|
if (fSquareDist > Square(768)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (origin.z > pSquadMate->origin.z) {
|
|
|
|
if (!m_Path.DoesTheoreticPathExist(origin, pSquadMate->origin, this, 1536, NULL, 0)) {
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
} else {
|
|
|
|
if (!m_Path.DoesTheoreticPathExist(pSquadMate->origin, origin, this, 1536, NULL, 0)) {
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
|
|
|
|
m_PotentialEnemies.ConfirmEnemy(this, pAttacker);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::RaiseAlertnessForEventType
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Raise alertness(enemy notice) for specifc event.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::RaiseAlertnessForEventType(int iType)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
switch (iType) {
|
2023-10-11 22:49:06 +02:00
|
|
|
case AI_EVENT_WEAPON_FIRE:
|
2023-10-16 23:42:30 +02:00
|
|
|
RaiseAlertness(0.2f);
|
|
|
|
break;
|
2023-10-11 22:49:06 +02:00
|
|
|
case AI_EVENT_WEAPON_IMPACT:
|
2023-10-16 23:42:30 +02:00
|
|
|
RaiseAlertness(0.1f);
|
|
|
|
break;
|
2023-10-11 22:49:06 +02:00
|
|
|
case AI_EVENT_EXPLOSION:
|
2023-10-16 23:42:30 +02:00
|
|
|
RaiseAlertness(0.4f);
|
|
|
|
break;
|
2023-10-11 22:49:06 +02:00
|
|
|
case AI_EVENT_AMERICAN_VOICE:
|
|
|
|
case AI_EVENT_AMERICAN_URGENT:
|
2023-10-16 23:42:30 +02:00
|
|
|
if (m_Team == TEAM_GERMAN) {
|
|
|
|
RaiseAlertness(0.25f);
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
break;
|
|
|
|
case AI_EVENT_GERMAN_VOICE:
|
|
|
|
case AI_EVENT_GERMAN_URGENT:
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_Team == TEAM_AMERICAN) {
|
2023-10-11 22:49:06 +02:00
|
|
|
RaiseAlertness(0.25);
|
|
|
|
}
|
2023-10-16 23:42:30 +02:00
|
|
|
break;
|
|
|
|
case AI_EVENT_MISC:
|
|
|
|
RaiseAlertness(0.02f);
|
|
|
|
break;
|
|
|
|
case AI_EVENT_MISC_LOUD:
|
|
|
|
case AI_EVENT_FOOTSTEP:
|
|
|
|
RaiseAlertness(0.05f);
|
|
|
|
break;
|
|
|
|
case AI_EVENT_GRENADE:
|
|
|
|
RaiseAlertness(0.04f);
|
|
|
|
break;
|
2023-10-11 22:49:06 +02:00
|
|
|
default:
|
2023-10-12 18:19:22 +02:00
|
|
|
char assertStr[16317] = {0};
|
2023-10-11 22:49:06 +02:00
|
|
|
strcpy(assertStr, "\"Actor::RaiseAlertnessForEventType: unknown event type\\n\"\n\tMessage: ");
|
|
|
|
Q_strcat(assertStr, sizeof(assertStr), DumpCallTrace(""));
|
|
|
|
assert(false && assertStr);
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::RaiseAlertness
|
|
|
|
|
|
|
|
Lower enemy notice time by fAmount.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::RaiseAlertness(float fAmount)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
if (fAmount > m_fNoticeTimeScale * (2.0 / 3.0)) {
|
|
|
|
fAmount = m_fNoticeTimeScale * (2.0 / 3.0);
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-16 23:42:30 +02:00
|
|
|
m_fNoticeTimeScale -= fAmount;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::NoticeShot
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if shooter is an enemy.
|
|
|
|
Otherwise the shooter is a team mate and target is registered an enemy if he's visible/reachable.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::NoticeShot(Sentient *pShooter, Sentient *pTarget, float fDist)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (pShooter->m_Team != m_Team) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return true;
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bEnemyIsDisguised = false;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (pTarget) {
|
2023-10-16 23:42:30 +02:00
|
|
|
if (DoesTheoreticPathExist(pShooter->origin, fDist * 1.5f)
|
|
|
|
|| CanSee(pTarget, 0, world->farplane_distance * 0.828, false)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_PotentialEnemies.ConfirmEnemy(this, pTarget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::NoticeFootstep
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if actor should notice this footstep sound (pedestrian is not visible for actor).
|
|
|
|
Otherwise returns false.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::NoticeFootstep(Sentient *pPedestrian)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_Team == pPedestrian->m_Team || pPedestrian->m_bIsDisguised) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
return !CanSeeFOV(pPedestrian);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::NoticeVoice
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if actor should notice this voice sound (vocalist is not visible for actor).
|
|
|
|
Otherwise returns false.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::NoticeVoice(Sentient *pVocallist)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-16 23:42:30 +02:00
|
|
|
return !IsSquadMate(pVocallist) && !CanSeeFOV(pVocallist);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::ValidGrenadePath
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if grenade trajectory is valid.
|
|
|
|
i.e grenade can get from vFrom to vTo with vVel with any obstacles.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::ValidGrenadePath(const Vector& vFrom, const Vector& vTo, Vector& vVel)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
vec3_t mins, maxs;
|
|
|
|
Vector vPoint1, vPoint2, vPoint3;
|
|
|
|
float fTime, fTimeLand;
|
2023-10-17 20:38:58 +02:00
|
|
|
trace_t trace;
|
2023-10-17 23:38:33 +02:00
|
|
|
float fGravity;
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
VectorSet(mins, -4, -4, -4);
|
|
|
|
VectorSet(maxs, 4, 4, 4);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (vVel.lengthSquared() > Square(768)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
fGravity = sv_gravity->value * 0.8f;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
fTime = vVel.z / fGravity * 0.5f;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
vPoint1.x = vVel.x * fTime + vFrom.x;
|
|
|
|
vPoint1.y = vVel.y * fTime + vFrom.y;
|
|
|
|
vPoint1.z = vVel.z * fTime * 0.75 + vFrom.z;
|
2023-10-17 23:38:33 +02:00
|
|
|
maxs[2] = fGravity / 8.0f * fTime * fTime + 4.0f;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (ai_debug_grenades->integer) {
|
2023-10-11 22:49:06 +02:00
|
|
|
G_DebugLine(vFrom, vPoint1, 1.0, 0.5, 0.5, 1.0);
|
|
|
|
}
|
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
if (!G_SightTrace(vFrom, mins, maxs, vPoint1, this, NULL, MASK_GRENADEPATH, qfalse, "Actor::ValidGrenadePath 1")) {
|
2023-10-17 20:38:58 +02:00
|
|
|
return false;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
fTime *= 2;
|
|
|
|
vPoint2.x = vVel.x * fTime + vFrom.x;
|
|
|
|
vPoint2.y = vVel.y * fTime + vFrom.y;
|
|
|
|
vPoint2.z = vVel.z * fTime * 0.5 + vFrom.z;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (ai_debug_grenades->integer) {
|
|
|
|
G_DebugLine(vPoint1, vPoint2, 1.0, 0.5, 0.5, 1.0);
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (!G_SightTrace(
|
2023-10-17 23:38:33 +02:00
|
|
|
vPoint1, mins, maxs, vPoint2, this, NULL, MASK_GRENADEPATH, qfalse, "Actor::ValidGrenadePath 2"
|
|
|
|
)) {
|
2023-10-17 20:38:58 +02:00
|
|
|
return false;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (fabs(vVel.x) > fabs(vVel.y)) {
|
|
|
|
fTimeLand = (vTo.x - vFrom.x) / vVel.x;
|
2023-10-17 23:38:33 +02:00
|
|
|
} else {
|
2023-10-17 20:38:58 +02:00
|
|
|
fTimeLand = (vTo.y - vFrom.y) / vVel.y;
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
maxs[2] = fGravity / 32.f * (fTimeLand - fTime) * (fTimeLand - fTime) + 4;
|
2023-10-17 23:38:33 +02:00
|
|
|
fTime = (fTime + fTimeLand) * 0.5f;
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
vPoint3.x = vVel.x * fTime + vFrom.x;
|
|
|
|
vPoint3.y = vVel.y * fTime + vFrom.y;
|
|
|
|
vPoint3.z = vFrom.z + (vVel.z - fGravity * 0.5 * fTime) * fTime;
|
|
|
|
|
|
|
|
if (ai_debug_grenades->integer) {
|
|
|
|
G_DebugLine(vPoint2, vPoint3, 1.0, 0.5, 0.5, 1.0);
|
|
|
|
}
|
|
|
|
if (!G_SightTrace(
|
2023-10-17 23:38:33 +02:00
|
|
|
vPoint2, mins, maxs, vPoint3, this, NULL, MASK_GRENADEPATH, qfalse, "Actor::ValidGrenadePath 3"
|
|
|
|
)) {
|
2023-10-17 20:38:58 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (ai_debug_grenades->integer) {
|
|
|
|
G_DebugLine(vPoint3, vTo, 1.0, 0.5, 0.5, 1.0);
|
|
|
|
}
|
|
|
|
|
|
|
|
trace = G_Trace(vPoint3, mins, maxs, vTo, this, MASK_GRENADEPATH, qfalse, "Actor::ValidGrenadePath 4");
|
|
|
|
if (!trace.allsolid) {
|
|
|
|
if (!trace.ent) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
if (trace.ent->entity->IsSubclassOfSentient() && static_cast<Sentient *>(trace.ent->entity)->m_Team != m_Team) {
|
2023-10-17 20:38:58 +02:00
|
|
|
return true;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2023-10-17 23:38:33 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (trace.entityNum != ENTITYNUM_WORLD || trace.plane.normal[2] < 0.999f) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2019-06-25 01:17:10 +02:00
|
|
|
}
|
2019-08-13 03:12:07 +02:00
|
|
|
|
|
|
|
/*
|
2023-10-11 22:49:06 +02:00
|
|
|
===============
|
|
|
|
Actor::CalcThrowVelocity
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Calculates required grenade throw velocity to get grenade from vFrom to vTo.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
Vector Actor::CalcThrowVelocity(const Vector& vFrom, const Vector& vTo)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
Vector vDelta;
|
2023-10-17 23:38:33 +02:00
|
|
|
float fHorzDistSquared, fDistance;
|
|
|
|
float fVelHorz, fVelVert;
|
2018-08-29 14:41:48 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
vDelta = vTo - vFrom;
|
2023-10-17 20:38:58 +02:00
|
|
|
fHorzDistSquared = vDelta.lengthXYSquared();
|
2023-10-17 23:38:33 +02:00
|
|
|
fDistance = sqrt(fHorzDistSquared + vDelta.z * vDelta.z);
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
// original irl equation: v10 = sqrt(fGravity * 0.5 * fHorzDistSquared / (fDistance * trigMult ))
|
|
|
|
// trigMult = (cos(th)/ tan(al) - sin(th)/tanSquared(al))
|
|
|
|
// al = inital velocity angle with ground plane.
|
|
|
|
// th = angle between vDelta and ground plane.
|
|
|
|
// mohaa devs decided to let trigMult be 1, for the sake of simplicity I guess.
|
2023-10-17 20:38:58 +02:00
|
|
|
fVelVert = sqrt(sv_gravity->value * 0.8f * 0.5f * fHorzDistSquared / fDistance);
|
2023-10-17 23:38:33 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
// no I dea what this means.
|
|
|
|
// maybe it's related to their angle choice.
|
|
|
|
// calculates the 1/distanceSquared necessary for fOOTime calculation.
|
2023-10-17 20:38:58 +02:00
|
|
|
fVelHorz = sqrt((fDistance + vDelta.z) / (fDistance - vDelta.z) / fHorzDistSquared) * fVelVert;
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
// 1/(speed * sqrt(1/distanceSquared))
|
|
|
|
// 1/(speed * 1/distance)
|
|
|
|
// 1/(1/time)
|
|
|
|
// time
|
2023-10-17 20:38:58 +02:00
|
|
|
return Vector(vDelta.x * fVelHorz, vDelta.y * fVelHorz, fVelVert);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::CanThrowGrenade
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns required velocity to throw grenade from vFrom to vTo.
|
|
|
|
Or vec_zero if it's not possible.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
Vector Actor::CanThrowGrenade(const Vector& vFrom, const Vector& vTo)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
Vector vVel;
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
vVel = CalcThrowVelocity(vFrom, vTo);
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
if (vVel != vec_zero && ValidGrenadePath(vFrom, vTo, vVel)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return vVel;
|
2023-10-17 20:38:58 +02:00
|
|
|
} else {
|
|
|
|
return vec_zero;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::CalcRollVelocity
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Calculates required grenade roll velocity to get grenade from vFrom to vTo.
|
|
|
|
Roll here means a low toss.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
Vector Actor::CalcRollVelocity(const Vector& vFrom, const Vector& vTo)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
Vector vDelta;
|
2023-10-17 23:38:33 +02:00
|
|
|
float fVelVert;
|
|
|
|
float fOOTime;
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
// you must throw from above.
|
|
|
|
// start point must be above (higher) than end point.
|
2023-10-17 20:38:58 +02:00
|
|
|
if (vTo.z >= vFrom.z) {
|
|
|
|
return vec_zero;
|
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
vDelta = vTo - vFrom;
|
|
|
|
// Required down velocity to hit the ground twice as fast as freefall time.
|
|
|
|
fVelVert = sqrt(-vDelta.z * sv_gravity->value * 0.8f);
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
// accel = speed / time, hence : time = speed / accel, 0.21961521 is an arbitary scalar.
|
|
|
|
// since the scalar is way less than 1, it will take more time to hit the ground than to arrive to target dest.
|
|
|
|
// this is kinda like a low toss rather than a roll. if I understand correctly.
|
|
|
|
fOOTime = sv_gravity->value * 0.8f * 0.21961521f / fVelVert;
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
// speed = distance / time
|
|
|
|
return Vector(vDelta.x * fOOTime, vDelta.y * fOOTime, fVelVert);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::CanRollGrenade
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns required velocity to roll grenade from vFrom to vTo.
|
|
|
|
Or vec_zero if it's not possible.
|
|
|
|
Roll here means a low toss.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
Vector Actor::CanRollGrenade(const Vector& vFrom, const Vector& vTo)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
Vector vVel;
|
|
|
|
|
|
|
|
vVel = CalcRollVelocity(vFrom, vTo);
|
|
|
|
|
|
|
|
if (vVel != vec_zero && ValidGrenadePath(vFrom, vTo, vVel)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return vVel;
|
2023-10-17 20:38:58 +02:00
|
|
|
} else {
|
|
|
|
return vec_zero;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::CanTossGrenadeThroughHint
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if actor can toss grenade through specified hint.
|
|
|
|
pvVel and peMode are modified.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::CanTossGrenadeThroughHint(
|
|
|
|
GrenadeHint *pHint, const Vector& vFrom, const Vector& vTo, bool bDesperate, Vector *pvVel, eGrenadeTossMode *peMode
|
|
|
|
)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
Vector vDelta;
|
2023-10-17 23:38:33 +02:00
|
|
|
float fHeight;
|
|
|
|
float fDistSquared, fDist;
|
|
|
|
float fRangeSquared, fRange;
|
|
|
|
float fVelHorz, fVelVert;
|
|
|
|
float fTemp;
|
|
|
|
float fAngle;
|
|
|
|
bool bSuccess;
|
|
|
|
float fGravity;
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
fGravity = sv_gravity->value * 0.8f;
|
2019-06-25 01:17:10 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (bDesperate) {
|
|
|
|
vDelta = pHint->origin - vFrom;
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
fDistSquared = vDelta.lengthXYSquared();
|
|
|
|
if (!fDistSquared) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
fDist = sqrt(fDistSquared);
|
2023-10-17 20:38:58 +02:00
|
|
|
fRangeSquared = vDelta.z * vDelta.z + fDistSquared;
|
2023-10-17 23:38:33 +02:00
|
|
|
fRange = sqrt(fRangeSquared);
|
|
|
|
fHeight = fGravity * fDistSquared / Square(768) + vDelta.z;
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
if (fabs(fHeight) > fabs(fRange)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
fAngle = (asin(fHeight / fRange) + atan(vDelta.z / fDist)) * 0.5f;
|
2023-10-17 20:38:58 +02:00
|
|
|
fVelVert = sin(fAngle) * 768.f;
|
|
|
|
fVelHorz = 768.f / fDist * cos(fAngle);
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
pvVel->x = fVelHorz * vDelta.x;
|
|
|
|
pvVel->y = fVelHorz * vDelta.y;
|
|
|
|
pvVel->z = fVelVert;
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
*peMode = AI_GREN_TOSS_HINT;
|
2023-10-17 20:38:58 +02:00
|
|
|
bSuccess = ValidGrenadePath(vFrom, pHint->origin, *pvVel);
|
|
|
|
} else {
|
2023-10-17 23:38:33 +02:00
|
|
|
vDelta = pHint->origin - vFrom;
|
2023-10-17 20:38:58 +02:00
|
|
|
fDistSquared = vDelta.lengthXYSquared();
|
2023-10-17 23:38:33 +02:00
|
|
|
fDist = sqrt(fDistSquared);
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
vDelta = vTo - vFrom;
|
2023-10-17 20:38:58 +02:00
|
|
|
fRangeSquared = vDelta.x * vDelta.x + vDelta.y * vDelta.y;
|
2023-10-17 23:38:33 +02:00
|
|
|
fRange = sqrt(fRangeSquared);
|
|
|
|
fHeight = vDelta.z * fRange - vDelta.z * fDist;
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (!fHeight) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
fHeight = 1.f / fHeight;
|
2023-10-17 20:38:58 +02:00
|
|
|
fVelHorz = (fRange - fDist) * fHeight;
|
|
|
|
if (fVelHorz <= 0) {
|
|
|
|
return false;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
fTemp = sqrt(fGravity * 0.5f * fDist * fRange * fVelHorz);
|
2023-10-17 20:38:58 +02:00
|
|
|
fVelVert = (fRangeSquared * vDelta.z - fDistSquared * vDelta.z) * fGravity * 0.5f / fTemp * fHeight;
|
|
|
|
fVelHorz = fTemp / fDist;
|
|
|
|
|
|
|
|
pvVel->x = (pHint->origin.x - vFrom.x) * fVelHorz;
|
|
|
|
pvVel->y = (pHint->origin.y - vFrom.y) * fVelHorz;
|
|
|
|
pvVel->z = fVelVert;
|
|
|
|
|
|
|
|
*peMode = AI_GREN_TOSS_HINT;
|
|
|
|
|
|
|
|
bSuccess = ValidGrenadePath(vFrom, pHint->origin, *pvVel);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
return bSuccess;
|
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::GrenadeThrowPoint
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns real grenade throw point.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
Vector Actor::GrenadeThrowPoint(const Vector& vFrom, const Vector& vDelta, const_str csAnim)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
vec2_t axis;
|
|
|
|
|
|
|
|
VectorCopy2D(vDelta, axis);
|
|
|
|
VectorNormalize2D(axis);
|
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
switch (csAnim) {
|
|
|
|
case STRING_ANIM_GRENADEKICK_SCR:
|
|
|
|
return Vector(vFrom.x, vFrom.y, vFrom.z + 8);
|
|
|
|
case STRING_ANIM_GRENADETHROW_SCR:
|
|
|
|
case STRING_ANIM_GRENADETOSS_SCR:
|
2023-10-17 23:38:33 +02:00
|
|
|
return Vector(
|
|
|
|
axis[0] * -34.0 + vFrom.x - axis[1] * -8.0, axis[1] * -34.0 + vFrom.y + axis[0] * -8.0, vFrom.z + 52
|
2023-10-17 20:38:58 +02:00
|
|
|
);
|
|
|
|
case STRING_ANIM_GRENADERETURN_SCR:
|
2023-10-17 23:38:33 +02:00
|
|
|
return Vector(
|
|
|
|
axis[0] * 25.0 + vFrom.x - axis[1] * -2.0, axis[1] * 25.0 + vFrom.y + axis[0] * -2.0, vFrom.z + 89
|
2023-10-17 20:38:58 +02:00
|
|
|
);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return vFrom + Vector(0, 0, 80);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::CalcKickVelocity
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Calculates required grenade kick velocity.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
Vector Actor::CalcKickVelocity(Vector& vDelta, float fDist) const
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
float fScale = sqrt(sv_gravity->value * 0.8f * 0.5f / (fDist * 0.57735032 - vDelta.z));
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
return Vector(vDelta.x * fScale, vDelta.y * fScale, fDist * 0.57735032 * fScale);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::CanKickGrenade
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if actor can kick grenade from vFrom to vTo.
|
|
|
|
Or false if it's not possible.
|
|
|
|
pvVel is changed.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::CanKickGrenade(Vector& vFrom, Vector& vTo, Vector& vFace, Vector *pvVel)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
Vector vDelta, vStart, vEnd;
|
2023-10-17 23:38:33 +02:00
|
|
|
float fDist, fScale;
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
if (sv_gravity->value <= 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
vStart = GrenadeThrowPoint(vFrom, vFace, STRING_ANIM_GRENADEKICK_SCR);
|
|
|
|
vDelta = vTo - vStart;
|
2023-10-17 20:38:58 +02:00
|
|
|
if (vDelta.z >= 0) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DotProduct(vDelta, vFace) < 0) {
|
|
|
|
return false;
|
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
fDist = VectorLength2D(vDelta);
|
|
|
|
if (fDist < 256 || fDist >= (255401.28f / sv_gravity->value * 0.8f + 192.f)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (fDist < 512) {
|
2023-10-17 20:38:58 +02:00
|
|
|
fScale = 192.0f / fDist + 0.25f;
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-17 20:38:58 +02:00
|
|
|
fScale = 1.0f - 192.0f / fDist;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
vDelta.x *= fScale;
|
|
|
|
vDelta.y *= fScale;
|
2023-10-11 22:49:06 +02:00
|
|
|
vEnd = vStart + vDelta;
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
*pvVel = CalcKickVelocity(vDelta, fDist);
|
2018-09-05 16:55:10 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (*pvVel == vec_zero || !ValidGrenadePath(vStart, vEnd, *pvVel)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
return true;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
2019-08-13 03:12:07 +02:00
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::GrenadeWillHurtTeamAt
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if grenade will hurt team at vTo.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::GrenadeWillHurtTeamAt(const Vector& vTo)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
Sentient *pSquadMate;
|
2023-10-17 20:38:58 +02:00
|
|
|
for (pSquadMate = m_pNextSquadMate; pSquadMate != this; pSquadMate = pSquadMate->m_pNextSquadMate) {
|
|
|
|
if ((pSquadMate->origin - vTo).length() < 65536) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::CanGetGrenadeFromAToB
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if actor can get a grenade from vFrom to vTo.
|
|
|
|
pvVel is the kick/roll/throw velocity.
|
|
|
|
peMode is the possible toss mode.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::CanGetGrenadeFromAToB(
|
|
|
|
const Vector& vFrom, const Vector& vTo, bool bDesperate, Vector *pvVel, eGrenadeTossMode *peMode
|
|
|
|
)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
static constexpr unsigned int MAX_GRENADE_HINTS = 4;
|
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
float fRangeSquared;
|
|
|
|
GrenadeHint *apHint[MAX_GRENADE_HINTS];
|
|
|
|
int nHints;
|
|
|
|
int i;
|
|
|
|
Vector vDelta;
|
|
|
|
Vector vAxisX, vAxisY;
|
|
|
|
Vector vStart;
|
|
|
|
Vector vHint;
|
|
|
|
float fDot;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (sv_gravity->value <= 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
vDelta = vTo - vFrom;
|
2023-10-11 22:49:06 +02:00
|
|
|
fRangeSquared = vDelta.lengthSquared();
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (fRangeSquared < Square(256)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (bDesperate) {
|
2023-10-11 22:49:06 +02:00
|
|
|
vStart = GrenadeThrowPoint(vFrom, vDelta, STRING_ANIM_GRENADERETURN_SCR);
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (fRangeSquared < Square(1024)) {
|
|
|
|
if (!bDesperate) {
|
2023-10-11 22:49:06 +02:00
|
|
|
vStart = GrenadeThrowPoint(vFrom, vDelta, STRING_ANIM_GRENADETOSS_SCR);
|
|
|
|
}
|
|
|
|
|
|
|
|
*pvVel = CanRollGrenade(vStart, vTo);
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (*pvVel != vec_zero) {
|
2023-10-11 22:49:06 +02:00
|
|
|
*peMode = AI_GREN_TOSS_ROLL;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!bDesperate) {
|
2023-10-11 22:49:06 +02:00
|
|
|
vStart = GrenadeThrowPoint(vFrom, vDelta, STRING_ANIM_GRENADETHROW_SCR);
|
|
|
|
}
|
|
|
|
|
|
|
|
*pvVel = CanThrowGrenade(vStart, vTo);
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (*pvVel != vec_zero) {
|
2023-10-11 22:49:06 +02:00
|
|
|
*peMode = AI_GREN_TOSS_THROW;
|
|
|
|
return true;
|
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
} else if (!bDesperate) {
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
nHints = GrenadeHint::GetClosestSet(apHint, MAX_GRENADE_HINTS, vStart, Square(1024));
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
for (i = 0; i < nHints; i++) {
|
|
|
|
if (!bDesperate) {
|
|
|
|
fDot = DotProduct2D(vHint, vDelta);
|
|
|
|
if (fDot < 0) {
|
|
|
|
continue;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if ((vHint.lengthXYSquared() * 0.9f * vDelta.lengthXYSquared()) >= (fDot * fDot)) {
|
|
|
|
continue;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
vStart =
|
|
|
|
GrenadeThrowPoint(vFrom, vHint, bDesperate ? STRING_ANIM_GRENADERETURN_SCR : STRING_ANIM_GRENADETOSS_SCR);
|
2023-10-17 20:38:58 +02:00
|
|
|
if (CanTossGrenadeThroughHint(apHint[i], vStart, vTo, bDesperate, pvVel, peMode)) {
|
|
|
|
return true;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
*peMode = AI_GREN_TOSS_NONE;
|
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::DecideToThrowGrenade
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Returns true if actor will throw grenade to vTo.
|
|
|
|
pvVel is the kick/roll/throw velocity.
|
|
|
|
peMode is the toss mode.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-17 20:38:58 +02:00
|
|
|
bool Actor::DecideToThrowGrenade(const Vector& vTo, Vector *pvVel, eGrenadeTossMode *peMode, bool bDesperate)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
if (!AmmoCount("grenade")) {
|
|
|
|
return false;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
if (GrenadeWillHurtTeamAt(vTo)) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return CanGetGrenadeFromAToB(origin, vTo, bDesperate, pvVel, peMode);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::GenericGrenadeTossThink
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Called when actor in grenade state.
|
|
|
|
i.e. actor noticed a grenade and must think fast.
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::GenericGrenadeTossThink(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
Vector vGrenadeVel = vec_zero;
|
2023-10-11 22:49:06 +02:00
|
|
|
eGrenadeTossMode eGrenadeMode;
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_Enemy && level.inttime >= m_iStateTime + 200) {
|
2024-02-13 16:22:56 +01:00
|
|
|
if (CanGetGrenadeFromAToB(origin, m_Enemy->origin + m_Enemy->velocity, false, &vGrenadeVel, &eGrenadeMode)) {
|
2023-10-12 18:19:22 +02:00
|
|
|
m_vGrenadeVel = vGrenadeVel;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_eGrenadeMode = eGrenadeMode;
|
|
|
|
}
|
|
|
|
m_iStateTime = level.inttime;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetDesiredYawDir(m_vGrenadeVel);
|
|
|
|
ContinueAnimation();
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2018-09-17 23:50:38 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-11 22:49:06 +02:00
|
|
|
Actor::Grenade_EventFire
|
2018-09-17 23:50:38 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Throw grenade animation
|
2018-09-17 23:50:38 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::Grenade_EventFire(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
Vector dir;
|
|
|
|
Vector pos;
|
|
|
|
float speed;
|
|
|
|
str strGrenade;
|
2023-10-11 22:49:06 +02:00
|
|
|
const_str csAnim;
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
gi.Tag_NumForName(edict->tiki, "tag_weapon_right");
|
2023-10-12 18:19:22 +02:00
|
|
|
|
|
|
|
if (m_eGrenadeMode == AI_GREN_TOSS_ROLL) {
|
2023-10-11 22:49:06 +02:00
|
|
|
csAnim = STRING_ANIM_GRENADETOSS_SCR;
|
2023-10-17 20:38:58 +02:00
|
|
|
} else {
|
|
|
|
csAnim = STRING_ANIM_GRENADETHROW_SCR;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
pos = GrenadeThrowPoint(origin, orientation[0], csAnim);
|
|
|
|
dir = m_vGrenadeVel;
|
2023-10-17 20:38:58 +02:00
|
|
|
speed = dir.normalize();
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (g_protocol >= PROTOCOL_MOHTA_MIN) {
|
2023-10-23 11:59:06 +02:00
|
|
|
// Added in 2.30
|
2023-10-17 20:38:58 +02:00
|
|
|
switch (m_iNationality) {
|
|
|
|
case ACTOR_NATIONALITY_ITALIAN:
|
|
|
|
strGrenade = "models/projectiles/Bomba_ai.tik";
|
|
|
|
break;
|
|
|
|
case ACTOR_NATIONALITY_RUSSIAN:
|
|
|
|
strGrenade = "models/projectiles/Russian_F1_grenade_ai.tik";
|
|
|
|
break;
|
|
|
|
case ACTOR_NATIONALITY_BRITISH:
|
|
|
|
strGrenade = "models/projectiles/Mills_grenade_ai.tik";
|
|
|
|
break;
|
|
|
|
case ACTOR_NATIONALITY_AMERICAN:
|
|
|
|
strGrenade = "models/projectiles/M2FGrenade_ai.tik";
|
|
|
|
break;
|
|
|
|
case ACTOR_NATIONALITY_GERMAN:
|
|
|
|
strGrenade = "models/projectiles/steilhandgranate_ai.tik";
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
// fallback to team
|
|
|
|
if (m_Team != TEAM_GERMAN) {
|
|
|
|
strGrenade = "models/projectiles/M2FGrenade_ai.tik";
|
2023-10-17 23:38:33 +02:00
|
|
|
} else {
|
2023-10-17 20:38:58 +02:00
|
|
|
strGrenade = "models/projectiles/steilhandgranate_ai.tik";
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-17 20:38:58 +02:00
|
|
|
if (m_Team != TEAM_GERMAN) {
|
|
|
|
strGrenade = "models/projectiles/M2FGrenade.tik";
|
|
|
|
} else {
|
|
|
|
strGrenade = "models/projectiles/steilhandgranate.tik";
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
ProjectileAttack(pos, dir, this, strGrenade, 0, speed);
|
2023-10-11 22:49:06 +02:00
|
|
|
UseAmmo("grenade", 1);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetTurret
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetTurret(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
Listener *l = ev->GetListener(1);
|
2023-10-17 20:38:58 +02:00
|
|
|
if (l && l->isSubclassOf(TurretGun)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_pTurret = (TurretGun *)l;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetTurret
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetTurret(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddListener(m_pTurret);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetAmmoGrenade
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetAmmoGrenade(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddInteger(AmmoCount("grenade"));
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetAmmoGrenade
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetAmmoGrenade(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
GiveAmmo("grenade", ev->GetInteger(1));
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventEnableEnemy
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventEnableEnemy(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bDesiredEnableEnemy = ev->GetBoolean(1);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventEnablePain
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventEnablePain(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bEnablePain = ev->GetBoolean(1);
|
2023-10-17 20:38:58 +02:00
|
|
|
if (!m_bEnablePain) {
|
|
|
|
SetThinkState(THINKSTATE_VOID, THINKLEVEL_PAIN);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventActivate
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventActivate(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bPatrolWaitTrigger = false;
|
|
|
|
Unregister(STRING_TRIGGER);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventInterruptPoint
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventInterruptPoint(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
GlobalFuncs_t *interrupt = &GlobalFuncs[m_Think[m_ThinkLevel]];
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (interrupt->PostShoot) {
|
|
|
|
(this->*interrupt->PostShoot)();
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetVisibilityThreshold
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventGetVisibilityThreshold(Event *ev)
|
|
|
|
{
|
|
|
|
ev->AddFloat(m_fVisibilityThreshold);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetVisibilityThreshold
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventSetVisibilityThreshold(Event *ev)
|
|
|
|
{
|
|
|
|
float threshold;
|
|
|
|
|
|
|
|
threshold = ev->GetFloat(1);
|
|
|
|
|
|
|
|
if (threshold < 0 || threshold > 1) {
|
|
|
|
ScriptError("DefaultNonVisLevel must be in range 0-1");
|
|
|
|
}
|
|
|
|
|
|
|
|
m_bHasVisibilityThreshold = true;
|
|
|
|
m_fVisibilityThreshold = threshold;
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetDefaultVisibilityThreshold
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventSetDefaultVisibilityThreshold(Event *ev)
|
|
|
|
{
|
|
|
|
float threshold;
|
|
|
|
|
|
|
|
threshold = ev->GetFloat(1);
|
|
|
|
|
|
|
|
if (threshold < 0 || threshold > 1) {
|
|
|
|
ScriptError("DefaultNonVisLevel must be in range 0-1");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!m_bHasVisibilityThreshold) {
|
|
|
|
m_fVisibilityThreshold = threshold;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetSuppressChance
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventGetSuppressChance(Event *ev)
|
|
|
|
{
|
|
|
|
ev->AddInteger(m_iSuppressChance);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetSuppressChance
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventSetSuppressChance(Event *ev)
|
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
m_iSuppressChance = ev->GetInteger(1);
|
|
|
|
if (m_iSuppressChance != ev->GetFloat(1)) {
|
|
|
|
Com_Printf(
|
|
|
|
"WARNING: suppresschance should be an integer in the range 0 - 100, was set to %g for entnum %i (%s)\n",
|
|
|
|
(double)ev->GetFloat(1),
|
|
|
|
entnum,
|
|
|
|
TargetName().c_str()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_iSuppressChance > 100) {
|
|
|
|
Com_Printf(
|
|
|
|
"WARNING: suppresschance should be in the range 0 - 100, was set to %i for entnum %i (%s)\n",
|
|
|
|
m_iSuppressChance,
|
|
|
|
entnum,
|
|
|
|
TargetName().c_str()
|
|
|
|
);
|
|
|
|
|
|
|
|
if (m_iSuppressChance >= 0) {
|
|
|
|
m_iSuppressChance = 100;
|
|
|
|
} else {
|
|
|
|
m_iSuppressChance = 0;
|
|
|
|
}
|
|
|
|
}
|
2023-10-12 19:21:41 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventAnimScript
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void Actor::EventAnimScript(Event *ev)
|
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
m_csAnimScript = ev->GetConstString(1);
|
2023-10-23 15:55:58 +02:00
|
|
|
m_bAnimScriptSet = true;
|
2023-10-14 14:10:16 +02:00
|
|
|
m_AnimMode = ANIM_MODE_NORMAL;
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThinkIdle(THINK_ANIM);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventAnimScript_Scripted
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventAnimScript_Scripted(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
m_csAnimScript = ev->GetConstString(1);
|
2023-10-12 23:17:09 +02:00
|
|
|
m_bAnimScriptSet = true;
|
2023-10-14 14:10:16 +02:00
|
|
|
m_AnimMode = ANIM_MODE_SCRIPTED;
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThinkIdle(THINK_ANIM);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventAnimScript_Noclip
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventAnimScript_Noclip(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 14:10:16 +02:00
|
|
|
m_csAnimScript = ev->GetConstString(1);
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bAnimScriptSet = true;
|
2023-10-14 14:10:16 +02:00
|
|
|
m_AnimMode = ANIM_MODE_NOCLIP;
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
SetThinkIdle(THINK_ANIM);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventAnimScript_Attached
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventAnimScript_Attached(Event *ev)
|
|
|
|
{
|
2023-10-14 14:10:16 +02:00
|
|
|
m_csAnimScript = ev->GetConstString(1);
|
2023-10-12 23:17:09 +02:00
|
|
|
m_bAnimScriptSet = true;
|
2023-10-14 14:10:16 +02:00
|
|
|
m_AnimMode = ANIM_MODE_ATTACHED;
|
2023-10-12 23:17:09 +02:00
|
|
|
|
|
|
|
SetThinkIdle(THINK_ANIM);
|
2023-10-12 19:21:41 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventReload_mg42
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventReload_mg42(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
if (m_State != ACTOR_STATE_MACHINE_GUNNER_RELOADING) {
|
|
|
|
if (m_State == ACTOR_STATE_MACHINE_GUNNER_READY) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bAnimScriptSet = true;
|
2023-10-17 20:38:58 +02:00
|
|
|
TransitionState(ACTOR_STATE_MACHINE_GUNNER_RELOADING, 0);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
Unregister(STRING_ANIMDONE);
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::CanMovePathWithLeash
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::CanMovePathWithLeash(void) const
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
vec2_t delta;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (!PathExists()) {
|
|
|
|
return false;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
VectorSub2D(origin, m_vHome, delta);
|
2024-02-14 20:06:35 +01:00
|
|
|
if (VectorLength2DSquared(delta) >= m_fLeashSquared
|
|
|
|
&& DotProduct2D(m_Path.CurrentDelta(), delta) >= 0) {
|
2023-10-17 20:38:58 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::MovePathWithLeash
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::MovePathWithLeash(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
if (!CanMovePathWithLeash()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Anim_Aim();
|
|
|
|
return false;
|
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
Anim_RunToInOpen(ANIM_MODE_PATH);
|
|
|
|
FaceMotion();
|
|
|
|
|
|
|
|
return true;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::GunTarget
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-17 20:38:58 +02:00
|
|
|
Vector Actor::GunTarget(bool bNoCollision, const vec3_t position, const vec3_t forward)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
static cvar_t *aifSupressScatter = gi.Cvar_Get("g_aiSupressScatter", "2.0", 0);
|
|
|
|
static cvar_t *aifCoverFactor = gi.Cvar_Get("g_aimcoverfactor", "0.80", 0);
|
|
|
|
static cvar_t *aiMaxDeviation = gi.Cvar_Get("g_aimaxdeviation", "0.965", 0);
|
|
|
|
static cvar_t *aiMinAccuracy = gi.Cvar_Get("g_aiminaccuracy", "0.33", 0);
|
|
|
|
static cvar_t *aiScatterWide = gi.Cvar_Get("g_aiScatterWide", "16.0", 0);
|
|
|
|
static cvar_t *aiScatterHeight = gi.Cvar_Get("g_aiScatterHeight", "45.0", 0);
|
|
|
|
static cvar_t *aiRanges[4];
|
2023-10-17 20:38:58 +02:00
|
|
|
static qboolean doInit = qtrue;
|
2023-10-17 23:38:33 +02:00
|
|
|
float fAccuracy, fCoverFactor;
|
|
|
|
Vector aimDir;
|
2023-10-17 20:38:58 +02:00
|
|
|
|
2024-08-05 18:43:56 +02:00
|
|
|
fCoverFactor = mAccuracy * ((1.0 - m_fVisibilityAlpha) * aiMinAccuracy->value + m_fVisibilityAlpha);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (doInit) {
|
2023-10-11 22:49:06 +02:00
|
|
|
aiRanges[0] = gi.Cvar_Get("g_aishortrange", "500", 0);
|
|
|
|
aiRanges[1] = gi.Cvar_Get("g_aimediumrange", "700", 0);
|
|
|
|
aiRanges[2] = gi.Cvar_Get("g_ailongrange", "1000", 0);
|
|
|
|
aiRanges[3] = gi.Cvar_Get("g_aisniperrange", "2200", 0);
|
2023-10-12 18:19:22 +02:00
|
|
|
doInit = false;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (m_aimNode) {
|
|
|
|
Vector centroid = m_aimNode->centroid;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (m_aimNode->IsSubclassOfActor()) {
|
2023-10-17 23:38:33 +02:00
|
|
|
Actor *pActor = static_cast<Actor *>(m_aimNode.Pointer());
|
2023-10-17 20:38:58 +02:00
|
|
|
if (pActor->IsOnFloor()) {
|
|
|
|
centroid = m_aimNode->origin + Vector(0, 0, 12);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
aimDir = centroid - Vector(position);
|
|
|
|
aimDir.normalize();
|
|
|
|
|
|
|
|
if (DotProduct(forward, aimDir) < 0.866f) {
|
|
|
|
return centroid;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
Vector dir = mTargetPos - EyePosition();
|
|
|
|
dir.normalize();
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2024-02-15 00:21:01 +01:00
|
|
|
if (g_target_game > target_game_e::TG_MOH) {
|
|
|
|
if (DotProduct2D(forward, dir) < aiMaxDeviation->value) {
|
|
|
|
Vector vOut;
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2024-02-15 00:21:01 +01:00
|
|
|
VectorMA(position, 2048, forward, vOut);
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2024-02-15 00:21:01 +01:00
|
|
|
return vOut;
|
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (mTargetPos == vec_zero) {
|
|
|
|
Vector vOut;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
AnglesToAxis(angles, orientation);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
vOut = Vector(orientation[0]) * 2048;
|
|
|
|
vOut += EyePosition();
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
return vOut;
|
|
|
|
}
|
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
Player *player = NULL;
|
|
|
|
Weapon *weapon;
|
|
|
|
float scatterMult = 1.f;
|
|
|
|
Vector vPos;
|
|
|
|
Vector vDelta;
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
if (m_Enemy) {
|
|
|
|
if (!m_Enemy->IsSubclassOfPlayer() && fabs(m_Enemy->origin.z - origin.z) >= 128) {
|
|
|
|
// half towards for the player
|
|
|
|
scatterMult = 0.5f;
|
|
|
|
}
|
|
|
|
|
|
|
|
vDelta = m_Enemy->centroid - centroid;
|
|
|
|
weapon = GetActiveWeapon(WEAPON_MAIN);
|
|
|
|
if (weapon) {
|
|
|
|
fAccuracy = vDelta.length() / aiRanges[weapon->mAIRange]->value;
|
|
|
|
if (fAccuracy < 1) {
|
|
|
|
fAccuracy = 1;
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
scatterMult = fAccuracy * 0.75f;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (m_Enemy->IsSubclassOfPlayer()) {
|
2023-10-17 23:38:33 +02:00
|
|
|
player = static_cast<Player *>(m_Enemy.Pointer());
|
|
|
|
vPos = player->centroid;
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
if (!G_SightTrace(
|
2023-10-17 23:38:33 +02:00
|
|
|
GunPosition(), vec_zero, vec_zero, vPos, m_Enemy, this, MASK_CANSEE, qfalse, "Actor::GunTarget 1"
|
|
|
|
)) {
|
2023-10-17 20:38:58 +02:00
|
|
|
fCoverFactor *= aifCoverFactor->value;
|
|
|
|
vPos = m_Enemy->EyePosition();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (m_State == ACTOR_STATE_TURRET_RETARGET_SNIPER_NODE) {
|
|
|
|
scatterMult = aifSupressScatter->value;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector error(0, 0, 0);
|
|
|
|
|
|
|
|
fAccuracy = (1.0 - fCoverFactor) * 2 * scatterMult;
|
|
|
|
if (fAccuracy < 0) {
|
|
|
|
fAccuracy = 0;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (player) {
|
2023-10-17 20:38:58 +02:00
|
|
|
error[0] = fAccuracy * aiScatterWide->value * crandom();
|
|
|
|
error[1] = fAccuracy * aiScatterWide->value * crandom();
|
|
|
|
error[2] = fAccuracy * aiScatterHeight->value * crandom();
|
2023-10-17 23:38:33 +02:00
|
|
|
vPos = player->centroid;
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-17 20:38:58 +02:00
|
|
|
error[0] = fAccuracy * 32.0 * crandom();
|
|
|
|
error[1] = fAccuracy * 32.0 * crandom();
|
|
|
|
error[2] = fAccuracy * 48.0 * crandom();
|
2023-10-17 23:38:33 +02:00
|
|
|
vPos = mTargetPos;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (m_Enemy && m_Enemy->GetVehicleTank()) {
|
|
|
|
vPos.z -= 128;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
return vPos + error;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::setModel
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
qboolean Actor::setModel(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
str name;
|
2023-10-17 20:38:58 +02:00
|
|
|
qboolean success;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (model != "") {
|
|
|
|
if (m_csLoadOut != STRING_EMPTY) {
|
2023-10-11 22:49:06 +02:00
|
|
|
name = "weapon|" + Director.GetString(m_csLoadOut) + "|";
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_csHeadModel == STRING_EMPTY) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_csHeadModel = Director.AddString(level.GetRandomHeadModel(model));
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_csHeadModel != STRING_EMPTY) {
|
2023-10-11 22:49:06 +02:00
|
|
|
name += "headmodel|" + Director.GetString(m_csHeadModel) + "|";
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_csHeadSkin == STRING_EMPTY) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_csHeadSkin = Director.AddString(level.GetRandomHeadSkin(model));
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_csHeadSkin != STRING_EMPTY) {
|
2023-10-17 20:38:58 +02:00
|
|
|
name += "headskin|" + Director.GetString(m_csHeadSkin) + "|";
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
name += model;
|
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
level.skel_index[edict->s.number] = -1;
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
success = gi.setmodel(edict, name);
|
|
|
|
return success;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetHeadModel
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetHeadModel(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_csHeadModel = ev->GetConstString(1);
|
|
|
|
setModel();
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetHeadModel
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetHeadModel(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddConstString(m_csHeadModel);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetHeadSkin
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetHeadSkin(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_csHeadSkin = ev->GetConstString(1);
|
|
|
|
setModel();
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetHeadSkin
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetHeadSkin(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddConstString(m_csHeadSkin);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::SetPathWithLeash
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetPathWithLeash(Vector vDestPos, const char *description, int iMaxDirtyTime)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
vec2_t vDelta;
|
|
|
|
|
|
|
|
VectorSub2D(vDestPos, m_vHome, vDelta);
|
|
|
|
|
|
|
|
if (VectorLength2DSquared(vDelta) > m_fLeashSquared) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearPath();
|
2023-10-17 20:38:58 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorSub2D(origin, m_vHome, vDelta);
|
|
|
|
|
|
|
|
if (VectorLength2DSquared(vDelta) > m_fLeashSquared) {
|
|
|
|
ClearPath();
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
SetPath(vDestPos, description, iMaxDirtyTime, m_vHome, m_fLeashSquared);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::SetPathWithLeash
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetPathWithLeash(SimpleEntity *pDestNode, const char *description, int iMaxDirtyTime)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
if (!pDestNode) {
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_bPathErrorTime + 5000 < level.inttime) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bPathErrorTime = level.inttime;
|
|
|
|
Com_Printf(
|
|
|
|
"^~^~^ No destination node specified for '%s' at (%f %f %f)\n",
|
2023-10-17 20:38:58 +02:00
|
|
|
TargetName().c_str(),
|
2023-10-11 22:49:06 +02:00
|
|
|
origin[0],
|
|
|
|
origin[1],
|
2023-10-12 18:19:22 +02:00
|
|
|
origin[2]
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearPath();
|
2023-10-17 20:38:58 +02:00
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
SetPathWithLeash(pDestNode->origin, description, iMaxDirtyTime);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-29 14:41:48 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::FindPathAwayWithLeash
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::FindPathAwayWithLeash(vec3_t vAwayFrom, vec3_t vDirPreferred, float fMinSafeDist)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
m_Path.FindPathAway(origin, vAwayFrom, vDirPreferred, this, fMinSafeDist, m_vHome, m_fLeashSquared);
|
2023-10-11 22:49:06 +02:00
|
|
|
ShortenPathToAvoidSquadMates();
|
|
|
|
}
|
2018-08-29 14:41:48 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::FindPathNearWithLeash
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::FindPathNearWithLeash(vec3_t vNearbyTo, float fCloseDistSquared)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
vec2_t vDelta;
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
VectorSub2D(vNearbyTo, m_vHome, vDelta);
|
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
if ((sqrt(m_fLeashSquared * fCloseDistSquared) * 2 + m_fLeashSquared + fCloseDistSquared)
|
|
|
|
< VectorLength2DSquared(vDelta)) {
|
2023-10-17 20:38:58 +02:00
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
VectorSub2D(origin, m_vHome, vDelta);
|
|
|
|
|
|
|
|
if (VectorLength2DSquared(vDelta) > m_fLeashSquared) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_Path.FindPathNear(origin, vNearbyTo, this, 0, fCloseDistSquared, m_vHome, m_fLeashSquared);
|
|
|
|
ShortenPathToAvoidSquadMates();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-29 14:41:48 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::GetAntiBunchPoint
|
2018-08-29 14:41:48 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
Vector Actor::GetAntiBunchPoint(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
float fMinDistSquared;
|
|
|
|
Vector vDelta;
|
|
|
|
Sentient *pSquadMate;
|
|
|
|
Vector vFinalPos;
|
|
|
|
int nAvoid;
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
fMinDistSquared = m_fInterval * m_fInterval;
|
2023-10-17 23:38:33 +02:00
|
|
|
nAvoid = 0;
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
for (pSquadMate = m_pNextSquadMate; pSquadMate != this; pSquadMate = pSquadMate->m_pNextSquadMate) {
|
|
|
|
float fLengthSquared, fLength;
|
2023-10-17 23:38:33 +02:00
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
fLengthSquared = vDelta.lengthSquared();
|
|
|
|
if (!fLengthSquared) {
|
|
|
|
continue;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
if (fLengthSquared >= fMinDistSquared) {
|
|
|
|
continue;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-17 20:38:58 +02:00
|
|
|
|
|
|
|
fLength = sqrt(fLengthSquared);
|
|
|
|
vDelta *= 1.0f / fLength;
|
|
|
|
vFinalPos += origin + vDelta * (m_fInterval - fLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!nAvoid) {
|
|
|
|
return origin;
|
|
|
|
} else if (nAvoid == 1) {
|
|
|
|
return vFinalPos;
|
|
|
|
} else {
|
|
|
|
vFinalPos *= 1.f / nAvoid;
|
|
|
|
return vFinalPos;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::AutoArchiveModel
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::AutoArchiveModel(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
return false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::AddToBodyQue
|
|
|
|
|
|
|
|
Add this to body queue.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::AddToBodyQue(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 20:38:58 +02:00
|
|
|
if (mBodyQueue[mCurBody]) {
|
|
|
|
mBodyQueue[mCurBody]->PostEvent(EV_Remove, 0);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
mBodyQueue[mCurBody] = this;
|
|
|
|
|
|
|
|
//update current body index
|
2023-10-17 20:38:58 +02:00
|
|
|
mCurBody = (mCurBody + 1) % MAX_BODYQUEUE;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::ResetBodyQueue
|
|
|
|
|
|
|
|
Clear body queue.
|
|
|
|
Called upon Level::Cleanup()
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::ResetBodyQueue(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
//weird useless loop ?
|
|
|
|
|
2023-10-17 20:38:58 +02:00
|
|
|
for (int i = 0; i < MAX_BODYQUEUE; i++) {
|
2023-10-11 22:49:06 +02:00
|
|
|
//do nothing.
|
|
|
|
}
|
|
|
|
//mBodyQueue
|
|
|
|
//this resets curBody, but all the magic happens in AddToBodyQue
|
|
|
|
mCurBody = 0;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetNoIdle
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetNoIdle(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bNoIdleAfterAnim = ev->GetInteger(1);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetNoIdle
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetNoIdle(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddInteger(m_bNoIdleAfterAnim);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetEnemy
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetEnemy(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddListener(m_Enemy);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetMaxNoticeTimeScale
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetMaxNoticeTimeScale(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
float fScale;
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
fScale = ev->GetFloat(1);
|
|
|
|
if (fScale <= 0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Com_Printf("^~^~^ ERROR: noticescale: value must be greater than 0\n");
|
2023-10-17 23:38:33 +02:00
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-17 23:38:33 +02:00
|
|
|
|
|
|
|
m_fMaxNoticeTimeScale = fScale * 0.01f;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetMaxNoticeTimeScale
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetMaxNoticeTimeScale(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddFloat(m_fMaxNoticeTimeScale * 100);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetFixedLeash
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetFixedLeash(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bFixedLeash = ev->GetBoolean(1);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetFixedLeash
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetFixedLeash(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddInteger(m_bFixedLeash);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::Holster
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::Holster(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
if (activeWeaponList[WEAPON_MAIN]) {
|
2023-10-11 22:49:06 +02:00
|
|
|
DeactivateWeapon(WEAPON_MAIN);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::HolsterOffHand
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::HolsterOffHand(void)
|
|
|
|
{
|
|
|
|
if (activeWeaponList[WEAPON_OFFHAND]) {
|
|
|
|
DeactivateWeapon(WEAPON_OFFHAND);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::Unholster
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::Unholster(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
Weapon *weap;
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-12 19:21:41 +02:00
|
|
|
if (!activeWeaponList[WEAPON_MAIN]) {
|
2023-10-17 23:38:33 +02:00
|
|
|
weap = GetWeapon(0);
|
2023-10-12 18:19:22 +02:00
|
|
|
if (weap) {
|
2023-10-11 22:49:06 +02:00
|
|
|
useWeapon(weap, WEAPON_MAIN);
|
|
|
|
ActivateNewWeapon();
|
|
|
|
}
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::UnholsterOffHand
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::UnholsterOffHand(void)
|
|
|
|
{
|
|
|
|
Weapon *weap;
|
|
|
|
|
|
|
|
if (!activeWeaponList[WEAPON_OFFHAND]) {
|
2023-10-17 23:38:33 +02:00
|
|
|
weap = GetWeapon(0);
|
2023-10-12 19:21:41 +02:00
|
|
|
if (weap) {
|
|
|
|
useWeapon(weap, WEAPON_OFFHAND);
|
|
|
|
ActivateNewWeapon();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventHolster
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventHolster(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
if (ev->NumArgs() > 0 && ev->GetInteger(1) > 0) {
|
|
|
|
HolsterOffHand();
|
|
|
|
} else {
|
|
|
|
Holster();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventUnholster
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventUnholster(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
if (ev->NumArgs() > 0 && ev->GetInteger(1) > 0) {
|
|
|
|
UnholsterOffHand();
|
|
|
|
} else {
|
|
|
|
Unholster();
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventIsEnemyVisible
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventIsEnemyVisible(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddInteger(m_bEnemyVisible);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetEnemyVisibleChangeTime
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetEnemyVisibleChangeTime(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
ev->AddFloat(m_iEnemyVisibleChangeTime / 100.f);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetLastEnemyVisibleTime
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetLastEnemyVisibleTime(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
ev->AddFloat(m_iLastEnemyVisibleTime / 100.f);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSoundDone
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSoundDone(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
int channelNum;
|
|
|
|
str sfxName;
|
|
|
|
|
|
|
|
channelNum = ev->GetInteger(1);
|
2024-08-26 01:05:58 +02:00
|
|
|
sfxName = ev->GetString(2);
|
2023-10-17 23:38:33 +02:00
|
|
|
|
|
|
|
if (gi.S_IsSoundPlaying(channelNum, sfxName)) {
|
|
|
|
Event event(EV_SoundDone);
|
|
|
|
event.AddInteger(channelNum);
|
|
|
|
event.AddString(sfxName);
|
|
|
|
PostEvent(event, level.frametime);
|
|
|
|
} else if (m_bSayAnimSet && m_iSaySlot == -2) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ChangeSayAnim();
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_csSayAnim == STRING_EMPTY) {
|
2023-10-11 22:49:06 +02:00
|
|
|
Unregister(STRING_SAYDONE);
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
Unregister(STRING_SOUNDDONE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSound
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSound(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
if (g_gametype->integer == GT_SINGLE_PLAYER || m_Team == TEAM_AMERICAN) {
|
|
|
|
ProcessSoundEvent(ev, qtrue);
|
|
|
|
} else {
|
|
|
|
ProcessSoundEvent(ev, qfalse);
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetFallHeight
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetFallHeight(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
float fHeight = ev->GetFloat(1);
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (fHeight < MIN_FALLHEIGHT) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("value less than %d not allowed", MIN_FALLHEIGHT);
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
if (fHeight > MAX_FALLHEIGHT) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("value greater than %d not allowed", MAX_FALLHEIGHT);
|
|
|
|
}
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
m_Path.SetFallHeight(fHeight);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetFallHeight
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetFallHeight(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddFloat(m_Path.GetFallHeight());
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventCanMoveTo
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventCanMoveTo(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
Vector vDest;
|
|
|
|
vec2_t vDelta;
|
|
|
|
float fDistSquared;
|
|
|
|
float fIntervalSquared;
|
|
|
|
Sentient *pSquadMate;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
vDest = ev->GetVector(1);
|
2023-10-17 23:38:33 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
VectorSub2D(vDest, m_vHome, vDelta);
|
|
|
|
fDistSquared = VectorLength2DSquared(vDelta);
|
2023-10-17 23:38:33 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (fDistSquared >= m_fLeashSquared) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddInteger(0);
|
|
|
|
return;
|
2023-10-17 23:38:33 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (m_Enemy) {
|
2023-10-11 22:49:06 +02:00
|
|
|
VectorSub2D(vDest, m_Enemy->origin, vDelta);
|
|
|
|
fDistSquared = VectorLength2DSquared(vDelta);
|
2023-10-17 23:38:33 +02:00
|
|
|
|
|
|
|
if (fDistSquared <= m_fMinDistanceSquared || fDistSquared >= m_fMaxDistanceSquared) {
|
|
|
|
ev->AddInteger(false);
|
2023-10-11 22:49:06 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2023-10-17 23:38:33 +02:00
|
|
|
|
|
|
|
if (m_fInterval) {
|
|
|
|
fIntervalSquared = Square(m_fInterval);
|
|
|
|
|
|
|
|
for (pSquadMate = m_pNextSquadMate; pSquadMate != this; pSquadMate = pSquadMate->m_pNextSquadMate) {
|
|
|
|
fDistSquared = (vDest - pSquadMate->origin).lengthSquared();
|
|
|
|
|
|
|
|
if (fDistSquared >= fIntervalSquared) {
|
|
|
|
continue;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-17 23:38:33 +02:00
|
|
|
|
|
|
|
if ((origin - pSquadMate->origin).lengthSquared() > fDistSquared) {
|
|
|
|
ev->AddInteger(false);
|
2023-10-11 22:49:06 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
for (pSquadMate = m_pNextSquadMate; pSquadMate != this; pSquadMate = pSquadMate->m_pNextSquadMate) {
|
|
|
|
Actor *pActor;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
if (pSquadMate->IsSubclassOfActor()) {
|
|
|
|
pActor = static_cast<Actor *>(pSquadMate);
|
|
|
|
if (!pActor->m_Enemy) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
VectorSub2D(pActor->m_Enemy->origin, pSquadMate->origin, vDelta);
|
|
|
|
} else {
|
|
|
|
VectorCopy2D(pSquadMate->orientation[0], vDelta);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
float fIntercept = CrossProduct2D(vDelta, pSquadMate->origin);
|
|
|
|
float a1 = CrossProduct2D(vDelta, origin) - fIntercept;
|
|
|
|
float a2 = CrossProduct2D(vDelta, vDest) - fIntercept;
|
|
|
|
|
|
|
|
if (signbit(a1) != signbit(a2)) {
|
|
|
|
ev->AddInteger(false);
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
2023-10-17 23:38:33 +02:00
|
|
|
|
|
|
|
ev->AddInteger(true);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventMoveDir
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventMoveDir(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
vec3_t vDir;
|
|
|
|
|
|
|
|
VectorClear(vDir);
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (!PathGoalSlowdownStarted()) {
|
2023-10-17 23:38:33 +02:00
|
|
|
VectorCopy2D(velocity, vDir);
|
|
|
|
|
|
|
|
if (velocity.x || velocity.y) {
|
|
|
|
VectorCopy2D(velocity, vDir);
|
|
|
|
VectorNormalize2D(vDir);
|
|
|
|
vDir[2] = 0;
|
|
|
|
} else if (PathExists() && !PathComplete()) {
|
|
|
|
VectorCopy2D(PathDelta(), vDir);
|
|
|
|
VectorNormalize2D(vDir);
|
|
|
|
vDir[2] = 0;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
ev->AddVector(vDir);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventIntervalDir
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventIntervalDir(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
if (level.inttime >= m_iIntervalDirTime + 250) {
|
|
|
|
m_vIntervalDir = vec_zero;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_iIntervalDirTime = level.inttime;
|
2023-10-17 23:38:33 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_Enemy) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_vIntervalDir = GetAntiBunchPoint() - origin;
|
2023-10-17 23:38:33 +02:00
|
|
|
if (m_vIntervalDir.x || m_vIntervalDir.y) {
|
|
|
|
m_vIntervalDir.normalizefast();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddVector(m_vIntervalDir);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventResetLeash
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventResetLeash(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
m_vHome = origin;
|
2023-10-11 22:49:06 +02:00
|
|
|
m_pTetherEnt = NULL;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventTether
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventTether(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_pTetherEnt = ev->GetSimpleEntity(1);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::ShortenPathToAttack
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::ShortenPathToAttack(float fMinDist)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
float fMinDistSquared;
|
|
|
|
PathInfo *pathnode;
|
|
|
|
Vector vEyePos;
|
|
|
|
|
|
|
|
if (!PathExists() || PathComplete()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!PathAvoidsSquadMates()) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
fMinDistSquared = Square(fMinDist);
|
|
|
|
for (pathnode = CurrentPathNode(); pathnode > LastPathNode(); pathnode--) {
|
|
|
|
if ((pathnode->point - origin).lengthSquared() < fMinDistSquared) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CanSeeFrom(pathnode->point - eyeposition, m_Enemy)) {
|
|
|
|
m_Path.TrimPathFromEnd(pathnode - LastPathNode());
|
|
|
|
return true;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::StrafeToAttack
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::StrafeToAttack(float fDist, vec3_t vDir)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
static const vec3_t mins = {-16, -16, 16};
|
|
|
|
static const vec3_t maxs = {16, 16, 128};
|
|
|
|
Vector vSpot;
|
|
|
|
Vector vDelta;
|
|
|
|
Vector vEnemyCentroid;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
VectorScale(vDir, fDist, vDelta);
|
|
|
|
VectorAdd(origin, vDelta, vSpot);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
float fDistSquared = (vSpot - m_vLastEnemyPos).lengthSquared();
|
|
|
|
if (fDistSquared >= m_fMaxDistanceSquared || fDistSquared <= m_fMinDistanceSquared) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearPath();
|
|
|
|
return;
|
|
|
|
}
|
2023-10-17 23:38:33 +02:00
|
|
|
|
|
|
|
if (!G_SightTrace(origin, mins, maxs, vSpot, this, NULL, MASK_TARGETPATH, qtrue, "Actor::StrafeToAttack 1")) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearPath();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
vEnemyCentroid = m_vLastEnemyPos;
|
|
|
|
vEnemyCentroid.z += m_Enemy->centroid.z - m_Enemy->origin.z;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
|
|
|
if (!G_SightTrace(
|
2023-10-17 23:38:33 +02:00
|
|
|
vDelta + EyePosition(),
|
|
|
|
vec3_origin,
|
|
|
|
vec3_origin,
|
|
|
|
vEnemyCentroid,
|
2023-10-12 18:19:22 +02:00
|
|
|
this,
|
|
|
|
m_Enemy,
|
2023-10-17 23:38:33 +02:00
|
|
|
MASK_CANSEE,
|
2023-10-12 18:19:22 +02:00
|
|
|
qfalse,
|
|
|
|
"Actor::StrafeToAttack 1"
|
|
|
|
)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ClearPath();
|
2023-10-17 23:38:33 +02:00
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-17 23:38:33 +02:00
|
|
|
|
|
|
|
SetPathWithLeash(vSpot, NULL, 0);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetThinkState
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetThinkState(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddConstString(m_csThinkStateNames[m_ThinkState]);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetEnemyShareRange
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetEnemyShareRange(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
ev->AddFloat(sqrt(m_fMaxShareDistSquared));
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetEnemyShareRange
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetEnemyShareRange(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
float fLength = ev->GetFloat(1);
|
|
|
|
m_fMaxShareDistSquared = Square(fLength);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::GetVoiceType
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::GetVoiceType(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
//voice type in actor is a char.
|
2023-10-17 23:38:33 +02:00
|
|
|
ev->AddString(va("%c", mVoiceType));
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::SetVoiceType
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetVoiceType(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
//voice type in actor is a char.
|
2023-10-17 23:38:33 +02:00
|
|
|
const str vType = ev->GetString(1);
|
|
|
|
|
|
|
|
if (vType.length() && vType[0]) {
|
2023-10-11 22:49:06 +02:00
|
|
|
mVoiceType = vType[0];
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
mVoiceType = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::FindSniperNodeAndSetPath
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
PathNode *Actor::FindSniperNodeAndSetPath(bool *pbTryAgain)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
PathNode *pSniperNode;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
pSniperNode = PathManager.FindNearestSniperNode(this, origin, m_Enemy);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
if (!pSniperNode) {
|
|
|
|
*pbTryAgain = false;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetPathWithLeash(pSniperNode, NULL, 0);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
if (!PathExists()) {
|
2023-10-11 22:49:06 +02:00
|
|
|
pSniperNode->MarkTemporarilyBad();
|
|
|
|
*pbTryAgain = true;
|
2023-10-17 23:38:33 +02:00
|
|
|
return NULL;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2023-10-17 23:38:33 +02:00
|
|
|
if (!PathComplete() && !PathAvoidsSquadMates()) {
|
|
|
|
pSniperNode->MarkTemporarilyBad();
|
|
|
|
*pbTryAgain = true;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
*pbTryAgain = true;
|
|
|
|
return pSniperNode;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::Remove
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::Remove(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
EndStates();
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (deadflag != DEAD_DEAD) {
|
2023-10-11 22:49:06 +02:00
|
|
|
deadflag = DEAD_DEAD;
|
2023-10-17 23:38:33 +02:00
|
|
|
health = 0;
|
|
|
|
Unregister(STRING_DEATH);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
Delete();
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetKickDir
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetKickDir(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddVector(m_vKickDir);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetNoLongPain
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetNoLongPain(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-17 23:38:33 +02:00
|
|
|
ev->AddInteger(m_bNoLongPain || m_Team == TEAM_AMERICAN);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetNoLongPain
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetNoLongPain(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bNoLongPain = ev->GetBoolean(1);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::DontFaceWall
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::DontFaceWall(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
trace_t trace;
|
|
|
|
Vector start, end;
|
|
|
|
float fAngle, fSinAngle, fCosAngle;
|
|
|
|
float fEyeRadius;
|
|
|
|
float fErrorLerp;
|
|
|
|
vec2_t vDelta;
|
|
|
|
PathNode *pNode;
|
2023-10-12 18:19:22 +02:00
|
|
|
|
|
|
|
if (m_pCoverNode && m_pCoverNode->nodeflags & (AI_CORNER_LEFT | AI_CORNER_RIGHT | AI_SNIPER | AI_CRATE)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_eDontFaceWallMode = 1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (velocity.lengthXYSquared() > Square(8)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_eDontFaceWallMode = 2;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
fAngle = AngleNormalize360(m_YawAchieved ? angles.y : m_DesiredYaw);
|
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
fErrorLerp = (level.time - m_fDfwTime) * 0.5;
|
|
|
|
if (fErrorLerp > 1) {
|
|
|
|
fErrorLerp = 1;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
VectorSub2D(m_vDfwPos, origin, vDelta);
|
|
|
|
|
2024-02-13 16:22:56 +01:00
|
|
|
if (Square(fErrorLerp * -14.0 + 16.0) > VectorLength2DSquared(vDelta) &&
|
|
|
|
(fabs(AngleNormalize180(m_fDfwRequestedYaw - m_DesiredYaw)) <= fErrorLerp * -29.0 + 30.0
|
|
|
|
|| fabs(AngleNormalize180(m_fDfwDerivedYaw - m_DesiredYaw)) <= fErrorLerp * -29.0 + 30.0)) {
|
2023-10-18 19:21:06 +02:00
|
|
|
if (AvoidingFacingWall()) {
|
|
|
|
SetDesiredYaw(m_fDfwDerivedYaw);
|
|
|
|
}
|
|
|
|
return;
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
m_vDfwPos = origin;
|
|
|
|
m_fDfwRequestedYaw = fAngle;
|
|
|
|
m_fDfwTime = level.time;
|
|
|
|
|
|
|
|
fSinAngle = sin(DEG2RAD(fAngle));
|
|
|
|
fCosAngle = cos(DEG2RAD(fAngle));
|
|
|
|
|
|
|
|
VectorSub2D(EyePosition(), origin, vDelta);
|
|
|
|
start = EyePosition();
|
|
|
|
start.x -= origin.x;
|
|
|
|
start.y -= origin.y;
|
|
|
|
fEyeRadius = VectorLength2D(start);
|
|
|
|
start.x = origin.x + fEyeRadius * fCosAngle;
|
|
|
|
start.y = origin.x + fEyeRadius * fSinAngle;
|
|
|
|
end.x = start.x + fCosAngle * 64;
|
|
|
|
end.y = start.y + fSinAngle * 64;
|
|
|
|
end.z = start.z;
|
|
|
|
|
|
|
|
trace = G_Trace(start, vec_zero, vec_zero, end, this, MASK_CANSEE, qfalse, "Actor::DontFaceWall");
|
|
|
|
|
|
|
|
if (trace.entityNum == ENTITYNUM_NONE || trace.fraction > 0.999f || trace.startsolid) {
|
|
|
|
m_eDontFaceWallMode = 3;
|
|
|
|
m_fDfwDerivedYaw = m_fDfwRequestedYaw;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (trace.entityNum != ENTITYNUM_WORLD && trace.ent->entity->AIDontFace()) {
|
|
|
|
m_eDontFaceWallMode = 4;
|
|
|
|
m_fDfwDerivedYaw = m_fDfwRequestedYaw;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (trace.plane.normal[2] < -0.7f || trace.plane.normal[2] > 0.7f) {
|
|
|
|
m_eDontFaceWallMode = 5;
|
|
|
|
m_fDfwDerivedYaw = m_fDfwRequestedYaw;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m_Enemy && (m_Enemy->origin * trace.plane.normal - trace.plane.dist) < 0) {
|
|
|
|
end = m_Enemy->origin;
|
|
|
|
} else {
|
|
|
|
end = start + 128 * (end - start);
|
|
|
|
}
|
|
|
|
|
|
|
|
pNode = PathManager.FindCornerNodeForWall(origin, end, this, 0.0f, trace.plane.normal);
|
|
|
|
if (pNode) {
|
|
|
|
SetDesiredYawDest(pNode->m_PathPos);
|
|
|
|
} else if (trace.fraction > 0.46875f) {
|
|
|
|
if (m_DesiredYaw < 90.0) {
|
|
|
|
SetDesiredYaw(m_DesiredYaw + 270);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-18 19:21:06 +02:00
|
|
|
SetDesiredYaw(m_DesiredYaw - 90);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-18 19:21:06 +02:00
|
|
|
m_eDontFaceWallMode = 8;
|
|
|
|
} else {
|
|
|
|
SetDesiredYawDir(trace.plane.normal);
|
|
|
|
m_eDontFaceWallMode = 7;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-18 19:21:06 +02:00
|
|
|
|
|
|
|
m_fDfwDerivedYaw = m_DesiredYaw;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::IsVoidState
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::IsVoidState(int state)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
return true;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::IsIdleState
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::IsIdleState(int state)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
return state == THINKSTATE_IDLE;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::IsCuriousState
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::IsCuriousState(int state)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
return state == THINKSTATE_CURIOUS;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::IsDisguiseState
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::IsDisguiseState(int state)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
return state == THINKSTATE_DISGUISE;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::IsAttackState
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::IsAttackState(int state)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
return state == THINKSTATE_ATTACK;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::IsGrenadeState
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::IsGrenadeState(int state)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
return state == THINKSTATE_GRENADE;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::IsBadPlaceState
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
bool Actor::IsBadPlaceState(int state)
|
|
|
|
{
|
|
|
|
return state == THINKSTATE_BADPLACE;
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::IsPainState
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::IsPainState(int state)
|
2018-08-19 08:26:59 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
return state == THINKSTATE_PAIN;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::IsKilledState
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
bool Actor::IsKilledState(int state)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
return state == THINKSTATE_KILLED;
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::IsNoClipState
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 20:17:09 +02:00
|
|
|
bool Actor::IsNoClipState(int state)
|
|
|
|
{
|
|
|
|
return state == THINKSTATE_NOCLIP;
|
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::InitVoid
|
|
|
|
|
|
|
|
Init void global func
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::InitVoid(GlobalFuncs_t *func)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
func->IsState = &Actor::IsVoidState;
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::BecomeCorpse
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::BecomeCorpse(void)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
AddToBodyQue();
|
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
setContents(CONTENTS_TRIGGER);
|
2023-10-11 22:49:06 +02:00
|
|
|
edict->r.svFlags &= ~SVF_MONSTER;
|
|
|
|
setSolidType(SOLID_NOT);
|
2023-10-18 19:21:06 +02:00
|
|
|
|
|
|
|
CheckGround();
|
|
|
|
if (groundentity) {
|
|
|
|
setMoveType(MOVETYPE_NONE);
|
|
|
|
} else {
|
|
|
|
// enable physics if on air
|
|
|
|
setMoveType(MOVETYPE_TOSS);
|
|
|
|
}
|
|
|
|
|
|
|
|
// don't cast shadow
|
2023-10-11 22:49:06 +02:00
|
|
|
edict->s.renderfx &= ~RF_SHADOW;
|
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
PostEvent(EV_DeathSinkStart, 10);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetFavoriteEnemy
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetFavoriteEnemy(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddEntity(m_FavoriteEnemy);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetFavoriteEnemy
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetFavoriteEnemy(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
m_FavoriteEnemy = static_cast<Sentient *>(ev->GetEntity(1));
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventFindEnemy
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventFindEnemy(Event *ev)
|
|
|
|
{
|
|
|
|
if (level.inttime > m_iEnemyCheckTime + 200) {
|
|
|
|
UpdateEnemyInternal();
|
|
|
|
}
|
|
|
|
|
|
|
|
ev->AddEntity(m_Enemy);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetMumble
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetMumble(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
|
|
|
ev->AddInteger(m_bMumble);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetMumble
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetMumble(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
m_bMumble = ev->GetInteger(1) != false;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetBreathSteam
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-18 19:21:06 +02:00
|
|
|
void Actor::EventGetBreathSteam(Event *ev)
|
2023-10-12 19:21:41 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
ev->AddInteger(m_bBreathSteam);
|
2023-10-12 19:21:41 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetBreathSteam
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-18 19:21:06 +02:00
|
|
|
void Actor::EventSetBreathSteam(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
m_bBreathSteam = ev->GetInteger(1) != false;
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetNextBreathTime
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-18 19:21:06 +02:00
|
|
|
void Actor::EventSetNextBreathTime(Event *ev)
|
|
|
|
{
|
|
|
|
ScriptVariable var;
|
|
|
|
ScriptThread *thread;
|
|
|
|
|
|
|
|
thread = Director.CreateThread("global/breathe.scr", "nextbreathtime");
|
|
|
|
|
|
|
|
// pass the breath time as the first argument
|
|
|
|
var.setFloatValue(ev->GetFloat(1));
|
|
|
|
thread->Execute(&var, 1);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventCalcGrenadeToss2
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-18 19:21:06 +02:00
|
|
|
void Actor::EventCalcGrenadeToss2(Event *ev)
|
|
|
|
{
|
|
|
|
Vector vTargetPos;
|
|
|
|
Vector vFrom;
|
|
|
|
Vector vPoint;
|
|
|
|
Vector vDelta;
|
|
|
|
Vector vVel;
|
|
|
|
Vector vPointTarget(0, 0, 0);
|
|
|
|
float speed;
|
|
|
|
float fDistSquared;
|
|
|
|
|
|
|
|
vFrom = origin;
|
|
|
|
speed = 0;
|
|
|
|
vTargetPos = ev->GetVector(1);
|
|
|
|
vDelta = vTargetPos - vFrom;
|
|
|
|
fDistSquared = vDelta.lengthSquared();
|
|
|
|
|
|
|
|
if (ev->NumArgs() > 1) {
|
|
|
|
speed = ev->GetFloat(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fDistSquared < Square(1024)) {
|
|
|
|
vPoint = GrenadeThrowPoint(vFrom, vDelta, STRING_ANIM_GRENADETOSS_SCR);
|
|
|
|
vVel = CanRollGrenade(vPoint, vTargetPos);
|
|
|
|
if (vVel != vPointTarget) {
|
|
|
|
m_vGrenadeVel = vVel;
|
|
|
|
m_eGrenadeMode = AI_GREN_TOSS_ROLL;
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddConstString(STRING_ANIM_GRENADETOSS_SCR);
|
2023-10-18 19:21:06 +02:00
|
|
|
SetDesiredYawDir(m_vGrenadeVel);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!speed) {
|
|
|
|
vPoint = GrenadeThrowPoint(vFrom, vDelta, STRING_ANIM_GRENADETHROW_SCR);
|
|
|
|
vVel = CanThrowGrenade(vPoint, vTargetPos);
|
|
|
|
if (vVel != vec_zero) {
|
|
|
|
m_vGrenadeVel = vVel;
|
|
|
|
m_eGrenadeMode = AI_GREN_TOSS_THROW;
|
|
|
|
ev->AddConstString(STRING_ANIM_GRENADETHROW_SCR);
|
|
|
|
SetDesiredYawDir(m_vGrenadeVel);
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-18 19:21:06 +02:00
|
|
|
ev->AddConstString(STRING_ANIM_GRENADETOSS_SCR);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-18 19:21:06 +02:00
|
|
|
return;
|
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
vPoint = GrenadeThrowPoint(vFrom, vDelta, STRING_ANIM_GRENADETHROW_SCR);
|
|
|
|
|
|
|
|
vVel = vTargetPos - vPoint;
|
|
|
|
vVel.normalize();
|
|
|
|
vVel *= speed;
|
|
|
|
m_vGrenadeVel = vVel;
|
|
|
|
|
|
|
|
ev->AddConstString(STRING_ANIM_GRENADETOSS_SCR);
|
|
|
|
SetDesiredYawDir(m_vGrenadeVel);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventCalcGrenadeToss
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-18 19:21:06 +02:00
|
|
|
void Actor::EventCalcGrenadeToss(Event *ev)
|
|
|
|
{
|
|
|
|
bool bSuccess;
|
|
|
|
|
|
|
|
if (ev->NumArgs() > 1) {
|
|
|
|
bSuccess = ev->GetBoolean(2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!DecideToThrowGrenade(ev->GetVector(1), &m_vGrenadeVel, &m_eGrenadeMode, bSuccess)) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddConstString(STRING_EMPTY);
|
2023-10-18 19:21:06 +02:00
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-18 19:21:06 +02:00
|
|
|
|
|
|
|
switch (m_eGrenadeMode) {
|
|
|
|
case AI_GREN_TOSS_ROLL:
|
|
|
|
ev->AddConstString(STRING_ANIM_GRENADETOSS_SCR);
|
|
|
|
break;
|
|
|
|
case AI_GREN_TOSS_HINT:
|
|
|
|
case AI_GREN_TOSS_THROW:
|
|
|
|
ev->AddConstString(STRING_ANIM_GRENADETHROW_SCR);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
{
|
|
|
|
char assertStr[16384] = {0};
|
|
|
|
strcpy(assertStr, "\"invalid return condition for Actor::EventCalcGrenadeToss\"\n\tMessage: ");
|
|
|
|
Q_strcat(assertStr, sizeof(assertStr), DumpCallTrace(""));
|
|
|
|
assert(false && assertStr);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
SetDesiredYawDir(m_vGrenadeVel);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetNoSurprise
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetNoSurprise(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddInteger(m_bNoSurprise);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetNoSurprise
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetNoSurprise(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bNoSurprise = ev->GetBoolean(1);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetSilent
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetSilent(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddInteger(m_bSilent);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetSilent
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetSilent(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bSilent = ev->GetBoolean(1);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetAvoidPlayer
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetAvoidPlayer(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddInteger(m_bAutoAvoidPlayer);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetAvoidPlayer
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetAvoidPlayer(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bAutoAvoidPlayer = ev->GetBoolean(1);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::PathnodeClaimRevoked
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::PathnodeClaimRevoked(PathNode *node)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
int iThinkLevel;
|
|
|
|
|
|
|
|
for (iThinkLevel = m_ThinkLevel; iThinkLevel >= 0; --iThinkLevel) {
|
|
|
|
GlobalFuncs_t *func = &GlobalFuncs[m_Think[iThinkLevel]];
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (func->PathnodeClaimRevoked) {
|
2023-10-11 22:49:06 +02:00
|
|
|
(this->*func->PathnodeClaimRevoked)();
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-18 19:21:06 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
node->Relinquish();
|
|
|
|
m_pCoverNode = NULL;
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::SetPathToNotBlockSentient
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::SetPathToNotBlockSentient(Sentient *pOther)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
Vector vAway;
|
|
|
|
Vector vPerp;
|
|
|
|
Vector vDest;
|
|
|
|
|
|
|
|
if (!pOther) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pOther->IsDead()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IsTeamMate(pOther)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pOther->velocity.lengthSquared() <= 1) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vAway = origin - pOther->origin;
|
|
|
|
|
|
|
|
if (vAway.lengthSquared() >= Square(48)) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (DotProduct2D(pOther->velocity, vAway) <= 0) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (CrossProduct2D(pOther->velocity, vAway) >= 0) {
|
|
|
|
vPerp[0] = -pOther->velocity[1];
|
|
|
|
vPerp[1] = pOther->velocity[0];
|
|
|
|
} else {
|
|
|
|
vPerp[0] = pOther->velocity[1];
|
|
|
|
vPerp[1] = -pOther->velocity[0];
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-18 19:21:06 +02:00
|
|
|
vPerp[2] = 0;
|
|
|
|
vPerp.normalizefast();
|
|
|
|
|
|
|
|
vDest = origin + vPerp * 48;
|
|
|
|
|
|
|
|
if (G_SightTrace(
|
|
|
|
vDest, mins, maxs, vDest, this, pOther, MASK_SOLID, qfalse, "Actor::SetPathToNotBlockSentient 1"
|
|
|
|
)) {
|
|
|
|
SetPathWithinDistance(vDest, NULL, 96, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PathExists()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
vDest = origin - vPerp * 48;
|
|
|
|
|
|
|
|
if (G_SightTrace(
|
|
|
|
vDest, mins, maxs, vDest, this, pOther, MASK_SOLID, qfalse, "Actor::SetPathToNotBlockSentient 2"
|
|
|
|
)) {
|
|
|
|
SetPathWithinDistance(vDest, NULL, 96, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (PathExists()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
FindPathAway(pOther->origin, vAway * 100, 96);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::LookAround
|
|
|
|
|
|
|
|
Look around behaviour.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::LookAround(float fFovAdd)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
float fModTime;
|
|
|
|
vec3_t vAngle;
|
|
|
|
vec3_t vDest;
|
|
|
|
trace_t trace;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (level.inttime >= m_iNextLookTime) {
|
2023-10-18 19:21:06 +02:00
|
|
|
VectorCopy(angles, vAngle);
|
|
|
|
fModTime = level.time / 8 - floor(level.time / 8);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
vAngle[1] = fFovAdd * (fModTime * 2 - 1) + vAngle[1];
|
|
|
|
vAngle[0] += (noise1(entnum + level.time * 1.005309626678312f) + 1) * 15;
|
2023-10-11 22:49:06 +02:00
|
|
|
AngleVectors(vAngle, vDest, NULL, NULL);
|
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
Vector vEyePos = EyePosition();
|
|
|
|
|
|
|
|
VectorMA(vEyePos, 1024, vDest, vDest);
|
|
|
|
|
|
|
|
trace = G_Trace(EyePosition(), vec_zero, vec_zero, vDest, this, MASK_LOOK, qfalse, "Actor::LookAround");
|
2023-10-12 18:19:22 +02:00
|
|
|
if (trace.fraction > 0.125) {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bHasDesiredLookDest = true;
|
|
|
|
VectorCopy(trace.endpos, m_vDesiredLookDest);
|
2023-10-18 19:21:06 +02:00
|
|
|
m_iNextLookTime = level.inttime + (rand() % 500) + 750;
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bHasDesiredLookDest = false;
|
2023-10-12 18:19:22 +02:00
|
|
|
m_iNextLookTime = level.inttime + 187;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (m_bHasDesiredLookDest) {
|
2023-10-11 22:49:06 +02:00
|
|
|
SetDesiredLookDir(m_vDesiredLookDest - EyePosition());
|
2023-10-12 18:19:22 +02:00
|
|
|
} else {
|
2023-10-18 19:21:06 +02:00
|
|
|
ForwardLook();
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetLookAroundAngle
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetLookAroundAngle(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
// Fixed in OPM
|
|
|
|
// Seems like a mistake in 2.40 and below, it should return a float instead
|
2023-10-11 22:49:06 +02:00
|
|
|
//ev->GetFloat(m_fLookAroundFov);
|
2023-10-18 19:21:06 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddFloat(m_fLookAroundFov);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetLookAroundAngle
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetLookAroundAngle(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
float fLookAroundFov;
|
|
|
|
|
|
|
|
fLookAroundFov = ev->GetFloat(1);
|
|
|
|
if (fLookAroundFov < 0.0 || fLookAroundFov > 60.0) {
|
2023-10-11 22:49:06 +02:00
|
|
|
ScriptError("lookaroundangle must be >= 0 and <= 60");
|
|
|
|
}
|
2023-10-18 19:21:06 +02:00
|
|
|
|
|
|
|
m_fLookAroundFov = fLookAroundFov;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::DumpAnimInfo
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::DumpAnimInfo(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
vec3_t LocalLookAngles;
|
|
|
|
Vector actualHeadAngle, actualTorsoAngle;
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Animate::DumpAnimInfo();
|
2023-10-18 19:21:06 +02:00
|
|
|
|
|
|
|
if (m_bHasDesiredLookAngles) {
|
|
|
|
VectorCopy(m_DesiredLookAngles, LocalLookAngles);
|
|
|
|
} else {
|
|
|
|
VectorClear(LocalLookAngles);
|
|
|
|
}
|
|
|
|
|
|
|
|
actualHeadAngle = GetControllerAngles(HEAD_TAG);
|
|
|
|
actualTorsoAngle = GetControllerAngles(TORSO_TAG);
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
MPrintf(
|
|
|
|
"Desired look yaw: %.1f, pitch: %.1f. Head yaw: %.1f, pitch %.1f. Torso yaw: %.1f, pitch: %.1f\n",
|
2023-10-18 19:21:06 +02:00
|
|
|
LocalLookAngles[1],
|
|
|
|
LocalLookAngles[0],
|
|
|
|
actualHeadAngle[1],
|
|
|
|
actualHeadAngle[0],
|
|
|
|
actualTorsoAngle[1],
|
|
|
|
actualTorsoAngle[0]
|
2023-10-12 18:19:22 +02:00
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::DumpCallTrace
|
|
|
|
|
|
|
|
Dump useful debug info.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
const char *Actor::DumpCallTrace(const char *pszFmt, ...) const
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
char szTemp[65536];
|
|
|
|
int i;
|
|
|
|
int i1, i2;
|
|
|
|
char szFile[MAX_QPATH];
|
|
|
|
Vector vPlayer;
|
2023-10-12 18:19:22 +02:00
|
|
|
time_t t;
|
2023-10-18 19:21:06 +02:00
|
|
|
tm *ptm;
|
|
|
|
cvar_t *sv_mapname;
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
va_list args;
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
va_start(args, pszFmt);
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
sv_mapname = gi.Cvar_Get("mapname", "unknown", 0);
|
|
|
|
|
|
|
|
Player *p = (Player *)G_GetEntity(0);
|
2023-10-12 18:19:22 +02:00
|
|
|
if (p) {
|
2023-10-11 22:49:06 +02:00
|
|
|
vPlayer = p->origin;
|
|
|
|
}
|
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
i1 = sprintf(
|
2023-10-11 22:49:06 +02:00
|
|
|
szTemp,
|
|
|
|
"map = %s\n"
|
|
|
|
"time = %i (%i:%02i)\n"
|
|
|
|
"entnum = %i, targetname = '%s'\n"
|
|
|
|
"origin = (%g %g %g)\n"
|
|
|
|
"think = %s, thinkstate = %s\n"
|
|
|
|
"type_idle = %s\n"
|
|
|
|
"type_attack = %s\n"
|
|
|
|
"m_State = %i, m_pszDebugState = %s\n"
|
|
|
|
"player is at (%g %g %g)\n"
|
|
|
|
"--------------------------------------\n",
|
|
|
|
sv_mapname->string,
|
|
|
|
level.inttime,
|
|
|
|
level.inttime / 60000,
|
|
|
|
level.inttime / 1000 - 60 * (level.inttime / 60000),
|
|
|
|
entnum,
|
|
|
|
targetname.c_str(),
|
|
|
|
origin[0],
|
|
|
|
origin[1],
|
|
|
|
origin[2],
|
|
|
|
ThinkName().c_str(),
|
|
|
|
ThinkStateName().c_str(),
|
|
|
|
Director.GetString(m_csThinkNames[m_ThinkMap[THINKSTATE_IDLE]]).c_str(),
|
|
|
|
Director.GetString(m_csThinkNames[m_ThinkMap[THINKSTATE_ATTACK]]).c_str(),
|
|
|
|
m_State,
|
|
|
|
m_pszDebugState,
|
|
|
|
vPlayer[0],
|
|
|
|
vPlayer[1],
|
2023-10-12 18:19:22 +02:00
|
|
|
vPlayer[2]
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
i2 = i1;
|
2023-10-12 18:19:22 +02:00
|
|
|
if (pszFmt) {
|
2023-10-18 19:21:06 +02:00
|
|
|
va_list args2;
|
|
|
|
va_copy(args2, args);
|
|
|
|
i2 = i1 + vsprintf(&szTemp[i1], pszFmt, args);
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-18 19:21:06 +02:00
|
|
|
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
if (i1 != i2) {
|
2023-10-11 22:49:06 +02:00
|
|
|
strcpy(&szTemp[i2], "\n--------------------------------------\n");
|
|
|
|
}
|
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
t = time(0);
|
2023-10-11 22:49:06 +02:00
|
|
|
ptm = localtime(&t);
|
|
|
|
sprintf(
|
|
|
|
szFile,
|
|
|
|
"main\\ai_trace_%s_%i_%i_%02i%02i.log",
|
|
|
|
sv_mapname->string,
|
|
|
|
ptm->tm_mon + 1,
|
|
|
|
ptm->tm_mday,
|
|
|
|
ptm->tm_hour,
|
2023-10-12 18:19:22 +02:00
|
|
|
ptm->tm_min
|
|
|
|
);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
for (i = 5; szFile[i]; i++) {
|
2023-10-12 18:19:22 +02:00
|
|
|
if (szFile[i] == '\\' || szFile[i] == '/') {
|
2023-10-11 22:49:06 +02:00
|
|
|
szFile[i] = '_';
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-12 18:19:22 +02:00
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
fprintf(stderr, "IMPORTANT: Include '%s' in your bug report!\n", szFile);
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
return va(
|
2023-10-11 22:49:06 +02:00
|
|
|
"\n"
|
|
|
|
"\t-------------------------- IMPORTANT REMINDER --------------------------\n"
|
|
|
|
"\n"
|
|
|
|
"\tinclude '%s' in your bug report! \n"
|
|
|
|
"\n"
|
|
|
|
"\t----------------------- END IMPORTANT REMINDER -----------------------\n"
|
|
|
|
"\n"
|
|
|
|
"%s",
|
|
|
|
szFile,
|
2023-10-18 19:21:06 +02:00
|
|
|
&szTemp[i1]
|
2023-10-12 18:19:22 +02:00
|
|
|
);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetMoveDoneRadius
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetMoveDoneRadius(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
float radius = ev->GetFloat(1);
|
|
|
|
m_fMoveDoneRadiusSquared = Square(radius);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetMoveDoneRadius
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventGetMoveDoneRadius(Event *ev)
|
|
|
|
{
|
|
|
|
ev->AddFloat(sqrtf(m_fMoveDoneRadiusSquared));
|
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::StoppedWaitFor
|
|
|
|
|
|
|
|
Called when stopped wait for an actor.
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::StoppedWaitFor(const_str name, bool bDeleting)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
g_iInThinks++;
|
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
GlobalFuncs_t *func = &GlobalFuncs[CurrentThink()];
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
if (func->FinishedAnimation) {
|
2023-10-11 22:49:06 +02:00
|
|
|
(this->*func->FinishedAnimation)();
|
|
|
|
}
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
g_iInThinks--;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventHasCompleteLookahead
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventHasCompleteLookahead(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
ev->AddInteger(PathExists() && PathHasCompleteLookahead());
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventPathDist
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventPathDist(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
if (!PathExists() || PathComplete()) {
|
|
|
|
ev->AddFloat(0);
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-18 19:21:06 +02:00
|
|
|
|
|
|
|
ev->AddFloat(PathDist());
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventCanShootEnemyFrom
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventCanShootEnemyFrom(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
if (!m_Enemy) {
|
|
|
|
ev->AddInteger(false);
|
|
|
|
return;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2023-10-18 19:21:06 +02:00
|
|
|
|
|
|
|
ev->AddInteger(CanSeeFrom(ev->GetVector(1), m_Enemy));
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetInReload
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetInReload(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bInReload = ev->GetBoolean(1);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetInReload
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetInReload(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddInteger(m_bInReload);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetReloadCover
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetReloadCover(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_bNeedReload = ev->GetBoolean(1);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventBreakSpecial
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventBreakSpecial(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
mbBreakSpecialAttack = true;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventCanShoot
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventCanShoot(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
Entity *ent;
|
|
|
|
|
|
|
|
ent = ev->GetEntity(1);
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
if (!ent) {
|
|
|
|
ScriptError("canshoot applied to NULL listener");
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
ev->AddInteger(CanShoot(ent));
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetBalconyHeight
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventSetBalconyHeight(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
m_fBalconyHeight = ev->GetFloat(1);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetIgnoreBadPlace
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventSetIgnoreBadPlace(Event *ev)
|
|
|
|
{
|
2023-10-18 19:21:06 +02:00
|
|
|
if (m_bIgnoreBadPlace == ev->GetBoolean(1)) {
|
|
|
|
return;
|
|
|
|
}
|
2023-10-12 19:21:41 +02:00
|
|
|
|
2023-10-18 19:21:06 +02:00
|
|
|
m_bIgnoreBadPlace = ev->GetBoolean(1);
|
|
|
|
|
|
|
|
if (level.m_badPlaces.NumObjects() && m_bIgnoreBadPlace) {
|
|
|
|
UpdateBadPlaces();
|
2023-10-12 19:21:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetIgnoreBadPlace
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventGetIgnoreBadPlace(Event *ev)
|
|
|
|
{
|
|
|
|
ev->AddInteger(m_bIgnoreBadPlace);
|
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventGetBalconyHeight
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::EventGetBalconyHeight(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
ev->AddFloat(m_fBalconyHeight);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::BecomeTurretGuy
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::BecomeTurretGuy(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 18:19:22 +02:00
|
|
|
SetThinkIdle(THINK_IDLE);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-12 18:19:22 +02:00
|
|
|
SetThink(THINKSTATE_ATTACK, THINK_TURRET);
|
|
|
|
SetThink(THINKSTATE_DISGUISE, THINK_DISGUISE_SALUTE);
|
|
|
|
SetThink(THINKSTATE_GRENADE, THINK_GRENADE);
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-29 20:20:56 +01:00
|
|
|
if (CurrentThink() == THINK_TURRET && Turret_DecideToSelectState()) {
|
2023-10-18 19:21:06 +02:00
|
|
|
TransitionState(ACTOR_STATE_TURRET_COMBAT, 0);
|
2023-10-12 18:19:22 +02:00
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::AimAtEnemyBehavior
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
Aiming at enemy behaviour.
|
|
|
|
Usally called after SetEnemyPos()
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 18:19:22 +02:00
|
|
|
void Actor::AimAtEnemyBehavior(void)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-11 22:49:06 +02:00
|
|
|
AimAtTargetPos();
|
|
|
|
Anim_Aim();
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-12 19:21:41 +02:00
|
|
|
Actor::EventEnableEnemySwitch
|
2023-10-11 22:49:06 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventEnableEnemySwitch(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 19:21:41 +02:00
|
|
|
m_bEnemySwitch = true;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-12 19:21:41 +02:00
|
|
|
Actor::EventDisableEnemySwitch
|
2023-10-11 22:49:06 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventDisableEnemySwitch(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 19:21:41 +02:00
|
|
|
m_bEnemySwitch = false;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-12 19:21:41 +02:00
|
|
|
Actor::EventSetRunAnimRate
|
2023-10-11 22:49:06 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventSetRunAnimRate(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 19:21:41 +02:00
|
|
|
m_fRunAnimRate = ev->GetFloat(1);
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-12 19:21:41 +02:00
|
|
|
Actor::EventGetRunAnimRate
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void Actor::EventGetRunAnimRate(Event *ev)
|
|
|
|
{
|
|
|
|
ev->AddFloat(m_fRunAnimRate);
|
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 19:21:41 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::Landed
|
2023-10-11 22:49:06 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::Landed(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-14 00:44:59 +02:00
|
|
|
if (groundentity && groundentity->entity != world) {
|
|
|
|
warning("Actor::Landed", "Actor %d has landed on an entity that might move\n", entnum);
|
|
|
|
}
|
|
|
|
|
|
|
|
setMoveType(MOVETYPE_NONE);
|
2023-10-12 19:21:41 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::IsOnFloor
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
bool Actor::IsOnFloor(void)
|
|
|
|
{
|
2023-10-12 23:17:09 +02:00
|
|
|
str name = AnimName(0);
|
|
|
|
name.toupper();
|
|
|
|
return strstr(name, "FLOOR") != NULL;
|
2023-10-11 22:49:06 +02:00
|
|
|
}
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-12 19:21:41 +02:00
|
|
|
Actor::GetNationality
|
2023-10-11 22:49:06 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::GetNationality(Event *ev)
|
2023-10-11 22:49:06 +02:00
|
|
|
{
|
2023-10-12 23:17:09 +02:00
|
|
|
switch (m_iNationality) {
|
|
|
|
case ACTOR_NATIONALITY_DEFAULT:
|
|
|
|
default:
|
|
|
|
switch (m_Team) {
|
|
|
|
case TEAM_AMERICAN:
|
|
|
|
ev->AddString("usa");
|
|
|
|
break;
|
|
|
|
case TEAM_GERMAN:
|
|
|
|
ev->AddString("ger");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ev->AddString("unset");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case ACTOR_NATIONALITY_AMERICAN:
|
|
|
|
ev->AddString("usa");
|
|
|
|
break;
|
|
|
|
case ACTOR_NATIONALITY_GERMAN:
|
|
|
|
ev->AddString("ger");
|
|
|
|
break;
|
|
|
|
case ACTOR_NATIONALITY_ITALIAN:
|
|
|
|
ev->AddString("it");
|
|
|
|
break;
|
|
|
|
case ACTOR_NATIONALITY_BRITISH:
|
|
|
|
ev->AddString("uk");
|
|
|
|
break;
|
|
|
|
case ACTOR_NATIONALITY_RUSSIAN:
|
|
|
|
ev->AddString("ussr");
|
|
|
|
break;
|
|
|
|
}
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2023-10-11 22:49:06 +02:00
|
|
|
/*
|
|
|
|
===============
|
2023-10-12 19:21:41 +02:00
|
|
|
Actor::SetNationality
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void Actor::SetNationality(Event *ev)
|
|
|
|
{
|
2023-10-12 23:17:09 +02:00
|
|
|
str name;
|
|
|
|
|
|
|
|
if (ev->NumArgs() != 1) {
|
2023-10-16 00:29:41 +02:00
|
|
|
ScriptError(
|
|
|
|
"Bad bad nationality specified for '%s' at (%f %f %f)\n",
|
|
|
|
TargetName().c_str(),
|
|
|
|
origin[0],
|
|
|
|
origin[1],
|
|
|
|
origin[2]
|
|
|
|
);
|
2023-10-12 23:17:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
name = ev->GetString(1);
|
|
|
|
|
|
|
|
if (!str::icmpn(name, "default", 8)) {
|
|
|
|
m_iNationality = ACTOR_NATIONALITY_DEFAULT;
|
|
|
|
} else if (!str::icmpn(name, "ger", 4)) {
|
|
|
|
m_iNationality = ACTOR_NATIONALITY_GERMAN;
|
|
|
|
} else if (!str::icmpn(name, "it", 3)) {
|
|
|
|
m_iNationality = ACTOR_NATIONALITY_ITALIAN;
|
|
|
|
} else if (!str::icmpn(name, "usa", 4)) {
|
|
|
|
m_iNationality = ACTOR_NATIONALITY_AMERICAN;
|
|
|
|
} else if (!str::icmpn(name, "uk", 3)) {
|
|
|
|
m_iNationality = ACTOR_NATIONALITY_BRITISH;
|
|
|
|
} else if (!str::icmpn(name, "ussr", 5)) {
|
|
|
|
m_iNationality = ACTOR_NATIONALITY_RUSSIAN;
|
|
|
|
} else {
|
2023-10-16 00:29:41 +02:00
|
|
|
ScriptError(
|
|
|
|
"Bad bad nationality specified for '%s', must be one of: ger, it, usa, uk, ussr or default\n",
|
|
|
|
TargetName().c_str()
|
|
|
|
);
|
2023-10-12 23:17:09 +02:00
|
|
|
}
|
2023-10-12 19:21:41 +02:00
|
|
|
}
|
2023-10-11 22:49:06 +02:00
|
|
|
|
2023-10-12 19:21:41 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventWriteStats
|
2023-10-11 22:49:06 +02:00
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
void Actor::EventWriteStats(Event *ev)
|
2016-03-27 11:49:47 +02:00
|
|
|
{
|
2023-10-12 19:21:41 +02:00
|
|
|
if (g_aistats->integer) {
|
2023-10-18 19:21:06 +02:00
|
|
|
level.WriteActorStats(this);
|
2023-10-12 19:21:41 +02:00
|
|
|
}
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-12 19:21:41 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventCuriousOff
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void Actor::EventCuriousOff(Event *ev)
|
|
|
|
{
|
|
|
|
m_bIsCurious = false;
|
|
|
|
}
|
2018-08-19 08:26:59 +02:00
|
|
|
|
2023-10-12 19:21:41 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventCuriousOn
|
|
|
|
===============
|
|
|
|
*/
|
|
|
|
void Actor::EventCuriousOn(Event *ev)
|
|
|
|
{
|
|
|
|
m_bIsCurious = true;
|
2016-03-27 11:49:47 +02:00
|
|
|
}
|
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetDestIdle
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-18 19:21:06 +02:00
|
|
|
void Actor::EventSetDestIdle(Event *ev) {}
|
2016-03-27 11:49:47 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::EventSetDestIdle2
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-18 19:21:06 +02:00
|
|
|
void Actor::EventSetDestIdle2(Event *ev) {}
|
2018-08-05 17:56:40 +02:00
|
|
|
|
2024-09-01 20:21:37 +02:00
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::IsDisabled
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-12 19:21:41 +02:00
|
|
|
bool Actor::IsDisabled() const
|
|
|
|
{
|
|
|
|
return !m_bDoAI;
|
|
|
|
}
|
2023-10-14 21:21:45 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
===============
|
|
|
|
Actor::ExtractConstraints
|
|
|
|
|
|
|
|
===============
|
|
|
|
*/
|
2023-10-18 19:21:06 +02:00
|
|
|
void Actor::ExtractConstraints(mmove_t *mm) {}
|